Index: head/contrib/llvm-project/FREEBSD-Xlist =================================================================== --- head/contrib/llvm-project/FREEBSD-Xlist (revision 362718) +++ head/contrib/llvm-project/FREEBSD-Xlist (revision 362719) @@ -1,1043 +1,1046 @@ # $FreeBSD$ .arcconfig .clang-format .clang-tidy .git-blame-ignore-revs .github/ .gitignore CONTRIBUTING.md README.md clang/.arcconfig clang/.clang-format clang/.clang-tidy clang/.gitignore clang/CMakeLists.txt clang/CODE_OWNERS.TXT clang/INPUTS/ clang/INSTALL.txt clang/ModuleInfo.txt clang/NOTES.txt clang/README.txt clang/bindings/ clang/cmake/ clang/docs/ clang/examples/ clang/include/CMakeLists.txt clang/include/clang/AST/CMakeLists.txt clang/include/clang/Basic/CMakeLists.txt clang/include/clang/Basic/Version.inc.in clang/include/clang/CMakeLists.txt clang/include/clang/Config/ clang/include/clang/Driver/CMakeLists.txt clang/include/clang/Parse/CMakeLists.txt clang/include/clang/Sema/CMakeLists.txt clang/include/clang/Serialization/CMakeLists.txt clang/include/clang/StaticAnalyzer/Checkers/CMakeLists.txt clang/lib/ARCMigrate/CMakeLists.txt clang/lib/AST/CMakeLists.txt clang/lib/ASTMatchers/CMakeLists.txt clang/lib/ASTMatchers/Dynamic/CMakeLists.txt clang/lib/Analysis/CMakeLists.txt clang/lib/Analysis/plugins/CMakeLists.txt clang/lib/Analysis/plugins/CheckerDependencyHandling/CMakeLists.txt clang/lib/Analysis/plugins/CheckerOptionHandling/CMakeLists.txt clang/lib/Analysis/plugins/SampleAnalyzer/CMakeLists.txt clang/lib/Basic/CMakeLists.txt clang/lib/CMakeLists.txt clang/lib/CodeGen/CMakeLists.txt clang/lib/CodeGen/README.txt clang/lib/CrossTU/CMakeLists.txt clang/lib/DirectoryWatcher/CMakeLists.txt clang/lib/Driver/CMakeLists.txt clang/lib/Edit/CMakeLists.txt clang/lib/Format/CMakeLists.txt clang/lib/Frontend/CMakeLists.txt clang/lib/Frontend/Rewrite/CMakeLists.txt clang/lib/FrontendTool/CMakeLists.txt clang/lib/Headers/CMakeLists.txt clang/lib/Index/CMakeLists.txt clang/lib/Lex/CMakeLists.txt clang/lib/Parse/CMakeLists.txt clang/lib/Rewrite/CMakeLists.txt clang/lib/Sema/CMakeLists.txt clang/lib/Serialization/CMakeLists.txt clang/lib/StaticAnalyzer/CMakeLists.txt clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt clang/lib/StaticAnalyzer/Core/CMakeLists.txt clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt clang/lib/StaticAnalyzer/README.txt clang/lib/Tooling/ASTDiff/CMakeLists.txt clang/lib/Tooling/CMakeLists.txt clang/lib/Tooling/Core/CMakeLists.txt clang/lib/Tooling/DependencyScanning/CMakeLists.txt clang/lib/Tooling/Inclusions/CMakeLists.txt clang/lib/Tooling/Refactoring/CMakeLists.txt clang/lib/Tooling/Syntax/CMakeLists.txt clang/lib/Tooling/Transformer/CMakeLists.txt clang/runtime/ clang/test/ clang/tools/CMakeLists.txt clang/tools/arcmt-test/ clang/tools/c-arcmt-test/ clang/tools/c-index-test/ clang/tools/clang-check/ clang/tools/clang-diff/ clang/tools/clang-extdef-mapping/ clang/tools/clang-format/CMakeLists.txt clang/tools/clang-format/clang-format-bbedit.applescript clang/tools/clang-format/clang-format-diff.py clang/tools/clang-format/clang-format-sublime.py clang/tools/clang-format/clang-format-test.el clang/tools/clang-format/clang-format.el clang/tools/clang-format/clang-format.py clang/tools/clang-format/fuzzer/ clang/tools/clang-format/git-clang-format clang/tools/clang-format-vs/ clang/tools/clang-fuzzer/ clang/tools/clang-import-test/ clang/tools/clang-offload-bundler/ clang/tools/clang-offload-wrapper/ clang/tools/clang-refactor/ clang/tools/clang-rename/ clang/tools/clang-scan-deps/ clang/tools/clang-shlib/ clang/tools/diag-build/ clang/tools/diagtool/ clang/tools/driver/CMakeLists.txt clang/tools/driver/Info.plist.in clang/tools/libclang/ clang/tools/scan-build/ clang/tools/scan-build-py/ clang/tools/scan-view/ clang/unittests/ clang/utils/ABITest/ clang/utils/CIndex/ clang/utils/CaptureCmd clang/utils/ClangDataFormat.py clang/utils/ClangVisualizers/ clang/utils/CmpDriver clang/utils/FindSpecRefs clang/utils/FuzzTest clang/utils/TableGen/CMakeLists.txt clang/utils/TestUtils/ clang/utils/VtableTest/ clang/utils/analyzer/ clang/utils/bash-autocomplete.sh clang/utils/builtin-defines.c clang/utils/check_cfc/ clang/utils/clangdiag.py clang/utils/convert_arm_neon.py clang/utils/creduce-clang-crash.py clang/utils/find-unused-diagnostics.sh clang/utils/hmaptool/ clang/utils/make-ast-dump-check.sh clang/utils/modfuzz.py clang/utils/perf-training/ clang/utils/token-delta.py clang/utils/valgrind/ clang/www/ clang-tools-extra/ compiler-rt/.arcconfig compiler-rt/.gitignore compiler-rt/CMakeLists.txt compiler-rt/CODE_OWNERS.TXT compiler-rt/cmake/ compiler-rt/docs/ compiler-rt/include/CMakeLists.txt compiler-rt/lib/CMakeLists.txt compiler-rt/lib/asan/.clang-format compiler-rt/lib/asan/CMakeLists.txt compiler-rt/lib/asan/scripts/ compiler-rt/lib/asan/tests/ compiler-rt/lib/builtins/CMakeLists.txt compiler-rt/lib/builtins/Darwin-excludes/ compiler-rt/lib/builtins/macho_embedded/ compiler-rt/lib/cfi/CMakeLists.txt compiler-rt/lib/crt/CMakeLists.txt compiler-rt/lib/dfsan/.clang-format compiler-rt/lib/dfsan/CMakeLists.txt compiler-rt/lib/dfsan/scripts/ compiler-rt/lib/fuzzer/CMakeLists.txt compiler-rt/lib/fuzzer/afl/ compiler-rt/lib/fuzzer/build.sh compiler-rt/lib/fuzzer/dataflow/ compiler-rt/lib/fuzzer/scripts/ compiler-rt/lib/fuzzer/standalone/ compiler-rt/lib/fuzzer/tests/ compiler-rt/lib/gwp_asan/CMakeLists.txt compiler-rt/lib/gwp_asan/scripts/ compiler-rt/lib/gwp_asan/tests/ compiler-rt/lib/hwasan/.clang-format compiler-rt/lib/hwasan/CMakeLists.txt compiler-rt/lib/hwasan/scripts/ compiler-rt/lib/interception/.clang-format compiler-rt/lib/interception/CMakeLists.txt compiler-rt/lib/interception/tests/ compiler-rt/lib/lsan/.clang-format compiler-rt/lib/lsan/CMakeLists.txt compiler-rt/lib/msan/.clang-format compiler-rt/lib/msan/CMakeLists.txt compiler-rt/lib/msan/tests/ compiler-rt/lib/profile/CMakeLists.txt compiler-rt/lib/safestack/.clang-format compiler-rt/lib/safestack/CMakeLists.txt compiler-rt/lib/sanitizer_common/.clang-format compiler-rt/lib/sanitizer_common/.clang-tidy compiler-rt/lib/sanitizer_common/CMakeLists.txt compiler-rt/lib/sanitizer_common/scripts/ compiler-rt/lib/sanitizer_common/tests/ compiler-rt/lib/scudo/CMakeLists.txt compiler-rt/lib/scudo/standalone/CMakeLists.txt compiler-rt/lib/scudo/standalone/benchmarks/ compiler-rt/lib/scudo/standalone/tests/ compiler-rt/lib/stats/CMakeLists.txt compiler-rt/lib/tsan/.clang-format compiler-rt/lib/tsan/CMakeLists.txt compiler-rt/lib/tsan/analyze_libtsan.sh compiler-rt/lib/tsan/check_analyze.sh compiler-rt/lib/tsan/check_cmake.sh compiler-rt/lib/tsan/dd/CMakeLists.txt compiler-rt/lib/tsan/go/build.bat compiler-rt/lib/tsan/go/buildgo.sh compiler-rt/lib/tsan/tests/ compiler-rt/lib/ubsan/CMakeLists.txt compiler-rt/lib/ubsan_minimal/CMakeLists.txt compiler-rt/lib/xray/CMakeLists.txt compiler-rt/lib/xray/tests/ compiler-rt/test/ compiler-rt/tools/ compiler-rt/unittests/ compiler-rt/utils/ compiler-rt/www/ debuginfo-tests/ libc/ libclc/ libcxx/.arcconfig libcxx/.clang-format libcxx/.gitignore libcxx/CMakeLists.txt libcxx/NOTES.TXT libcxx/TODO.TXT libcxx/appveyor-reqs-install.cmd libcxx/appveyor.yml libcxx/benchmarks/ libcxx/cmake/ libcxx/docs/ libcxx/fuzzing/ libcxx/include/CMakeLists.txt libcxx/include/__config_site.in libcxx/include/support/ libcxx/lib/ libcxx/src/CMakeLists.txt libcxx/src/support/solaris/ libcxx/src/support/win32/ libcxx/test/ libcxx/utils/ libcxx/www/ libcxxabi/ libunwind/.arcconfig libunwind/.clang-format libunwind/CMakeLists.txt libunwind/cmake/ libunwind/docs/ libunwind/src/CMakeLists.txt libunwind/test/ lld/CMakeLists.txt lld/COFF/CMakeLists.txt lld/Common/CMakeLists.txt lld/ELF/CMakeLists.txt lld/MinGW/ lld/cmake/ lld/docs/CMakeLists.txt lld/lib/CMakeLists.txt lld/lib/Core/CMakeLists.txt lld/lib/Driver/CMakeLists.txt lld/lib/ReaderWriter/CMakeLists.txt lld/lib/ReaderWriter/MachO/CMakeLists.txt lld/lib/ReaderWriter/YAML/CMakeLists.txt lld/test/ lld/tools/lld/CMakeLists.txt lld/unittests/ lld/utils/ lld/wasm/ lldb/.arcconfig lldb/.clang-format lldb/.gitignore lldb/CMakeLists.txt lldb/CODE_OWNERS.txt lldb/bindings/CMakeLists.txt lldb/cmake/ lldb/docs/.htaccess lldb/docs/CMakeLists.txt lldb/docs/_static/ lldb/docs/conf.py lldb/docs/doxygen-mainpage.dox lldb/docs/doxygen.cfg.in lldb/docs/index.rst lldb/docs/lldb-for-gdb-users.txt lldb/docs/lldb-gdb-remote.txt lldb/docs/lldb-platform-packets.txt lldb/docs/resources/ lldb/docs/status/ lldb/docs/structured_data/ lldb/docs/testsuite/ lldb/docs/use/ lldb/examples/ lldb/include/lldb/Host/android/ lldb/include/lldb/Host/linux/ lldb/include/lldb/Host/macosx/ lldb/include/lldb/Host/windows/ lldb/packages/ lldb/resources/ lldb/scripts/ lldb/source/API/CMakeLists.txt lldb/source/Breakpoint/CMakeLists.txt lldb/source/CMakeLists.txt lldb/source/Commands/CMakeLists.txt lldb/source/Core/CMakeLists.txt lldb/source/DataFormatters/CMakeLists.txt lldb/source/Expression/CMakeLists.txt lldb/source/Host/CMakeLists.txt lldb/source/Host/android/ lldb/source/Host/linux/ lldb/source/Host/macosx/ lldb/source/Host/windows/ lldb/source/Initialization/CMakeLists.txt lldb/source/Interpreter/CMakeLists.txt lldb/source/Plugins/ABI/CMakeLists.txt lldb/source/Plugins/ABI/MacOSX-arm/CMakeLists.txt lldb/source/Plugins/ABI/MacOSX-arm64/CMakeLists.txt lldb/source/Plugins/ABI/MacOSX-i386/CMakeLists.txt lldb/source/Plugins/ABI/SysV-arc/CMakeLists.txt lldb/source/Plugins/ABI/SysV-arm/CMakeLists.txt lldb/source/Plugins/ABI/SysV-arm64/CMakeLists.txt lldb/source/Plugins/ABI/SysV-hexagon/CMakeLists.txt lldb/source/Plugins/ABI/SysV-i386/CMakeLists.txt lldb/source/Plugins/ABI/SysV-mips/CMakeLists.txt lldb/source/Plugins/ABI/SysV-mips64/CMakeLists.txt lldb/source/Plugins/ABI/SysV-ppc/CMakeLists.txt lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt lldb/source/Plugins/ABI/SysV-s390x/CMakeLists.txt lldb/source/Plugins/ABI/SysV-x86_64/CMakeLists.txt lldb/source/Plugins/ABI/Windows-x86_64/CMakeLists.txt lldb/source/Plugins/Architecture/Arm/CMakeLists.txt lldb/source/Plugins/Architecture/CMakeLists.txt lldb/source/Plugins/Architecture/Mips/CMakeLists.txt lldb/source/Plugins/Architecture/PPC64/CMakeLists.txt lldb/source/Plugins/CMakeLists.txt lldb/source/Plugins/Disassembler/CMakeLists.txt lldb/source/Plugins/Disassembler/llvm/CMakeLists.txt lldb/source/Plugins/DynamicLoader/CMakeLists.txt lldb/source/Plugins/DynamicLoader/Darwin-Kernel/ lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/CMakeLists.txt lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ lldb/source/Plugins/DynamicLoader/POSIX-DYLD/CMakeLists.txt lldb/source/Plugins/DynamicLoader/Static/CMakeLists.txt lldb/source/Plugins/DynamicLoader/Windows-DYLD/CMakeLists.txt lldb/source/Plugins/ExpressionParser/CMakeLists.txt lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt lldb/source/Plugins/Instruction/ARM/CMakeLists.txt lldb/source/Plugins/Instruction/ARM64/CMakeLists.txt lldb/source/Plugins/Instruction/CMakeLists.txt lldb/source/Plugins/Instruction/MIPS/CMakeLists.txt lldb/source/Plugins/Instruction/MIPS64/CMakeLists.txt lldb/source/Plugins/Instruction/PPC64/CMakeLists.txt lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt lldb/source/Plugins/InstrumentationRuntime/CMakeLists.txt lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt lldb/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt lldb/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt lldb/source/Plugins/JITLoader/CMakeLists.txt lldb/source/Plugins/JITLoader/GDB/CMakeLists.txt lldb/source/Plugins/Language/CMakeLists.txt lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt lldb/source/Plugins/Language/ClangCommon/CMakeLists.txt lldb/source/Plugins/Language/ObjC/CMakeLists.txt lldb/source/Plugins/Language/ObjCPlusPlus/CMakeLists.txt lldb/source/Plugins/LanguageRuntime/CMakeLists.txt lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt lldb/source/Plugins/LanguageRuntime/Go/ lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt lldb/source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt lldb/source/Plugins/MemoryHistory/CMakeLists.txt lldb/source/Plugins/MemoryHistory/asan/CMakeLists.txt lldb/source/Plugins/ObjectContainer/BSD-Archive/CMakeLists.txt lldb/source/Plugins/ObjectContainer/CMakeLists.txt lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ lldb/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt lldb/source/Plugins/ObjectFile/CMakeLists.txt lldb/source/Plugins/ObjectFile/ELF/CMakeLists.txt lldb/source/Plugins/ObjectFile/JIT/CMakeLists.txt lldb/source/Plugins/ObjectFile/Mach-O/ lldb/source/Plugins/ObjectFile/PECOFF/ lldb/source/Plugins/OperatingSystem/CMakeLists.txt lldb/source/Plugins/OperatingSystem/Python/CMakeLists.txt lldb/source/Plugins/Platform/Android/ lldb/source/Plugins/Platform/CMakeLists.txt lldb/source/Plugins/Platform/FreeBSD/CMakeLists.txt lldb/source/Plugins/Platform/Linux/ lldb/source/Plugins/Platform/MacOSX/ lldb/source/Plugins/Platform/NetBSD/CMakeLists.txt lldb/source/Plugins/Platform/OpenBSD/CMakeLists.txt lldb/source/Plugins/Platform/POSIX/CMakeLists.txt lldb/source/Plugins/Platform/Windows/ lldb/source/Plugins/Platform/gdb-server/CMakeLists.txt lldb/source/Plugins/Process/CMakeLists.txt lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt lldb/source/Plugins/Process/Linux/ lldb/source/Plugins/Process/MacOSX-Kernel/ lldb/source/Plugins/Process/NetBSD/CMakeLists.txt lldb/source/Plugins/Process/POSIX/CMakeLists.txt lldb/source/Plugins/Process/Utility/CMakeLists.txt lldb/source/Plugins/Process/Windows/ lldb/source/Plugins/Process/elf-core/CMakeLists.txt lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt lldb/source/Plugins/Process/mach-core/ lldb/source/Plugins/Process/minidump/CMakeLists.txt lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt lldb/source/Plugins/StructuredData/CMakeLists.txt lldb/source/Plugins/StructuredData/DarwinLog/CMakeLists.txt lldb/source/Plugins/SymbolFile/Breakpad/CMakeLists.txt lldb/source/Plugins/SymbolFile/CMakeLists.txt lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt lldb/source/Plugins/SymbolFile/Symtab/CMakeLists.txt lldb/source/Plugins/SymbolVendor/CMakeLists.txt lldb/source/Plugins/SymbolVendor/ELF/CMakeLists.txt lldb/source/Plugins/SymbolVendor/MacOSX/ lldb/source/Plugins/SystemRuntime/ lldb/source/Plugins/UnwindAssembly/CMakeLists.txt lldb/source/Plugins/UnwindAssembly/InstEmulation/CMakeLists.txt lldb/source/Plugins/UnwindAssembly/x86/CMakeLists.txt lldb/source/Symbol/CMakeLists.txt lldb/source/Target/CMakeLists.txt lldb/source/Utility/CMakeLists.txt lldb/test/ lldb/third_party/ lldb/tools/CMakeLists.txt lldb/tools/argdumper/CMakeLists.txt lldb/tools/darwin-debug/ lldb/tools/darwin-threads/ lldb/tools/debugserver/ lldb/tools/driver/CMakeLists.txt lldb/tools/driver/lldb-Info.plist.in lldb/tools/intel-features/ lldb/tools/lldb-instr/CMakeLists.txt lldb/tools/lldb-perf/ lldb/tools/lldb-server/CMakeLists.txt lldb/tools/lldb-test/ lldb/tools/lldb-vscode/ lldb/unittests/ lldb/use_lldb_suite_root.py lldb/utils/TableGen/CMakeLists.txt lldb/utils/lit-cpuid/ lldb/utils/lldb-dotest/ lldb/utils/lui/ lldb/utils/test/ llgo/ llvm/.arcconfig llvm/.clang-format llvm/.clang-tidy llvm/.gitattributes llvm/.gitignore llvm/CMakeLists.txt llvm/CODE_OWNERS.TXT llvm/CREDITS.TXT llvm/LLVMBuild.txt llvm/README.txt llvm/RELEASE_TESTERS.TXT llvm/benchmarks/ llvm/bindings/ llvm/cmake/ llvm/configure llvm/docs/ llvm/examples/ llvm/include/llvm/CMakeLists.txt llvm/include/llvm/Config/ llvm/include/llvm/IR/CMakeLists.txt llvm/include/llvm/Support/CMakeLists.txt llvm/include/llvm/Support/LICENSE.TXT llvm/lib/Analysis/CMakeLists.txt llvm/lib/Analysis/LLVMBuild.txt llvm/lib/Analysis/README.txt llvm/lib/AsmParser/CMakeLists.txt llvm/lib/AsmParser/LLVMBuild.txt llvm/lib/BinaryFormat/CMakeLists.txt llvm/lib/BinaryFormat/LLVMBuild.txt llvm/lib/Bitcode/CMakeLists.txt llvm/lib/Bitcode/LLVMBuild.txt llvm/lib/Bitcode/Reader/CMakeLists.txt llvm/lib/Bitcode/Reader/LLVMBuild.txt llvm/lib/Bitcode/Writer/CMakeLists.txt llvm/lib/Bitcode/Writer/LLVMBuild.txt llvm/lib/Bitstream/CMakeLists.txt llvm/lib/Bitstream/LLVMBuild.txt llvm/lib/Bitstream/Reader/CMakeLists.txt llvm/lib/Bitstream/Reader/LLVMBuild.txt llvm/lib/CMakeLists.txt llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt llvm/lib/CodeGen/AsmPrinter/LLVMBuild.txt llvm/lib/CodeGen/CMakeLists.txt llvm/lib/CodeGen/GlobalISel/CMakeLists.txt llvm/lib/CodeGen/GlobalISel/LLVMBuild.txt llvm/lib/CodeGen/LLVMBuild.txt llvm/lib/CodeGen/MIRParser/CMakeLists.txt llvm/lib/CodeGen/MIRParser/LLVMBuild.txt llvm/lib/CodeGen/README.txt llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt llvm/lib/CodeGen/SelectionDAG/LLVMBuild.txt llvm/lib/DWARFLinker/CMakeLists.txt llvm/lib/DWARFLinker/LLVMBuild.txt llvm/lib/DebugInfo/CMakeLists.txt llvm/lib/DebugInfo/CodeView/CMakeLists.txt llvm/lib/DebugInfo/CodeView/LLVMBuild.txt llvm/lib/DebugInfo/DWARF/CMakeLists.txt llvm/lib/DebugInfo/DWARF/LLVMBuild.txt llvm/lib/DebugInfo/GSYM/CMakeLists.txt llvm/lib/DebugInfo/GSYM/LLVMBuild.txt llvm/lib/DebugInfo/LLVMBuild.txt llvm/lib/DebugInfo/MSF/CMakeLists.txt llvm/lib/DebugInfo/MSF/LLVMBuild.txt llvm/lib/DebugInfo/PDB/CMakeLists.txt llvm/lib/DebugInfo/PDB/LLVMBuild.txt llvm/lib/DebugInfo/Symbolize/CMakeLists.txt llvm/lib/DebugInfo/Symbolize/LLVMBuild.txt llvm/lib/Demangle/CMakeLists.txt llvm/lib/Demangle/LLVMBuild.txt llvm/lib/ExecutionEngine/CMakeLists.txt llvm/lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt llvm/lib/ExecutionEngine/IntelJITEvents/LLVMBuild.txt llvm/lib/ExecutionEngine/Interpreter/CMakeLists.txt llvm/lib/ExecutionEngine/Interpreter/LLVMBuild.txt llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt llvm/lib/ExecutionEngine/JITLink/LLVMBuild.txt llvm/lib/ExecutionEngine/LLVMBuild.txt llvm/lib/ExecutionEngine/MCJIT/CMakeLists.txt llvm/lib/ExecutionEngine/MCJIT/LLVMBuild.txt llvm/lib/ExecutionEngine/OProfileJIT/CMakeLists.txt llvm/lib/ExecutionEngine/OProfileJIT/LLVMBuild.txt llvm/lib/ExecutionEngine/Orc/CMakeLists.txt llvm/lib/ExecutionEngine/Orc/LLVMBuild.txt llvm/lib/ExecutionEngine/OrcError/CMakeLists.txt llvm/lib/ExecutionEngine/OrcError/LLVMBuild.txt llvm/lib/ExecutionEngine/PerfJITEvents/CMakeLists.txt llvm/lib/ExecutionEngine/PerfJITEvents/LLVMBuild.txt llvm/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt llvm/lib/ExecutionEngine/RuntimeDyld/LLVMBuild.txt llvm/lib/Extensions/ llvm/lib/Frontend/CMakeLists.txt llvm/lib/Frontend/LLVMBuild.txt llvm/lib/Frontend/OpenMP/CMakeLists.txt llvm/lib/Frontend/OpenMP/LLVMBuild.txt llvm/lib/FuzzMutate/CMakeLists.txt llvm/lib/FuzzMutate/LLVMBuild.txt llvm/lib/Fuzzer/ llvm/lib/IR/CMakeLists.txt llvm/lib/IR/LLVMBuild.txt llvm/lib/IRReader/CMakeLists.txt llvm/lib/IRReader/LLVMBuild.txt llvm/lib/LLVMBuild.txt llvm/lib/LTO/CMakeLists.txt llvm/lib/LTO/LLVMBuild.txt llvm/lib/LineEditor/CMakeLists.txt llvm/lib/LineEditor/LLVMBuild.txt llvm/lib/Linker/CMakeLists.txt llvm/lib/Linker/LLVMBuild.txt llvm/lib/MC/CMakeLists.txt llvm/lib/MC/LLVMBuild.txt llvm/lib/MC/MCDisassembler/CMakeLists.txt llvm/lib/MC/MCDisassembler/LLVMBuild.txt llvm/lib/MC/MCParser/CMakeLists.txt llvm/lib/MC/MCParser/LLVMBuild.txt llvm/lib/MCA/CMakeLists.txt llvm/lib/MCA/LLVMBuild.txt llvm/lib/Object/CMakeLists.txt llvm/lib/Object/LLVMBuild.txt llvm/lib/ObjectYAML/CMakeLists.txt llvm/lib/ObjectYAML/LLVMBuild.txt llvm/lib/Option/CMakeLists.txt llvm/lib/Option/LLVMBuild.txt llvm/lib/Passes/CMakeLists.txt llvm/lib/Passes/LLVMBuild.txt llvm/lib/ProfileData/CMakeLists.txt llvm/lib/ProfileData/Coverage/CMakeLists.txt llvm/lib/ProfileData/Coverage/LLVMBuild.txt llvm/lib/ProfileData/LLVMBuild.txt llvm/lib/Remarks/CMakeLists.txt llvm/lib/Remarks/LLVMBuild.txt llvm/lib/Support/CMakeLists.txt llvm/lib/Support/LLVMBuild.txt llvm/lib/TableGen/CMakeLists.txt llvm/lib/TableGen/LLVMBuild.txt llvm/lib/Target/AArch64/AsmParser/CMakeLists.txt llvm/lib/Target/AArch64/AsmParser/LLVMBuild.txt llvm/lib/Target/AArch64/CMakeLists.txt llvm/lib/Target/AArch64/Disassembler/CMakeLists.txt llvm/lib/Target/AArch64/Disassembler/LLVMBuild.txt llvm/lib/Target/AArch64/LLVMBuild.txt llvm/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt llvm/lib/Target/AArch64/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/AArch64/TargetInfo/CMakeLists.txt llvm/lib/Target/AArch64/TargetInfo/LLVMBuild.txt llvm/lib/Target/AArch64/Utils/CMakeLists.txt llvm/lib/Target/AArch64/Utils/LLVMBuild.txt llvm/lib/Target/AMDGPU/AsmParser/CMakeLists.txt llvm/lib/Target/AMDGPU/AsmParser/LLVMBuild.txt llvm/lib/Target/AMDGPU/CMakeLists.txt llvm/lib/Target/AMDGPU/Disassembler/CMakeLists.txt llvm/lib/Target/AMDGPU/Disassembler/LLVMBuild.txt llvm/lib/Target/AMDGPU/LLVMBuild.txt llvm/lib/Target/AMDGPU/MCTargetDesc/CMakeLists.txt llvm/lib/Target/AMDGPU/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/AMDGPU/TargetInfo/CMakeLists.txt llvm/lib/Target/AMDGPU/TargetInfo/LLVMBuild.txt llvm/lib/Target/AMDGPU/Utils/CMakeLists.txt llvm/lib/Target/AMDGPU/Utils/LLVMBuild.txt llvm/lib/Target/ARC/CMakeLists.txt llvm/lib/Target/ARC/Disassembler/CMakeLists.txt llvm/lib/Target/ARC/Disassembler/LLVMBuild.txt llvm/lib/Target/ARC/LLVMBuild.txt llvm/lib/Target/ARC/MCTargetDesc/CMakeLists.txt llvm/lib/Target/ARC/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/ARC/TargetInfo/CMakeLists.txt llvm/lib/Target/ARC/TargetInfo/LLVMBuild.txt llvm/lib/Target/ARM/AsmParser/CMakeLists.txt llvm/lib/Target/ARM/AsmParser/LLVMBuild.txt llvm/lib/Target/ARM/CMakeLists.txt llvm/lib/Target/ARM/Disassembler/CMakeLists.txt llvm/lib/Target/ARM/Disassembler/LLVMBuild.txt llvm/lib/Target/ARM/LLVMBuild.txt llvm/lib/Target/ARM/MCTargetDesc/CMakeLists.txt llvm/lib/Target/ARM/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/ARM/README-Thumb.txt llvm/lib/Target/ARM/README-Thumb2.txt llvm/lib/Target/ARM/README.txt llvm/lib/Target/ARM/TargetInfo/CMakeLists.txt llvm/lib/Target/ARM/TargetInfo/LLVMBuild.txt llvm/lib/Target/ARM/Utils/CMakeLists.txt llvm/lib/Target/ARM/Utils/LLVMBuild.txt llvm/lib/Target/AVR/AsmParser/CMakeLists.txt llvm/lib/Target/AVR/AsmParser/LLVMBuild.txt llvm/lib/Target/AVR/CMakeLists.txt llvm/lib/Target/AVR/Disassembler/CMakeLists.txt llvm/lib/Target/AVR/Disassembler/LLVMBuild.txt llvm/lib/Target/AVR/LLVMBuild.txt llvm/lib/Target/AVR/MCTargetDesc/CMakeLists.txt llvm/lib/Target/AVR/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/AVR/TargetInfo/CMakeLists.txt llvm/lib/Target/AVR/TargetInfo/LLVMBuild.txt llvm/lib/Target/BPF/AsmParser/CMakeLists.txt llvm/lib/Target/BPF/AsmParser/LLVMBuild.txt llvm/lib/Target/BPF/CMakeLists.txt llvm/lib/Target/BPF/Disassembler/CMakeLists.txt llvm/lib/Target/BPF/Disassembler/LLVMBuild.txt llvm/lib/Target/BPF/LLVMBuild.txt llvm/lib/Target/BPF/MCTargetDesc/CMakeLists.txt llvm/lib/Target/BPF/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/BPF/TargetInfo/CMakeLists.txt llvm/lib/Target/BPF/TargetInfo/LLVMBuild.txt llvm/lib/Target/CMakeLists.txt llvm/lib/Target/Hexagon/AsmParser/CMakeLists.txt llvm/lib/Target/Hexagon/AsmParser/LLVMBuild.txt llvm/lib/Target/Hexagon/CMakeLists.txt llvm/lib/Target/Hexagon/Disassembler/CMakeLists.txt llvm/lib/Target/Hexagon/Disassembler/LLVMBuild.txt llvm/lib/Target/Hexagon/LLVMBuild.txt llvm/lib/Target/Hexagon/MCTargetDesc/CMakeLists.txt llvm/lib/Target/Hexagon/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/Hexagon/TargetInfo/CMakeLists.txt llvm/lib/Target/Hexagon/TargetInfo/LLVMBuild.txt llvm/lib/Target/LLVMBuild.txt llvm/lib/Target/Lanai/AsmParser/CMakeLists.txt llvm/lib/Target/Lanai/AsmParser/LLVMBuild.txt llvm/lib/Target/Lanai/CMakeLists.txt llvm/lib/Target/Lanai/Disassembler/CMakeLists.txt llvm/lib/Target/Lanai/Disassembler/LLVMBuild.txt llvm/lib/Target/Lanai/LLVMBuild.txt llvm/lib/Target/Lanai/MCTargetDesc/CMakeLists.txt llvm/lib/Target/Lanai/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/Lanai/TargetInfo/CMakeLists.txt llvm/lib/Target/Lanai/TargetInfo/LLVMBuild.txt llvm/lib/Target/MSP430/AsmParser/CMakeLists.txt llvm/lib/Target/MSP430/AsmParser/LLVMBuild.txt llvm/lib/Target/MSP430/CMakeLists.txt llvm/lib/Target/MSP430/Disassembler/CMakeLists.txt llvm/lib/Target/MSP430/Disassembler/LLVMBuild.txt llvm/lib/Target/MSP430/LLVMBuild.txt llvm/lib/Target/MSP430/MCTargetDesc/CMakeLists.txt llvm/lib/Target/MSP430/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/MSP430/README.txt llvm/lib/Target/MSP430/TargetInfo/CMakeLists.txt llvm/lib/Target/MSP430/TargetInfo/LLVMBuild.txt llvm/lib/Target/Mips/AsmParser/CMakeLists.txt llvm/lib/Target/Mips/AsmParser/LLVMBuild.txt llvm/lib/Target/Mips/CMakeLists.txt llvm/lib/Target/Mips/Disassembler/CMakeLists.txt llvm/lib/Target/Mips/Disassembler/LLVMBuild.txt llvm/lib/Target/Mips/LLVMBuild.txt llvm/lib/Target/Mips/MCTargetDesc/CMakeLists.txt llvm/lib/Target/Mips/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/Mips/TargetInfo/CMakeLists.txt llvm/lib/Target/Mips/TargetInfo/LLVMBuild.txt llvm/lib/Target/NVPTX/CMakeLists.txt llvm/lib/Target/NVPTX/LLVMBuild.txt llvm/lib/Target/NVPTX/MCTargetDesc/CMakeLists.txt llvm/lib/Target/NVPTX/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/NVPTX/TargetInfo/CMakeLists.txt llvm/lib/Target/NVPTX/TargetInfo/LLVMBuild.txt llvm/lib/Target/PowerPC/AsmParser/CMakeLists.txt llvm/lib/Target/PowerPC/AsmParser/LLVMBuild.txt llvm/lib/Target/PowerPC/CMakeLists.txt llvm/lib/Target/PowerPC/Disassembler/CMakeLists.txt llvm/lib/Target/PowerPC/Disassembler/LLVMBuild.txt llvm/lib/Target/PowerPC/LLVMBuild.txt llvm/lib/Target/PowerPC/MCTargetDesc/CMakeLists.txt llvm/lib/Target/PowerPC/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/PowerPC/README.txt llvm/lib/Target/PowerPC/README_ALTIVEC.txt llvm/lib/Target/PowerPC/TargetInfo/CMakeLists.txt llvm/lib/Target/PowerPC/TargetInfo/LLVMBuild.txt llvm/lib/Target/README.txt llvm/lib/Target/RISCV/AsmParser/CMakeLists.txt llvm/lib/Target/RISCV/AsmParser/LLVMBuild.txt llvm/lib/Target/RISCV/CMakeLists.txt llvm/lib/Target/RISCV/Disassembler/CMakeLists.txt llvm/lib/Target/RISCV/Disassembler/LLVMBuild.txt llvm/lib/Target/RISCV/LLVMBuild.txt llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt llvm/lib/Target/RISCV/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/RISCV/TargetInfo/CMakeLists.txt llvm/lib/Target/RISCV/TargetInfo/LLVMBuild.txt llvm/lib/Target/RISCV/Utils/CMakeLists.txt llvm/lib/Target/RISCV/Utils/LLVMBuild.txt llvm/lib/Target/Sparc/AsmParser/CMakeLists.txt llvm/lib/Target/Sparc/AsmParser/LLVMBuild.txt llvm/lib/Target/Sparc/CMakeLists.txt llvm/lib/Target/Sparc/Disassembler/CMakeLists.txt llvm/lib/Target/Sparc/Disassembler/LLVMBuild.txt llvm/lib/Target/Sparc/LLVMBuild.txt llvm/lib/Target/Sparc/MCTargetDesc/CMakeLists.txt llvm/lib/Target/Sparc/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/Sparc/README.txt llvm/lib/Target/Sparc/TargetInfo/CMakeLists.txt llvm/lib/Target/Sparc/TargetInfo/LLVMBuild.txt llvm/lib/Target/SystemZ/AsmParser/CMakeLists.txt llvm/lib/Target/SystemZ/AsmParser/LLVMBuild.txt llvm/lib/Target/SystemZ/CMakeLists.txt llvm/lib/Target/SystemZ/Disassembler/CMakeLists.txt llvm/lib/Target/SystemZ/Disassembler/LLVMBuild.txt llvm/lib/Target/SystemZ/LLVMBuild.txt llvm/lib/Target/SystemZ/MCTargetDesc/CMakeLists.txt llvm/lib/Target/SystemZ/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/SystemZ/TargetInfo/CMakeLists.txt llvm/lib/Target/SystemZ/TargetInfo/LLVMBuild.txt llvm/lib/Target/VE/CMakeLists.txt llvm/lib/Target/VE/InstPrinter/CMakeLists.txt llvm/lib/Target/VE/InstPrinter/LLVMBuild.txt llvm/lib/Target/VE/LLVMBuild.txt llvm/lib/Target/VE/MCTargetDesc/CMakeLists.txt llvm/lib/Target/VE/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/VE/TargetInfo/CMakeLists.txt llvm/lib/Target/VE/TargetInfo/LLVMBuild.txt llvm/lib/Target/WebAssembly/AsmParser/CMakeLists.txt llvm/lib/Target/WebAssembly/AsmParser/LLVMBuild.txt llvm/lib/Target/WebAssembly/CMakeLists.txt llvm/lib/Target/WebAssembly/Disassembler/CMakeLists.txt llvm/lib/Target/WebAssembly/Disassembler/LLVMBuild.txt llvm/lib/Target/WebAssembly/LLVMBuild.txt llvm/lib/Target/WebAssembly/MCTargetDesc/CMakeLists.txt llvm/lib/Target/WebAssembly/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/WebAssembly/TargetInfo/CMakeLists.txt llvm/lib/Target/WebAssembly/TargetInfo/LLVMBuild.txt llvm/lib/Target/X86/AsmParser/CMakeLists.txt llvm/lib/Target/X86/AsmParser/LLVMBuild.txt llvm/lib/Target/X86/CMakeLists.txt llvm/lib/Target/X86/Disassembler/CMakeLists.txt llvm/lib/Target/X86/Disassembler/LLVMBuild.txt llvm/lib/Target/X86/LLVMBuild.txt llvm/lib/Target/X86/MCTargetDesc/CMakeLists.txt llvm/lib/Target/X86/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/X86/README-FPStack.txt llvm/lib/Target/X86/README-SSE.txt llvm/lib/Target/X86/README-X86-64.txt llvm/lib/Target/X86/README.txt llvm/lib/Target/X86/TargetInfo/CMakeLists.txt llvm/lib/Target/X86/TargetInfo/LLVMBuild.txt llvm/lib/Target/X86/Utils/CMakeLists.txt llvm/lib/Target/X86/Utils/LLVMBuild.txt llvm/lib/Target/XCore/CMakeLists.txt llvm/lib/Target/XCore/Disassembler/CMakeLists.txt llvm/lib/Target/XCore/Disassembler/LLVMBuild.txt llvm/lib/Target/XCore/LLVMBuild.txt llvm/lib/Target/XCore/MCTargetDesc/CMakeLists.txt llvm/lib/Target/XCore/MCTargetDesc/LLVMBuild.txt llvm/lib/Target/XCore/README.txt llvm/lib/Target/XCore/TargetInfo/CMakeLists.txt llvm/lib/Target/XCore/TargetInfo/LLVMBuild.txt llvm/lib/Testing/CMakeLists.txt llvm/lib/Testing/LLVMBuild.txt llvm/lib/Testing/Support/CMakeLists.txt llvm/lib/Testing/Support/LLVMBuild.txt llvm/lib/TextAPI/CMakeLists.txt llvm/lib/TextAPI/LLVMBuild.txt llvm/lib/ToolDrivers/CMakeLists.txt llvm/lib/ToolDrivers/LLVMBuild.txt llvm/lib/ToolDrivers/llvm-dlltool/CMakeLists.txt llvm/lib/ToolDrivers/llvm-dlltool/LLVMBuild.txt llvm/lib/ToolDrivers/llvm-lib/CMakeLists.txt llvm/lib/ToolDrivers/llvm-lib/LLVMBuild.txt llvm/lib/Transforms/AggressiveInstCombine/CMakeLists.txt llvm/lib/Transforms/AggressiveInstCombine/LLVMBuild.txt llvm/lib/Transforms/CFGuard/CMakeLists.txt llvm/lib/Transforms/CFGuard/LLVMBuild.txt llvm/lib/Transforms/CMakeLists.txt llvm/lib/Transforms/Coroutines/CMakeLists.txt llvm/lib/Transforms/Coroutines/LLVMBuild.txt llvm/lib/Transforms/Hello/ llvm/lib/Transforms/IPO/CMakeLists.txt llvm/lib/Transforms/IPO/LLVMBuild.txt llvm/lib/Transforms/InstCombine/CMakeLists.txt llvm/lib/Transforms/InstCombine/LLVMBuild.txt llvm/lib/Transforms/Instrumentation/CMakeLists.txt llvm/lib/Transforms/Instrumentation/LLVMBuild.txt llvm/lib/Transforms/LLVMBuild.txt llvm/lib/Transforms/ObjCARC/CMakeLists.txt llvm/lib/Transforms/ObjCARC/LLVMBuild.txt llvm/lib/Transforms/Scalar/CMakeLists.txt llvm/lib/Transforms/Scalar/LLVMBuild.txt llvm/lib/Transforms/Utils/CMakeLists.txt llvm/lib/Transforms/Utils/LLVMBuild.txt llvm/lib/Transforms/Vectorize/CMakeLists.txt llvm/lib/Transforms/Vectorize/LLVMBuild.txt llvm/lib/WindowsManifest/CMakeLists.txt llvm/lib/WindowsManifest/LLVMBuild.txt llvm/lib/XRay/CMakeLists.txt llvm/lib/XRay/LLVMBuild.txt llvm/llvm.spec.in llvm/projects/ llvm/resources/ llvm/runtimes/ llvm/test/ llvm/tools/CMakeLists.txt llvm/tools/LLVMBuild.txt llvm/tools/bugpoint/CMakeLists.txt llvm/tools/bugpoint/LLVMBuild.txt llvm/tools/bugpoint-passes/ llvm/tools/dsymutil/ llvm/tools/gold/ llvm/tools/llc/CMakeLists.txt llvm/tools/llc/LLVMBuild.txt llvm/tools/lli/CMakeLists.txt llvm/tools/lli/ChildTarget/CMakeLists.txt llvm/tools/lli/ChildTarget/LLVMBuild.txt llvm/tools/lli/LLVMBuild.txt llvm/tools/llvm-ar/CMakeLists.txt llvm/tools/llvm-ar/LLVMBuild.txt llvm/tools/llvm-as/CMakeLists.txt llvm/tools/llvm-as/LLVMBuild.txt llvm/tools/llvm-as-fuzzer/ llvm/tools/llvm-bcanalyzer/CMakeLists.txt llvm/tools/llvm-bcanalyzer/LLVMBuild.txt llvm/tools/llvm-c-test/ llvm/tools/llvm-cat/ llvm/tools/llvm-cfi-verify/ llvm/tools/llvm-config/ llvm/tools/llvm-cov/CMakeLists.txt llvm/tools/llvm-cov/LLVMBuild.txt llvm/tools/llvm-cvtres/ llvm/tools/llvm-cxxdump/CMakeLists.txt llvm/tools/llvm-cxxdump/LLVMBuild.txt llvm/tools/llvm-cxxfilt/CMakeLists.txt llvm/tools/llvm-cxxmap/CMakeLists.txt llvm/tools/llvm-cxxmap/LLVMBuild.txt llvm/tools/llvm-diff/CMakeLists.txt llvm/tools/llvm-diff/LLVMBuild.txt llvm/tools/llvm-dis/CMakeLists.txt llvm/tools/llvm-dis/LLVMBuild.txt llvm/tools/llvm-dwarfdump/CMakeLists.txt llvm/tools/llvm-dwarfdump/LLVMBuild.txt llvm/tools/llvm-dwarfdump/fuzzer/ -llvm/tools/llvm-dwp/ +llvm/tools/llvm-dwp/CMakeLists.txt +llvm/tools/llvm-dwp/LLVMBuild.txt llvm/tools/llvm-elfabi/ llvm/tools/llvm-exegesis/ llvm/tools/llvm-extract/CMakeLists.txt llvm/tools/llvm-extract/LLVMBuild.txt llvm/tools/llvm-go/ llvm/tools/llvm-ifs/ llvm/tools/llvm-isel-fuzzer/ llvm/tools/llvm-itanium-demangle-fuzzer/ llvm/tools/llvm-jitlink/ llvm/tools/llvm-jitlistener/ llvm/tools/llvm-link/CMakeLists.txt llvm/tools/llvm-link/LLVMBuild.txt llvm/tools/llvm-lipo/ llvm/tools/llvm-lto/CMakeLists.txt llvm/tools/llvm-lto/LLVMBuild.txt llvm/tools/llvm-lto2/CMakeLists.txt llvm/tools/llvm-lto2/LLVMBuild.txt llvm/tools/llvm-mc/CMakeLists.txt llvm/tools/llvm-mc/LLVMBuild.txt llvm/tools/llvm-mc-assemble-fuzzer/ llvm/tools/llvm-mc-disassemble-fuzzer/ llvm/tools/llvm-mca/CMakeLists.txt llvm/tools/llvm-mca/LLVMBuild.txt llvm/tools/llvm-microsoft-demangle-fuzzer/ llvm/tools/llvm-modextract/CMakeLists.txt llvm/tools/llvm-modextract/LLVMBuild.txt llvm/tools/llvm-mt/ llvm/tools/llvm-nm/CMakeLists.txt llvm/tools/llvm-nm/LLVMBuild.txt llvm/tools/llvm-objcopy/CMakeLists.txt llvm/tools/llvm-objcopy/LLVMBuild.txt llvm/tools/llvm-objdump/CMakeLists.txt llvm/tools/llvm-objdump/LLVMBuild.txt llvm/tools/llvm-opt-fuzzer/ llvm/tools/llvm-opt-report/ llvm/tools/llvm-pdbutil/CMakeLists.txt llvm/tools/llvm-pdbutil/LLVMBuild.txt llvm/tools/llvm-profdata/CMakeLists.txt llvm/tools/llvm-profdata/LLVMBuild.txt llvm/tools/llvm-rc/ llvm/tools/llvm-readobj/CMakeLists.txt llvm/tools/llvm-readobj/LLVMBuild.txt llvm/tools/llvm-reduce/ llvm/tools/llvm-rtdyld/CMakeLists.txt llvm/tools/llvm-rtdyld/LLVMBuild.txt llvm/tools/llvm-shlib/ -llvm/tools/llvm-size/ +llvm/tools/llvm-size/CMakeLists.txt +llvm/tools/llvm-size/LLVMBuild.txt llvm/tools/llvm-special-case-list-fuzzer/ llvm/tools/llvm-split/ llvm/tools/llvm-stress/CMakeLists.txt llvm/tools/llvm-stress/LLVMBuild.txt -llvm/tools/llvm-strings/ +llvm/tools/llvm-strings/CMakeLists.txt +llvm/tools/llvm-strings/LLVMBuild.txt llvm/tools/llvm-symbolizer/CMakeLists.txt llvm/tools/llvm-undname/ llvm/tools/llvm-xray/CMakeLists.txt llvm/tools/llvm-yaml-numeric-parser-fuzzer/ llvm/tools/lto/ llvm/tools/msbuild/ llvm/tools/obj2yaml/ llvm/tools/opt/CMakeLists.txt llvm/tools/opt/LLVMBuild.txt llvm/tools/opt-viewer/ llvm/tools/remarks-shlib/ llvm/tools/sancov/ llvm/tools/sanstats/ llvm/tools/verify-uselistorder/ llvm/tools/vfabi-demangle-fuzzer/ llvm/tools/xcode-toolchain/ llvm/tools/yaml2obj/ llvm/unittests/ llvm/utils/DSAclean.py llvm/utils/DSAextract.py llvm/utils/FileCheck/ llvm/utils/GenLibDeps.pl llvm/utils/GetRepositoryPath llvm/utils/GetSourceVersion llvm/utils/KillTheDoctor/ llvm/utils/LLVMBuild.txt llvm/utils/LLVMVisualizers/ llvm/utils/Misc/ llvm/utils/PerfectShuffle/ llvm/utils/Reviewing/ llvm/utils/TableGen/CMakeLists.txt llvm/utils/TableGen/GlobalISel/CMakeLists.txt llvm/utils/TableGen/LLVMBuild.txt llvm/utils/TableGen/tdtags llvm/utils/Target/ llvm/utils/UpdateCMakeLists.pl llvm/utils/UpdateTestChecks/ llvm/utils/abtest.py llvm/utils/add_argument_names.py llvm/utils/benchmark/ llvm/utils/bisect llvm/utils/bisect-skip-count llvm/utils/bugpoint/ llvm/utils/bugpoint_gisel_reducer.py llvm/utils/check-each-file llvm/utils/chunk-print-before-all.py llvm/utils/clang-parse-diagnostics-file llvm/utils/codegen-diff llvm/utils/collect_and_build_with_pgo.py llvm/utils/count/ llvm/utils/countloc.sh llvm/utils/create_ladder_graph.py llvm/utils/crosstool/ llvm/utils/demangle_tree.py llvm/utils/docker/ llvm/utils/emacs/ llvm/utils/extract_symbols.py llvm/utils/extract_vplan.py llvm/utils/findmisopt llvm/utils/findoptdiff llvm/utils/findsym.pl llvm/utils/fpcmp/ llvm/utils/gdb-scripts/ llvm/utils/getsrcs.sh llvm/utils/git-svn/ llvm/utils/gn/ llvm/utils/indirect_calls.py llvm/utils/jedit/ llvm/utils/kate/ llvm/utils/lint/ llvm/utils/lit/ llvm/utils/lldbDataFormatters.py llvm/utils/llvm-build/ llvm/utils/llvm-compilers-check llvm/utils/llvm-gisel-cov.py llvm/utils/llvm-lit/ llvm/utils/llvm-locstats/ llvm/utils/llvm-native-gxx llvm/utils/llvm.grm llvm/utils/llvmdo llvm/utils/llvmgrep llvm/utils/not/ llvm/utils/prepare-code-coverage-artifact.py llvm/utils/release/ llvm/utils/sanitizers/ llvm/utils/schedcover.py llvm/utils/shuffle_fuzz.py llvm/utils/shuffle_select_fuzz_tester.py llvm/utils/sort_includes.py llvm/utils/testgen/ llvm/utils/textmate/ llvm/utils/unicode-case-fold.py llvm/utils/unittest/ llvm/utils/update_analyze_test_checks.py llvm/utils/update_cc_test_checks.py llvm/utils/update_llc_test_checks.py llvm/utils/update_mca_test_checks.py llvm/utils/update_mir_test_checks.py llvm/utils/update_test_checks.py llvm/utils/valgrind/ llvm/utils/vim/ llvm/utils/vscode/ llvm/utils/wciia.py llvm/utils/yaml-bench/ mlir/ openmp/.arcconfig openmp/.gitignore openmp/CMakeLists.txt openmp/README.rst openmp/cmake/ openmp/libomptarget/ openmp/runtime/.clang-format openmp/runtime/CMakeLists.txt openmp/runtime/README.txt openmp/runtime/cmake/ openmp/runtime/doc/ openmp/runtime/src/CMakeLists.txt openmp/runtime/test/ openmp/runtime/tools/ openmp/tools/ openmp/www/ parallel-libs/ polly/ pstl/ Index: head/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- head/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp (revision 362718) +++ head/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp (revision 362719) @@ -1,10136 +1,10137 @@ //===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // These classes wrap the information about a call or function // definition used to handle ABI compliancy. // //===----------------------------------------------------------------------===// #include "TargetInfo.h" #include "ABIInfo.h" #include "CGBlocks.h" #include "CGCXXABI.h" #include "CGValue.h" #include "CodeGenFunction.h" #include "clang/AST/Attr.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/CodeGen/SwiftCallingConv.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Type.h" #include "llvm/Support/raw_ostream.h" #include // std::sort using namespace clang; using namespace CodeGen; // Helper for coercing an aggregate argument or return value into an integer // array of the same size (including padding) and alignment. This alternate // coercion happens only for the RenderScript ABI and can be removed after // runtimes that rely on it are no longer supported. // // RenderScript assumes that the size of the argument / return value in the IR // is the same as the size of the corresponding qualified type. This helper // coerces the aggregate type into an array of the same size (including // padding). This coercion is used in lieu of expansion of struct members or // other canonical coercions that return a coerced-type of larger size. // // Ty - The argument / return value type // Context - The associated ASTContext // LLVMContext - The associated LLVMContext static ABIArgInfo coerceToIntArray(QualType Ty, ASTContext &Context, llvm::LLVMContext &LLVMContext) { // Alignment and Size are measured in bits. const uint64_t Size = Context.getTypeSize(Ty); const uint64_t Alignment = Context.getTypeAlign(Ty); llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Alignment); const uint64_t NumElements = (Size + Alignment - 1) / Alignment; return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements)); } static void AssignToArrayRange(CodeGen::CGBuilderTy &Builder, llvm::Value *Array, llvm::Value *Value, unsigned FirstIndex, unsigned LastIndex) { // Alternatively, we could emit this as a loop in the source. for (unsigned I = FirstIndex; I <= LastIndex; ++I) { llvm::Value *Cell = Builder.CreateConstInBoundsGEP1_32(Builder.getInt8Ty(), Array, I); Builder.CreateAlignedStore(Value, Cell, CharUnits::One()); } } static bool isAggregateTypeForABI(QualType T) { return !CodeGenFunction::hasScalarEvaluationKind(T) || T->isMemberFunctionPointerType(); } ABIArgInfo ABIInfo::getNaturalAlignIndirect(QualType Ty, bool ByRef, bool Realign, llvm::Type *Padding) const { return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty), ByRef, Realign, Padding); } ABIArgInfo ABIInfo::getNaturalAlignIndirectInReg(QualType Ty, bool Realign) const { return ABIArgInfo::getIndirectInReg(getContext().getTypeAlignInChars(Ty), /*ByRef*/ false, Realign); } Address ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return Address::invalid(); } ABIInfo::~ABIInfo() {} /// Does the given lowering require more than the given number of /// registers when expanded? /// /// This is intended to be the basis of a reasonable basic implementation /// of should{Pass,Return}IndirectlyForSwift. /// /// For most targets, a limit of four total registers is reasonable; this /// limits the amount of code required in order to move around the value /// in case it wasn't produced immediately prior to the call by the caller /// (or wasn't produced in exactly the right registers) or isn't used /// immediately within the callee. But some targets may need to further /// limit the register count due to an inability to support that many /// return registers. static bool occupiesMoreThan(CodeGenTypes &cgt, ArrayRef scalarTypes, unsigned maxAllRegisters) { unsigned intCount = 0, fpCount = 0; for (llvm::Type *type : scalarTypes) { if (type->isPointerTy()) { intCount++; } else if (auto intTy = dyn_cast(type)) { auto ptrWidth = cgt.getTarget().getPointerWidth(0); intCount += (intTy->getBitWidth() + ptrWidth - 1) / ptrWidth; } else { assert(type->isVectorTy() || type->isFloatingPointTy()); fpCount++; } } return (intCount + fpCount > maxAllRegisters); } bool SwiftABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize, llvm::Type *eltTy, unsigned numElts) const { // The default implementation of this assumes that the target guarantees // 128-bit SIMD support but nothing more. return (vectorSize.getQuantity() > 8 && vectorSize.getQuantity() <= 16); } static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, CGCXXABI &CXXABI) { const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD) { if (!RT->getDecl()->canPassInRegisters()) return CGCXXABI::RAA_Indirect; return CGCXXABI::RAA_Default; } return CXXABI.getRecordArgABI(RD); } static CGCXXABI::RecordArgABI getRecordArgABI(QualType T, CGCXXABI &CXXABI) { const RecordType *RT = T->getAs(); if (!RT) return CGCXXABI::RAA_Default; return getRecordArgABI(RT, CXXABI); } static bool classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, const ABIInfo &Info) { QualType Ty = FI.getReturnType(); if (const auto *RT = Ty->getAs()) if (!isa(RT->getDecl()) && !RT->getDecl()->canPassInRegisters()) { FI.getReturnInfo() = Info.getNaturalAlignIndirect(Ty); return true; } return CXXABI.classifyReturnType(FI); } /// Pass transparent unions as if they were the type of the first element. Sema /// should ensure that all elements of the union have the same "machine type". static QualType useFirstFieldIfTransparentUnion(QualType Ty) { if (const RecordType *UT = Ty->getAsUnionType()) { const RecordDecl *UD = UT->getDecl(); if (UD->hasAttr()) { assert(!UD->field_empty() && "sema created an empty transparent union"); return UD->field_begin()->getType(); } } return Ty; } CGCXXABI &ABIInfo::getCXXABI() const { return CGT.getCXXABI(); } ASTContext &ABIInfo::getContext() const { return CGT.getContext(); } llvm::LLVMContext &ABIInfo::getVMContext() const { return CGT.getLLVMContext(); } const llvm::DataLayout &ABIInfo::getDataLayout() const { return CGT.getDataLayout(); } const TargetInfo &ABIInfo::getTarget() const { return CGT.getTarget(); } const CodeGenOptions &ABIInfo::getCodeGenOpts() const { return CGT.getCodeGenOpts(); } bool ABIInfo::isAndroid() const { return getTarget().getTriple().isAndroid(); } bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { return false; } bool ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const { return false; } LLVM_DUMP_METHOD void ABIArgInfo::dump() const { raw_ostream &OS = llvm::errs(); OS << "(ABIArgInfo Kind="; switch (TheKind) { case Direct: OS << "Direct Type="; if (llvm::Type *Ty = getCoerceToType()) Ty->print(OS); else OS << "null"; break; case Extend: OS << "Extend"; break; case Ignore: OS << "Ignore"; break; case InAlloca: OS << "InAlloca Offset=" << getInAllocaFieldIndex(); break; case Indirect: OS << "Indirect Align=" << getIndirectAlign().getQuantity() << " ByVal=" << getIndirectByVal() << " Realign=" << getIndirectRealign(); break; case Expand: OS << "Expand"; break; case CoerceAndExpand: OS << "CoerceAndExpand Type="; getCoerceAndExpandType()->print(OS); break; } OS << ")\n"; } // Dynamically round a pointer up to a multiple of the given alignment. static llvm::Value *emitRoundPointerUpToAlignment(CodeGenFunction &CGF, llvm::Value *Ptr, CharUnits Align) { llvm::Value *PtrAsInt = Ptr; // OverflowArgArea = (OverflowArgArea + Align - 1) & -Align; PtrAsInt = CGF.Builder.CreatePtrToInt(PtrAsInt, CGF.IntPtrTy); PtrAsInt = CGF.Builder.CreateAdd(PtrAsInt, llvm::ConstantInt::get(CGF.IntPtrTy, Align.getQuantity() - 1)); PtrAsInt = CGF.Builder.CreateAnd(PtrAsInt, llvm::ConstantInt::get(CGF.IntPtrTy, -Align.getQuantity())); PtrAsInt = CGF.Builder.CreateIntToPtr(PtrAsInt, Ptr->getType(), Ptr->getName() + ".aligned"); return PtrAsInt; } /// Emit va_arg for a platform using the common void* representation, /// where arguments are simply emitted in an array of slots on the stack. /// /// This version implements the core direct-value passing rules. /// /// \param SlotSize - The size and alignment of a stack slot. /// Each argument will be allocated to a multiple of this number of /// slots, and all the slots will be aligned to this value. /// \param AllowHigherAlign - The slot alignment is not a cap; /// an argument type with an alignment greater than the slot size /// will be emitted on a higher-alignment address, potentially /// leaving one or more empty slots behind as padding. If this /// is false, the returned address might be less-aligned than /// DirectAlign. static Address emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr, llvm::Type *DirectTy, CharUnits DirectSize, CharUnits DirectAlign, CharUnits SlotSize, bool AllowHigherAlign) { // Cast the element type to i8* if necessary. Some platforms define // va_list as a struct containing an i8* instead of just an i8*. if (VAListAddr.getElementType() != CGF.Int8PtrTy) VAListAddr = CGF.Builder.CreateElementBitCast(VAListAddr, CGF.Int8PtrTy); llvm::Value *Ptr = CGF.Builder.CreateLoad(VAListAddr, "argp.cur"); // If the CC aligns values higher than the slot size, do so if needed. Address Addr = Address::invalid(); if (AllowHigherAlign && DirectAlign > SlotSize) { Addr = Address(emitRoundPointerUpToAlignment(CGF, Ptr, DirectAlign), DirectAlign); } else { Addr = Address(Ptr, SlotSize); } // Advance the pointer past the argument, then store that back. CharUnits FullDirectSize = DirectSize.alignTo(SlotSize); Address NextPtr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next"); CGF.Builder.CreateStore(NextPtr.getPointer(), VAListAddr); // If the argument is smaller than a slot, and this is a big-endian // target, the argument will be right-adjusted in its slot. if (DirectSize < SlotSize && CGF.CGM.getDataLayout().isBigEndian() && !DirectTy->isStructTy()) { Addr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, SlotSize - DirectSize); } Addr = CGF.Builder.CreateElementBitCast(Addr, DirectTy); return Addr; } /// Emit va_arg for a platform using the common void* representation, /// where arguments are simply emitted in an array of slots on the stack. /// /// \param IsIndirect - Values of this type are passed indirectly. /// \param ValueInfo - The size and alignment of this type, generally /// computed with getContext().getTypeInfoInChars(ValueTy). /// \param SlotSizeAndAlign - The size and alignment of a stack slot. /// Each argument will be allocated to a multiple of this number of /// slots, and all the slots will be aligned to this value. /// \param AllowHigherAlign - The slot alignment is not a cap; /// an argument type with an alignment greater than the slot size /// will be emitted on a higher-alignment address, potentially /// leaving one or more empty slots behind as padding. static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType ValueTy, bool IsIndirect, std::pair ValueInfo, CharUnits SlotSizeAndAlign, bool AllowHigherAlign) { // The size and alignment of the value that was passed directly. CharUnits DirectSize, DirectAlign; if (IsIndirect) { DirectSize = CGF.getPointerSize(); DirectAlign = CGF.getPointerAlign(); } else { DirectSize = ValueInfo.first; DirectAlign = ValueInfo.second; } // Cast the address we've calculated to the right type. llvm::Type *DirectTy = CGF.ConvertTypeForMem(ValueTy); if (IsIndirect) DirectTy = DirectTy->getPointerTo(0); Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, DirectTy, DirectSize, DirectAlign, SlotSizeAndAlign, AllowHigherAlign); if (IsIndirect) { Addr = Address(CGF.Builder.CreateLoad(Addr), ValueInfo.second); } return Addr; } static Address emitMergePHI(CodeGenFunction &CGF, Address Addr1, llvm::BasicBlock *Block1, Address Addr2, llvm::BasicBlock *Block2, const llvm::Twine &Name = "") { assert(Addr1.getType() == Addr2.getType()); llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name); PHI->addIncoming(Addr1.getPointer(), Block1); PHI->addIncoming(Addr2.getPointer(), Block2); CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment()); return Address(PHI, Align); } TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; } // If someone can figure out a general rule for this, that would be great. // It's probably just doomed to be platform-dependent, though. unsigned TargetCodeGenInfo::getSizeOfUnwindException() const { // Verified for: // x86-64 FreeBSD, Linux, Darwin // x86-32 FreeBSD, Linux, Darwin // PowerPC Linux, Darwin // ARM Darwin (*not* EABI) // AArch64 Linux return 32; } bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args, const FunctionNoProtoType *fnType) const { // The following conventions are known to require this to be false: // x86_stdcall // MIPS // For everything else, we just prefer false unless we opt out. return false; } void TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const { // This assumes the user is passing a library name like "rt" instead of a // filename like "librt.a/so", and that they don't care whether it's static or // dynamic. Opt = "-l"; Opt += Lib; } unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const { // OpenCL kernels are called via an explicit runtime API with arguments // set with clSetKernelArg(), not as normal sub-functions. // Return SPIR_KERNEL by default as the kernel calling convention to // ensure the fingerprint is fixed such way that each OpenCL argument // gets one matching argument in the produced kernel function argument // list to enable feasible implementation of clSetKernelArg() with // aggregates etc. In case we would use the default C calling conv here, // clSetKernelArg() might break depending on the target-specific // conventions; different targets might split structs passed as values // to multiple function arguments etc. return llvm::CallingConv::SPIR_KERNEL; } llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM, llvm::PointerType *T, QualType QT) const { return llvm::ConstantPointerNull::get(T); } LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, const VarDecl *D) const { assert(!CGM.getLangOpts().OpenCL && !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && "Address space agnostic languages only"); return D ? D->getType().getAddressSpace() : LangAS::Default; } llvm::Value *TargetCodeGenInfo::performAddrSpaceCast( CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr, LangAS DestAddr, llvm::Type *DestTy, bool isNonNull) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. if (auto *C = dyn_cast(Src)) return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy); // Try to preserve the source's name to make IR more readable. return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( Src, DestTy, Src->hasName() ? Src->getName() + ".ascast" : ""); } llvm::Constant * TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src, LangAS SrcAddr, LangAS DestAddr, llvm::Type *DestTy) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. return llvm::ConstantExpr::getPointerCast(Src, DestTy); } llvm::SyncScope::ID TargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts, SyncScope Scope, llvm::AtomicOrdering Ordering, llvm::LLVMContext &Ctx) const { return Ctx.getOrInsertSyncScopeID(""); /* default sync scope */ } static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); /// isEmptyField - Return true iff a the field is "empty", that is it /// is an unnamed bit-field or an (array of) empty record(s). static bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays) { if (FD->isUnnamedBitfield()) return true; QualType FT = FD->getType(); // Constant arrays of empty records count as empty, strip them off. // Constant arrays of zero length always count as empty. if (AllowArrays) while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { if (AT->getSize() == 0) return true; FT = AT->getElementType(); } const RecordType *RT = FT->getAs(); if (!RT) return false; // C++ record fields are never empty, at least in the Itanium ABI. // // FIXME: We should use a predicate for whether this behavior is true in the // current ABI. if (isa(RT->getDecl())) return false; return isEmptyRecord(Context, FT, AllowArrays); } /// isEmptyRecord - Return true iff a structure contains only empty /// fields. Note that a structure with a flexible array member is not /// considered empty. static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { const RecordType *RT = T->getAs(); if (!RT) return false; const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return false; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) for (const auto &I : CXXRD->bases()) if (!isEmptyRecord(Context, I.getType(), true)) return false; for (const auto *I : RD->fields()) if (!isEmptyField(Context, I, AllowArrays)) return false; return true; } /// isSingleElementStruct - Determine if a structure is a "single /// element struct", i.e. it has exactly one non-empty field or /// exactly one field which is itself a single element /// struct. Structures with flexible array members are never /// considered single element structs. /// /// \return The field declaration for the single non-empty field, if /// it exists. static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { const RecordType *RT = T->getAs(); if (!RT) return nullptr; const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return nullptr; const Type *Found = nullptr; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) { // Ignore empty records. if (isEmptyRecord(Context, I.getType(), true)) continue; // If we already found an element then this isn't a single-element struct. if (Found) return nullptr; // If this is non-empty and not a single element struct, the composite // cannot be a single element struct. Found = isSingleElementStruct(I.getType(), Context); if (!Found) return nullptr; } } // Check for single element. for (const auto *FD : RD->fields()) { QualType FT = FD->getType(); // Ignore empty fields. if (isEmptyField(Context, FD, true)) continue; // If we already found an element then this isn't a single-element // struct. if (Found) return nullptr; // Treat single element arrays as the element. while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { if (AT->getSize().getZExtValue() != 1) break; FT = AT->getElementType(); } if (!isAggregateTypeForABI(FT)) { Found = FT.getTypePtr(); } else { Found = isSingleElementStruct(FT, Context); if (!Found) return nullptr; } } // We don't consider a struct a single-element struct if it has // padding beyond the element type. if (Found && Context.getTypeSize(Found) != Context.getTypeSize(T)) return nullptr; return Found; } namespace { Address EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, const ABIArgInfo &AI) { // This default implementation defers to the llvm backend's va_arg // instruction. It can handle only passing arguments directly // (typically only handled in the backend for primitive types), or // aggregates passed indirectly by pointer (NOTE: if the "byval" // flag has ABI impact in the callee, this implementation cannot // work.) // Only a few cases are covered here at the moment -- those needed // by the default abi. llvm::Value *Val; if (AI.isIndirect()) { assert(!AI.getPaddingType() && "Unexpected PaddingType seen in arginfo in generic VAArg emitter!"); assert( !AI.getIndirectRealign() && "Unexpected IndirectRealign seen in arginfo in generic VAArg emitter!"); auto TyInfo = CGF.getContext().getTypeInfoInChars(Ty); CharUnits TyAlignForABI = TyInfo.second; llvm::Type *BaseTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty)); llvm::Value *Addr = CGF.Builder.CreateVAArg(VAListAddr.getPointer(), BaseTy); return Address(Addr, TyAlignForABI); } else { assert((AI.isDirect() || AI.isExtend()) && "Unexpected ArgInfo Kind in generic VAArg emitter!"); assert(!AI.getInReg() && "Unexpected InReg seen in arginfo in generic VAArg emitter!"); assert(!AI.getPaddingType() && "Unexpected PaddingType seen in arginfo in generic VAArg emitter!"); assert(!AI.getDirectOffset() && "Unexpected DirectOffset seen in arginfo in generic VAArg emitter!"); assert(!AI.getCoerceToType() && "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!"); Address Temp = CGF.CreateMemTemp(Ty, "varet"); Val = CGF.Builder.CreateVAArg(VAListAddr.getPointer(), CGF.ConvertType(Ty)); CGF.Builder.CreateStore(Val, Temp); return Temp; } } /// DefaultABIInfo - The default implementation for ABI specific /// details. This implementation provides information which results in /// self-consistent and sensible LLVM IR generation, but does not /// conform to any particular ABI. class DefaultABIInfo : public ABIInfo { public: DefaultABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override { return EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty)); } }; class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { public: DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} }; ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); if (isAggregateTypeForABI(Ty)) { // Records with non-trivial destructors/copy-constructors should not be // passed by value. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); return getNaturalAlignIndirect(Ty); } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (isAggregateTypeForABI(RetTy)) return getNaturalAlignIndirect(RetTy); // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } //===----------------------------------------------------------------------===// // WebAssembly ABI Implementation // // This is a very simple ABI that relies a lot on DefaultABIInfo. //===----------------------------------------------------------------------===// class WebAssemblyABIInfo final : public SwiftABIInfo { DefaultABIInfo defaultInfo; public: explicit WebAssemblyABIInfo(CodeGen::CodeGenTypes &CGT) : SwiftABIInfo(CGT), defaultInfo(CGT) {} private: ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo and EmitVAArg are virtual, so we // overload them. void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &Arg : FI.arguments()) Arg.info = classifyArgumentType(Arg.type); } Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool shouldPassIndirectlyForSwift(ArrayRef scalars, bool asReturnValue) const override { return occupiesMoreThan(CGT, scalars, /*total*/ 4); } bool isSwiftErrorInRegister() const override { return false; } }; class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo { public: explicit WebAssemblyTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new WebAssemblyABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); if (const auto *FD = dyn_cast_or_null(D)) { if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B; B.addAttribute("wasm-import-module", Attr->getImportModule()); Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); } if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B; B.addAttribute("wasm-import-name", Attr->getImportName()); Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); } if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B; B.addAttribute("wasm-export-name", Attr->getExportName()); Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); } } if (auto *FD = dyn_cast_or_null(D)) { llvm::Function *Fn = cast(GV); if (!FD->doesThisDeclarationHaveABody() && !FD->hasPrototype()) Fn->addFnAttr("no-prototype"); } } }; /// Classify argument of given type \p Ty. ABIArgInfo WebAssemblyABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); if (isAggregateTypeForABI(Ty)) { // Records with non-trivial destructors/copy-constructors should not be // passed by value. if (auto RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); // Lower single-element structs to just pass a regular value. TODO: We // could do reasonable-size multiple-element structs too, using getExpand(), // though watch out for things like bitfields. if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); } // Otherwise just do the default thing. return defaultInfo.classifyArgumentType(Ty); } ABIArgInfo WebAssemblyABIInfo::classifyReturnType(QualType RetTy) const { if (isAggregateTypeForABI(RetTy)) { // Records with non-trivial destructors/copy-constructors should not be // returned by value. if (!getRecordArgABI(RetTy, getCXXABI())) { // Ignore empty structs/unions. if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Lower single-element structs to just return a regular value. TODO: We // could do reasonable-size multiple-element structs too, using // ABIArgInfo::getDirect(). if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); } } // Otherwise just do the default thing. return defaultInfo.classifyReturnType(RetTy); } Address WebAssemblyABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { bool IsIndirect = isAggregateTypeForABI(Ty) && !isEmptyRecord(getContext(), Ty, true) && !isSingleElementStruct(Ty, getContext()); return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(4), /*AllowHigherAlign=*/true); } //===----------------------------------------------------------------------===// // le32/PNaCl bitcode ABI Implementation // // This is a simplified version of the x86_32 ABI. Arguments and return values // are always passed on the stack. //===----------------------------------------------------------------------===// class PNaClABIInfo : public ABIInfo { public: PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class PNaClTargetCodeGenInfo : public TargetCodeGenInfo { public: PNaClTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new PNaClABIInfo(CGT)) {} }; void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } Address PNaClABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { // The PNaCL ABI is a bit odd, in that varargs don't use normal // function classification. Structs get passed directly for varargs // functions, through a rewriting transform in // pnacl-llvm/lib/Transforms/NaCl/ExpandVarArgs.cpp, which allows // this target to actually support a va_arg instructions with an // aggregate type, unlike other targets. return EmitVAArgInstr(CGF, VAListAddr, Ty, ABIArgInfo::getDirect()); } /// Classify argument of given type \p Ty. ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty) const { if (isAggregateTypeForABI(Ty)) { if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); return getNaturalAlignIndirect(Ty); } else if (const EnumType *EnumTy = Ty->getAs()) { // Treat an enum type as its underlying type. Ty = EnumTy->getDecl()->getIntegerType(); } else if (Ty->isFloatingType()) { // Floating-point types don't go inreg. return ABIArgInfo::getDirect(); } return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // In the PNaCl ABI we always return records/structures on the stack. if (isAggregateTypeForABI(RetTy)) return getNaturalAlignIndirect(RetTy); // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } /// IsX86_MMXType - Return true if this is an MMX type. bool IsX86_MMXType(llvm::Type *IRType) { // Return true if the type is an MMX type <2 x i32>, <4 x i16>, or <8 x i8>. return IRType->isVectorTy() && IRType->getPrimitiveSizeInBits() == 64 && cast(IRType)->getElementType()->isIntegerTy() && IRType->getScalarSizeInBits() != 64; } static llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF, StringRef Constraint, llvm::Type* Ty) { bool IsMMXCons = llvm::StringSwitch(Constraint) .Cases("y", "&y", "^Ym", true) .Default(false); if (IsMMXCons && Ty->isVectorTy()) { if (cast(Ty)->getBitWidth() != 64) { // Invalid MMX constraint return nullptr; } return llvm::Type::getX86_MMXTy(CGF.getLLVMContext()); } // No operation needed return Ty; } /// Returns true if this type can be passed in SSE registers with the /// X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorTypeForVectorCall(ASTContext &Context, QualType Ty) { if (const BuiltinType *BT = Ty->getAs()) { if (BT->isFloatingPoint() && BT->getKind() != BuiltinType::Half) { if (BT->getKind() == BuiltinType::LongDouble) { if (&Context.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) return false; } return true; } } else if (const VectorType *VT = Ty->getAs()) { // vectorcall can pass XMM, YMM, and ZMM vectors. We don't pass SSE1 MMX // registers specially. unsigned VecSize = Context.getTypeSize(VT); if (VecSize == 128 || VecSize == 256 || VecSize == 512) return true; } return false; } /// Returns true if this aggregate is small enough to be passed in SSE registers /// in the X86_VectorCall calling convention. Shared between x86_32 and x86_64. static bool isX86VectorCallAggregateSmallEnough(uint64_t NumMembers) { return NumMembers <= 4; } /// Returns a Homogeneous Vector Aggregate ABIArgInfo, used in X86. static ABIArgInfo getDirectX86Hva(llvm::Type* T = nullptr) { auto AI = ABIArgInfo::getDirect(T); AI.setInReg(true); AI.setCanBeFlattened(false); return AI; } //===----------------------------------------------------------------------===// // X86-32 ABI Implementation //===----------------------------------------------------------------------===// /// Similar to llvm::CCState, but for Clang. struct CCState { CCState(CGFunctionInfo &FI) : IsPreassigned(FI.arg_size()), CC(FI.getCallingConvention()) {} llvm::SmallBitVector IsPreassigned; unsigned CC = CallingConv::CC_C; unsigned FreeRegs = 0; unsigned FreeSSERegs = 0; }; enum { // Vectorcall only allows the first 6 parameters to be passed in registers. VectorcallMaxParamNumAsReg = 6 }; /// X86_32ABIInfo - The X86-32 ABI information. class X86_32ABIInfo : public SwiftABIInfo { enum Class { Integer, Float }; static const unsigned MinABIStackAlignInBytes = 4; bool IsDarwinVectorABI; bool IsRetSmallStructInRegABI; bool IsWin32StructABI; bool IsSoftFloatABI; bool IsMCUABI; unsigned DefaultNumRegisterParameters; static bool isRegisterSize(unsigned Size) { return (Size == 8 || Size == 16 || Size == 32 || Size == 64); } bool isHomogeneousAggregateBaseType(QualType Ty) const override { // FIXME: Assumes vectorcall is in use. return isX86VectorTypeForVectorCall(getContext(), Ty); } bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t NumMembers) const override { // FIXME: Assumes vectorcall is in use. return isX86VectorCallAggregateSmallEnough(NumMembers); } bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const; ABIArgInfo getIndirectReturnResult(QualType Ty, CCState &State) const; /// Return the alignment to use for the given type on the stack. unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const; Class classify(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const; ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; /// Updates the number of available free registers, returns /// true if any registers were allocated. bool updateFreeRegs(QualType Ty, CCState &State) const; bool shouldAggregateUseDirect(QualType Ty, CCState &State, bool &InReg, bool &NeedsPadding) const; bool shouldPrimitiveUseInReg(QualType Ty, CCState &State) const; bool canExpandIndirectArgument(QualType Ty) const; /// Rewrite the function info so that all memory arguments use /// inalloca. void rewriteWithInAlloca(CGFunctionInfo &FI) const; void addFieldToArgStruct(SmallVector &FrameFields, CharUnits &StackOffset, ABIArgInfo &Info, QualType Type) const; void runVectorCallFirstPass(CGFunctionInfo &FI, CCState &State) const; public: void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; X86_32ABIInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI, bool RetSmallStructInRegABI, bool Win32StructABI, unsigned NumRegisterParameters, bool SoftFloatABI) : SwiftABIInfo(CGT), IsDarwinVectorABI(DarwinVectorABI), IsRetSmallStructInRegABI(RetSmallStructInRegABI), IsWin32StructABI(Win32StructABI), IsSoftFloatABI(SoftFloatABI), IsMCUABI(CGT.getTarget().getTriple().isOSIAMCU()), DefaultNumRegisterParameters(NumRegisterParameters) {} bool shouldPassIndirectlyForSwift(ArrayRef scalars, bool asReturnValue) const override { // LLVM's x86-32 lowering currently only assigns up to three // integer registers and three fp registers. Oddly, it'll use up to // four vector registers for vectors, but those can overlap with the // scalar registers. return occupiesMoreThan(CGT, scalars, /*total*/ 3); } bool isSwiftErrorInRegister() const override { // x86-32 lowering does not support passing swifterror in a register. return false; } }; class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI, bool RetSmallStructInRegABI, bool Win32StructABI, unsigned NumRegisterParameters, bool SoftFloatABI) : TargetCodeGenInfo(new X86_32ABIInfo( CGT, DarwinVectorABI, RetSmallStructInRegABI, Win32StructABI, NumRegisterParameters, SoftFloatABI)) {} static bool isStructReturnInRegABI( const llvm::Triple &Triple, const CodeGenOptions &Opts); void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { // Darwin uses different dwarf register numbers for EH. if (CGM.getTarget().getTriple().isOSDarwin()) return 5; return 4; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF, StringRef Constraint, llvm::Type* Ty) const override { return X86AdjustInlineAsmType(CGF, Constraint, Ty); } void addReturnRegisterOutputs(CodeGenFunction &CGF, LValue ReturnValue, std::string &Constraints, std::vector &ResultRegTypes, std::vector &ResultTruncRegTypes, std::vector &ResultRegDests, std::string &AsmString, unsigned NumOutputs) const override; llvm::Constant * getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override { unsigned Sig = (0xeb << 0) | // jmp rel8 (0x06 << 8) | // .+0x08 ('v' << 16) | ('2' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } StringRef getARCRetainAutoreleasedReturnValueMarker() const override { return "movl\t%ebp, %ebp" "\t\t// marker for objc_retainAutoreleaseReturnValue"; } }; } /// Rewrite input constraint references after adding some output constraints. /// In the case where there is one output and one input and we add one output, /// we need to replace all operand references greater than or equal to 1: /// mov $0, $1 /// mov eax, $1 /// The result will be: /// mov $0, $2 /// mov eax, $2 static void rewriteInputConstraintReferences(unsigned FirstIn, unsigned NumNewOuts, std::string &AsmString) { std::string Buf; llvm::raw_string_ostream OS(Buf); size_t Pos = 0; while (Pos < AsmString.size()) { size_t DollarStart = AsmString.find('$', Pos); if (DollarStart == std::string::npos) DollarStart = AsmString.size(); size_t DollarEnd = AsmString.find_first_not_of('$', DollarStart); if (DollarEnd == std::string::npos) DollarEnd = AsmString.size(); OS << StringRef(&AsmString[Pos], DollarEnd - Pos); Pos = DollarEnd; size_t NumDollars = DollarEnd - DollarStart; if (NumDollars % 2 != 0 && Pos < AsmString.size()) { // We have an operand reference. size_t DigitStart = Pos; if (AsmString[DigitStart] == '{') { OS << '{'; ++DigitStart; } size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart); if (DigitEnd == std::string::npos) DigitEnd = AsmString.size(); StringRef OperandStr(&AsmString[DigitStart], DigitEnd - DigitStart); unsigned OperandIndex; if (!OperandStr.getAsInteger(10, OperandIndex)) { if (OperandIndex >= FirstIn) OperandIndex += NumNewOuts; OS << OperandIndex; } else { OS << OperandStr; } Pos = DigitEnd; } } AsmString = std::move(OS.str()); } /// Add output constraints for EAX:EDX because they are return registers. void X86_32TargetCodeGenInfo::addReturnRegisterOutputs( CodeGenFunction &CGF, LValue ReturnSlot, std::string &Constraints, std::vector &ResultRegTypes, std::vector &ResultTruncRegTypes, std::vector &ResultRegDests, std::string &AsmString, unsigned NumOutputs) const { uint64_t RetWidth = CGF.getContext().getTypeSize(ReturnSlot.getType()); // Use the EAX constraint if the width is 32 or smaller and EAX:EDX if it is // larger. if (!Constraints.empty()) Constraints += ','; if (RetWidth <= 32) { Constraints += "={eax}"; ResultRegTypes.push_back(CGF.Int32Ty); } else { // Use the 'A' constraint for EAX:EDX. Constraints += "=A"; ResultRegTypes.push_back(CGF.Int64Ty); } // Truncate EAX or EAX:EDX to an integer of the appropriate size. llvm::Type *CoerceTy = llvm::IntegerType::get(CGF.getLLVMContext(), RetWidth); ResultTruncRegTypes.push_back(CoerceTy); // Coerce the integer by bitcasting the return slot pointer. ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(CGF), CoerceTy->getPointerTo())); ResultRegDests.push_back(ReturnSlot); rewriteInputConstraintReferences(NumOutputs, 1, AsmString); } /// shouldReturnTypeInRegister - Determine if the given type should be /// returned in a register (for the Darwin and MCU ABI). bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty, ASTContext &Context) const { uint64_t Size = Context.getTypeSize(Ty); // For i386, type must be register sized. // For the MCU ABI, it only needs to be <= 8-byte if ((IsMCUABI && Size > 64) || (!IsMCUABI && !isRegisterSize(Size))) return false; if (Ty->isVectorType()) { // 64- and 128- bit vectors inside structures are not returned in // registers. if (Size == 64 || Size == 128) return false; return true; } // If this is a builtin, pointer, enum, complex type, member pointer, or // member function pointer it is ok. if (Ty->getAs() || Ty->hasPointerRepresentation() || Ty->isAnyComplexType() || Ty->isEnumeralType() || Ty->isBlockPointerType() || Ty->isMemberPointerType()) return true; // Arrays are treated like records. if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) return shouldReturnTypeInRegister(AT->getElementType(), Context); // Otherwise, it must be a record type. const RecordType *RT = Ty->getAs(); if (!RT) return false; // FIXME: Traverse bases here too. // Structure types are passed in register if all fields would be // passed in a register. for (const auto *FD : RT->getDecl()->fields()) { // Empty fields are ignored. if (isEmptyField(Context, FD, true)) continue; // Check fields recursively. if (!shouldReturnTypeInRegister(FD->getType(), Context)) return false; } return true; } static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) { // Treat complex types as the element type. if (const ComplexType *CTy = Ty->getAs()) Ty = CTy->getElementType(); // Check for a type which we know has a simple scalar argument-passing // convention without any padding. (We're specifically looking for 32 // and 64-bit integer and integer-equivalents, float, and double.) if (!Ty->getAs() && !Ty->hasPointerRepresentation() && !Ty->isEnumeralType() && !Ty->isBlockPointerType()) return false; uint64_t Size = Context.getTypeSize(Ty); return Size == 32 || Size == 64; } static bool addFieldSizes(ASTContext &Context, const RecordDecl *RD, uint64_t &Size) { for (const auto *FD : RD->fields()) { // Scalar arguments on the stack get 4 byte alignment on x86. If the // argument is smaller than 32-bits, expanding the struct will create // alignment padding. if (!is32Or64BitBasicType(FD->getType(), Context)) return false; // FIXME: Reject bit-fields wholesale; there are two problems, we don't know // how to expand them yet, and the predicate for telling if a bitfield still // counts as "basic" is more complicated than what we were doing previously. if (FD->isBitField()) return false; Size += Context.getTypeSize(FD->getType()); } return true; } static bool addBaseAndFieldSizes(ASTContext &Context, const CXXRecordDecl *RD, uint64_t &Size) { // Don't do this if there are any non-empty bases. for (const CXXBaseSpecifier &Base : RD->bases()) { if (!addBaseAndFieldSizes(Context, Base.getType()->getAsCXXRecordDecl(), Size)) return false; } if (!addFieldSizes(Context, RD, Size)) return false; return true; } /// Test whether an argument type which is to be passed indirectly (on the /// stack) would have the equivalent layout if it was expanded into separate /// arguments. If so, we prefer to do the latter to avoid inhibiting /// optimizations. bool X86_32ABIInfo::canExpandIndirectArgument(QualType Ty) const { // We can only expand structure types. const RecordType *RT = Ty->getAs(); if (!RT) return false; const RecordDecl *RD = RT->getDecl(); uint64_t Size = 0; if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { if (!IsWin32StructABI) { // On non-Windows, we have to conservatively match our old bitcode // prototypes in order to be ABI-compatible at the bitcode level. if (!CXXRD->isCLike()) return false; } else { // Don't do this for dynamic classes. if (CXXRD->isDynamicClass()) return false; } if (!addBaseAndFieldSizes(getContext(), CXXRD, Size)) return false; } else { if (!addFieldSizes(getContext(), RD, Size)) return false; } // We can do this if there was no alignment padding. return Size == getContext().getTypeSize(Ty); } ABIArgInfo X86_32ABIInfo::getIndirectReturnResult(QualType RetTy, CCState &State) const { // If the return value is indirect, then the hidden argument is consuming one // integer register. if (State.FreeRegs) { --State.FreeRegs; if (!IsMCUABI) return getNaturalAlignIndirectInReg(RetTy); } return getNaturalAlignIndirect(RetTy, /*ByVal=*/false); } ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, CCState &State) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); const Type *Base = nullptr; uint64_t NumElts = 0; if ((State.CC == llvm::CallingConv::X86_VectorCall || State.CC == llvm::CallingConv::X86_RegCall) && isHomogeneousAggregate(RetTy, Base, NumElts)) { // The LLVM struct type for such an aggregate should lower properly. return ABIArgInfo::getDirect(); } if (const VectorType *VT = RetTy->getAs()) { // On Darwin, some vectors are returned in registers. if (IsDarwinVectorABI) { uint64_t Size = getContext().getTypeSize(RetTy); // 128-bit vectors are a special case; they are returned in // registers and we need to make sure to pick a type the LLVM // backend will like. if (Size == 128) return ABIArgInfo::getDirect(llvm::VectorType::get( llvm::Type::getInt64Ty(getVMContext()), 2)); // Always return in register if it fits in a general purpose // register, or if it is 64 bits and has a single element. if ((Size == 8 || Size == 16 || Size == 32) || (Size == 64 && VT->getNumElements() == 1)) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); return getIndirectReturnResult(RetTy, State); } return ABIArgInfo::getDirect(); } if (isAggregateTypeForABI(RetTy)) { if (const RecordType *RT = RetTy->getAs()) { // Structures with flexible arrays are always indirect. if (RT->getDecl()->hasFlexibleArrayMember()) return getIndirectReturnResult(RetTy, State); } // If specified, structs and unions are always indirect. if (!IsRetSmallStructInRegABI && !RetTy->isAnyComplexType()) return getIndirectReturnResult(RetTy, State); // Ignore empty structs/unions. if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Small structures which are register sized are generally returned // in a register. if (shouldReturnTypeInRegister(RetTy, getContext())) { uint64_t Size = getContext().getTypeSize(RetTy); // As a special-case, if the struct is a "single-element" struct, and // the field is of type "float" or "double", return it in a // floating-point register. (MSVC does not apply this special case.) // We apply a similar transformation for pointer types to improve the // quality of the generated IR. if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) if ((!IsWin32StructABI && SeltTy->isRealFloatingType()) || SeltTy->hasPointerRepresentation()) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); // FIXME: We should be able to narrow this integer in cases with dead // padding. return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),Size)); } return getIndirectReturnResult(RetTy, State); } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } static bool isSSEVectorType(ASTContext &Context, QualType Ty) { return Ty->getAs() && Context.getTypeSize(Ty) == 128; } static bool isRecordWithSSEVectorType(ASTContext &Context, QualType Ty) { const RecordType *RT = Ty->getAs(); if (!RT) return 0; const RecordDecl *RD = RT->getDecl(); // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) for (const auto &I : CXXRD->bases()) if (!isRecordWithSSEVectorType(Context, I.getType())) return false; for (const auto *i : RD->fields()) { QualType FT = i->getType(); if (isSSEVectorType(Context, FT)) return true; if (isRecordWithSSEVectorType(Context, FT)) return true; } return false; } unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty, unsigned Align) const { // Otherwise, if the alignment is less than or equal to the minimum ABI // alignment, just use the default; the backend will handle this. if (Align <= MinABIStackAlignInBytes) return 0; // Use default alignment. // On non-Darwin, the stack type alignment is always 4. if (!IsDarwinVectorABI) { // Set explicit alignment, since we may need to realign the top. return MinABIStackAlignInBytes; } // Otherwise, if the type contains an SSE vector type, the alignment is 16. if (Align >= 16 && (isSSEVectorType(getContext(), Ty) || isRecordWithSSEVectorType(getContext(), Ty))) return 16; return MinABIStackAlignInBytes; } ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal, CCState &State) const { if (!ByVal) { if (State.FreeRegs) { --State.FreeRegs; // Non-byval indirects just use one pointer. if (!IsMCUABI) return getNaturalAlignIndirectInReg(Ty); } return getNaturalAlignIndirect(Ty, false); } // Compute the byval alignment. unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; unsigned StackAlign = getTypeStackAlignInBytes(Ty, TypeAlign); if (StackAlign == 0) return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true); // If the stack alignment is less than the type alignment, realign the // argument. bool Realign = TypeAlign > StackAlign; return ABIArgInfo::getIndirect(CharUnits::fromQuantity(StackAlign), /*ByVal=*/true, Realign); } X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const { const Type *T = isSingleElementStruct(Ty, getContext()); if (!T) T = Ty.getTypePtr(); if (const BuiltinType *BT = T->getAs()) { BuiltinType::Kind K = BT->getKind(); if (K == BuiltinType::Float || K == BuiltinType::Double) return Float; } return Integer; } bool X86_32ABIInfo::updateFreeRegs(QualType Ty, CCState &State) const { if (!IsSoftFloatABI) { Class C = classify(Ty); if (C == Float) return false; } unsigned Size = getContext().getTypeSize(Ty); unsigned SizeInRegs = (Size + 31) / 32; if (SizeInRegs == 0) return false; if (!IsMCUABI) { if (SizeInRegs > State.FreeRegs) { State.FreeRegs = 0; return false; } } else { // The MCU psABI allows passing parameters in-reg even if there are // earlier parameters that are passed on the stack. Also, // it does not allow passing >8-byte structs in-register, // even if there are 3 free registers available. if (SizeInRegs > State.FreeRegs || SizeInRegs > 2) return false; } State.FreeRegs -= SizeInRegs; return true; } bool X86_32ABIInfo::shouldAggregateUseDirect(QualType Ty, CCState &State, bool &InReg, bool &NeedsPadding) const { // On Windows, aggregates other than HFAs are never passed in registers, and // they do not consume register slots. Homogenous floating-point aggregates // (HFAs) have already been dealt with at this point. if (IsWin32StructABI && isAggregateTypeForABI(Ty)) return false; NeedsPadding = false; InReg = !IsMCUABI; if (!updateFreeRegs(Ty, State)) return false; if (IsMCUABI) return true; if (State.CC == llvm::CallingConv::X86_FastCall || State.CC == llvm::CallingConv::X86_VectorCall || State.CC == llvm::CallingConv::X86_RegCall) { if (getContext().getTypeSize(Ty) <= 32 && State.FreeRegs) NeedsPadding = true; return false; } return true; } bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const { if (!updateFreeRegs(Ty, State)) return false; if (IsMCUABI) return false; if (State.CC == llvm::CallingConv::X86_FastCall || State.CC == llvm::CallingConv::X86_VectorCall || State.CC == llvm::CallingConv::X86_RegCall) { if (getContext().getTypeSize(Ty) > 32) return false; return (Ty->isIntegralOrEnumerationType() || Ty->isPointerType() || Ty->isReferenceType()); } return true; } void X86_32ABIInfo::runVectorCallFirstPass(CGFunctionInfo &FI, CCState &State) const { // Vectorcall x86 works subtly different than in x64, so the format is // a bit different than the x64 version. First, all vector types (not HVAs) // are assigned, with the first 6 ending up in the [XYZ]MM0-5 registers. // This differs from the x64 implementation, where the first 6 by INDEX get // registers. // In the second pass over the arguments, HVAs are passed in the remaining // vector registers if possible, or indirectly by address. The address will be // passed in ECX/EDX if available. Any other arguments are passed according to // the usual fastcall rules. MutableArrayRef Args = FI.arguments(); for (int I = 0, E = Args.size(); I < E; ++I) { const Type *Base = nullptr; uint64_t NumElts = 0; const QualType &Ty = Args[I].type; if ((Ty->isVectorType() || Ty->isBuiltinType()) && isHomogeneousAggregate(Ty, Base, NumElts)) { if (State.FreeSSERegs >= NumElts) { State.FreeSSERegs -= NumElts; Args[I].info = ABIArgInfo::getDirect(); State.IsPreassigned.set(I); } } } } ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State) const { // FIXME: Set alignment on indirect arguments. bool IsFastCall = State.CC == llvm::CallingConv::X86_FastCall; bool IsRegCall = State.CC == llvm::CallingConv::X86_RegCall; bool IsVectorCall = State.CC == llvm::CallingConv::X86_VectorCall; Ty = useFirstFieldIfTransparentUnion(Ty); // Check with the C++ ABI first. const RecordType *RT = Ty->getAs(); if (RT) { CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); if (RAA == CGCXXABI::RAA_Indirect) { return getIndirectResult(Ty, false, State); } else if (RAA == CGCXXABI::RAA_DirectInMemory) { // The field index doesn't matter, we'll fix it up later. return ABIArgInfo::getInAlloca(/*FieldIndex=*/0); } } // Regcall uses the concept of a homogenous vector aggregate, similar // to other targets. const Type *Base = nullptr; uint64_t NumElts = 0; if ((IsRegCall || IsVectorCall) && isHomogeneousAggregate(Ty, Base, NumElts)) { if (State.FreeSSERegs >= NumElts) { State.FreeSSERegs -= NumElts; // Vectorcall passes HVAs directly and does not flatten them, but regcall // does. if (IsVectorCall) return getDirectX86Hva(); if (Ty->isBuiltinType() || Ty->isVectorType()) return ABIArgInfo::getDirect(); return ABIArgInfo::getExpand(); } return getIndirectResult(Ty, /*ByVal=*/false, State); } if (isAggregateTypeForABI(Ty)) { // Structures with flexible arrays are always indirect. // FIXME: This should not be byval! if (RT && RT->getDecl()->hasFlexibleArrayMember()) return getIndirectResult(Ty, true, State); // Ignore empty structs/unions on non-Windows. if (!IsWin32StructABI && isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); llvm::LLVMContext &LLVMContext = getVMContext(); llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); bool NeedsPadding = false; bool InReg; if (shouldAggregateUseDirect(Ty, State, InReg, NeedsPadding)) { unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; SmallVector Elements(SizeInRegs, Int32); llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); if (InReg) return ABIArgInfo::getDirectInReg(Result); else return ABIArgInfo::getDirect(Result); } llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : nullptr; // Expand small (<= 128-bit) record types when we know that the stack layout // of those arguments will match the struct. This is important because the // LLVM backend isn't smart enough to remove byval, which inhibits many // optimizations. // Don't do this for the MCU if there are still free integer registers // (see X86_64 ABI for full explanation). if (getContext().getTypeSize(Ty) <= 4 * 32 && (!IsMCUABI || State.FreeRegs == 0) && canExpandIndirectArgument(Ty)) return ABIArgInfo::getExpandWithPadding( IsFastCall || IsVectorCall || IsRegCall, PaddingType); return getIndirectResult(Ty, true, State); } if (const VectorType *VT = Ty->getAs()) { // On Darwin, some vectors are passed in memory, we handle this by passing // it as an i8/i16/i32/i64. if (IsDarwinVectorABI) { uint64_t Size = getContext().getTypeSize(Ty); if ((Size == 8 || Size == 16 || Size == 32) || (Size == 64 && VT->getNumElements() == 1)) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } if (IsX86_MMXType(CGT.ConvertType(Ty))) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), 64)); return ABIArgInfo::getDirect(); } if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); bool InReg = shouldPrimitiveUseInReg(Ty, State); if (Ty->isPromotableIntegerType()) { if (InReg) return ABIArgInfo::getExtendInReg(Ty); return ABIArgInfo::getExtend(Ty); } if (InReg) return ABIArgInfo::getDirectInReg(); return ABIArgInfo::getDirect(); } void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { CCState State(FI); if (IsMCUABI) State.FreeRegs = 3; else if (State.CC == llvm::CallingConv::X86_FastCall) State.FreeRegs = 2; else if (State.CC == llvm::CallingConv::X86_VectorCall) { State.FreeRegs = 2; State.FreeSSERegs = 6; } else if (FI.getHasRegParm()) State.FreeRegs = FI.getRegParm(); else if (State.CC == llvm::CallingConv::X86_RegCall) { State.FreeRegs = 5; State.FreeSSERegs = 8; } else State.FreeRegs = DefaultNumRegisterParameters; if (!::classifyReturnType(getCXXABI(), FI, *this)) { FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), State); } else if (FI.getReturnInfo().isIndirect()) { // The C++ ABI is not aware of register usage, so we have to check if the // return value was sret and put it in a register ourselves if appropriate. if (State.FreeRegs) { --State.FreeRegs; // The sret parameter consumes a register. if (!IsMCUABI) FI.getReturnInfo().setInReg(true); } } // The chain argument effectively gives us another free register. if (FI.isChainCall()) ++State.FreeRegs; // For vectorcall, do a first pass over the arguments, assigning FP and vector // arguments to XMM registers as available. if (State.CC == llvm::CallingConv::X86_VectorCall) runVectorCallFirstPass(FI, State); bool UsedInAlloca = false; MutableArrayRef Args = FI.arguments(); for (int I = 0, E = Args.size(); I < E; ++I) { // Skip arguments that have already been assigned. if (State.IsPreassigned.test(I)) continue; Args[I].info = classifyArgumentType(Args[I].type, State); UsedInAlloca |= (Args[I].info.getKind() == ABIArgInfo::InAlloca); } // If we needed to use inalloca for any argument, do a second pass and rewrite // all the memory arguments to use inalloca. if (UsedInAlloca) rewriteWithInAlloca(FI); } void X86_32ABIInfo::addFieldToArgStruct(SmallVector &FrameFields, CharUnits &StackOffset, ABIArgInfo &Info, QualType Type) const { // Arguments are always 4-byte-aligned. CharUnits FieldAlign = CharUnits::fromQuantity(4); assert(StackOffset.isMultipleOf(FieldAlign) && "unaligned inalloca struct"); Info = ABIArgInfo::getInAlloca(FrameFields.size()); FrameFields.push_back(CGT.ConvertTypeForMem(Type)); StackOffset += getContext().getTypeSizeInChars(Type); // Insert padding bytes to respect alignment. CharUnits FieldEnd = StackOffset; StackOffset = FieldEnd.alignTo(FieldAlign); if (StackOffset != FieldEnd) { CharUnits NumBytes = StackOffset - FieldEnd; llvm::Type *Ty = llvm::Type::getInt8Ty(getVMContext()); Ty = llvm::ArrayType::get(Ty, NumBytes.getQuantity()); FrameFields.push_back(Ty); } } static bool isArgInAlloca(const ABIArgInfo &Info) { // Leave ignored and inreg arguments alone. switch (Info.getKind()) { case ABIArgInfo::InAlloca: return true; case ABIArgInfo::Indirect: assert(Info.getIndirectByVal()); return true; case ABIArgInfo::Ignore: return false; case ABIArgInfo::Direct: case ABIArgInfo::Extend: if (Info.getInReg()) return false; return true; case ABIArgInfo::Expand: case ABIArgInfo::CoerceAndExpand: // These are aggregate types which are never passed in registers when // inalloca is involved. return true; } llvm_unreachable("invalid enum"); } void X86_32ABIInfo::rewriteWithInAlloca(CGFunctionInfo &FI) const { assert(IsWin32StructABI && "inalloca only supported on win32"); // Build a packed struct type for all of the arguments in memory. SmallVector FrameFields; // The stack alignment is always 4. CharUnits StackAlign = CharUnits::fromQuantity(4); CharUnits StackOffset; CGFunctionInfo::arg_iterator I = FI.arg_begin(), E = FI.arg_end(); // Put 'this' into the struct before 'sret', if necessary. bool IsThisCall = FI.getCallingConvention() == llvm::CallingConv::X86_ThisCall; ABIArgInfo &Ret = FI.getReturnInfo(); if (Ret.isIndirect() && Ret.isSRetAfterThis() && !IsThisCall && isArgInAlloca(I->info)) { addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type); ++I; } // Put the sret parameter into the inalloca struct if it's in memory. if (Ret.isIndirect() && !Ret.getInReg()) { CanQualType PtrTy = getContext().getPointerType(FI.getReturnType()); addFieldToArgStruct(FrameFields, StackOffset, Ret, PtrTy); // On Windows, the hidden sret parameter is always returned in eax. Ret.setInAllocaSRet(IsWin32StructABI); } // Skip the 'this' parameter in ecx. if (IsThisCall) ++I; // Put arguments passed in memory into the struct. for (; I != E; ++I) { if (isArgInAlloca(I->info)) addFieldToArgStruct(FrameFields, StackOffset, I->info, I->type); } FI.setArgStruct(llvm::StructType::get(getVMContext(), FrameFields, /*isPacked=*/true), StackAlign); } Address X86_32ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { auto TypeInfo = getContext().getTypeInfoInChars(Ty); // x86-32 changes the alignment of certain arguments on the stack. // // Just messing with TypeInfo like this works because we never pass // anything indirectly. TypeInfo.second = CharUnits::fromQuantity( getTypeStackAlignInBytes(Ty, TypeInfo.second.getQuantity())); return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo, CharUnits::fromQuantity(4), /*AllowHigherAlign*/ true); } bool X86_32TargetCodeGenInfo::isStructReturnInRegABI( const llvm::Triple &Triple, const CodeGenOptions &Opts) { assert(Triple.getArch() == llvm::Triple::x86); switch (Opts.getStructReturnConvention()) { case CodeGenOptions::SRCK_Default: break; case CodeGenOptions::SRCK_OnStack: // -fpcc-struct-return return false; case CodeGenOptions::SRCK_InRegs: // -freg-struct-return return true; } if (Triple.isOSDarwin() || Triple.isOSIAMCU()) return true; switch (Triple.getOS()) { case llvm::Triple::DragonFly: case llvm::Triple::FreeBSD: case llvm::Triple::OpenBSD: case llvm::Triple::Win32: return true; default: return false; } } void X86_32TargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { if (GV->isDeclaration()) return; if (const FunctionDecl *FD = dyn_cast_or_null(D)) { if (FD->hasAttr()) { llvm::Function *Fn = cast(GV); Fn->addFnAttr("stackrealign"); } if (FD->hasAttr()) { llvm::Function *Fn = cast(GV); Fn->setCallingConv(llvm::CallingConv::X86_INTR); } } } bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable( CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4); // 0-7 are the eight integer registers; the order is different // on Darwin (for EH), but the range is the same. // 8 is %eip. AssignToArrayRange(Builder, Address, Four8, 0, 8); if (CGF.CGM.getTarget().getTriple().isOSDarwin()) { // 12-16 are st(0..4). Not sure why we stop at 4. // These have size 16, which is sizeof(long double) on // platforms with 8-byte alignment for that type. llvm::Value *Sixteen8 = llvm::ConstantInt::get(CGF.Int8Ty, 16); AssignToArrayRange(Builder, Address, Sixteen8, 12, 16); } else { // 9 is %eflags, which doesn't get a size on Darwin for some // reason. Builder.CreateAlignedStore( Four8, Builder.CreateConstInBoundsGEP1_32(CGF.Int8Ty, Address, 9), CharUnits::One()); // 11-16 are st(0..5). Not sure why we stop at 5. // These have size 12, which is sizeof(long double) on // platforms with 4-byte alignment for that type. llvm::Value *Twelve8 = llvm::ConstantInt::get(CGF.Int8Ty, 12); AssignToArrayRange(Builder, Address, Twelve8, 11, 16); } return false; } //===----------------------------------------------------------------------===// // X86-64 ABI Implementation //===----------------------------------------------------------------------===// namespace { /// The AVX ABI level for X86 targets. enum class X86AVXABILevel { None, AVX, AVX512 }; /// \p returns the size in bits of the largest (native) vector for \p AVXLevel. static unsigned getNativeVectorSizeForAVXABI(X86AVXABILevel AVXLevel) { switch (AVXLevel) { case X86AVXABILevel::AVX512: return 512; case X86AVXABILevel::AVX: return 256; case X86AVXABILevel::None: return 128; } llvm_unreachable("Unknown AVXLevel"); } /// X86_64ABIInfo - The X86_64 ABI information. class X86_64ABIInfo : public SwiftABIInfo { enum Class { Integer = 0, SSE, SSEUp, X87, X87Up, ComplexX87, NoClass, Memory }; /// merge - Implement the X86_64 ABI merging algorithm. /// /// Merge an accumulating classification \arg Accum with a field /// classification \arg Field. /// /// \param Accum - The accumulating classification. This should /// always be either NoClass or the result of a previous merge /// call. In addition, this should never be Memory (the caller /// should just return Memory for the aggregate). static Class merge(Class Accum, Class Field); /// postMerge - Implement the X86_64 ABI post merging algorithm. /// /// Post merger cleanup, reduces a malformed Hi and Lo pair to /// final MEMORY or SSE classes when necessary. /// /// \param AggregateSize - The size of the current aggregate in /// the classification process. /// /// \param Lo - The classification for the parts of the type /// residing in the low word of the containing object. /// /// \param Hi - The classification for the parts of the type /// residing in the higher words of the containing object. /// void postMerge(unsigned AggregateSize, Class &Lo, Class &Hi) const; /// classify - Determine the x86_64 register classes in which the /// given type T should be passed. /// /// \param Lo - The classification for the parts of the type /// residing in the low word of the containing object. /// /// \param Hi - The classification for the parts of the type /// residing in the high word of the containing object. /// /// \param OffsetBase - The bit offset of this type in the /// containing object. Some parameters are classified different /// depending on whether they straddle an eightbyte boundary. /// /// \param isNamedArg - Whether the argument in question is a "named" /// argument, as used in AMD64-ABI 3.5.7. /// /// If a word is unused its result will be NoClass; if a type should /// be passed in Memory then at least the classification of \arg Lo /// will be Memory. /// /// The \arg Lo class will be NoClass iff the argument is ignored. /// /// If the \arg Lo class is ComplexX87, then the \arg Hi class will /// also be ComplexX87. void classify(QualType T, uint64_t OffsetBase, Class &Lo, Class &Hi, bool isNamedArg) const; llvm::Type *GetByteVectorType(QualType Ty) const; llvm::Type *GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const; llvm::Type *GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be returned in memory. ABIArgInfo getIndirectReturnResult(QualType Ty) const; /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. /// /// \param freeIntRegs - The number of free integer registers remaining /// available. ABIArgInfo getIndirectResult(QualType Ty, unsigned freeIntRegs) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty, unsigned freeIntRegs, unsigned &neededInt, unsigned &neededSSE, bool isNamedArg) const; ABIArgInfo classifyRegCallStructType(QualType Ty, unsigned &NeededInt, unsigned &NeededSSE) const; ABIArgInfo classifyRegCallStructTypeImpl(QualType Ty, unsigned &NeededInt, unsigned &NeededSSE) const; bool IsIllegalVectorType(QualType Ty) const; /// The 0.98 ABI revision clarified a lot of ambiguities, /// unfortunately in ways that were not always consistent with /// certain previous compilers. In particular, platforms which /// required strict binary compatibility with older versions of GCC /// may need to exempt themselves. bool honorsRevision0_98() const { return !getTarget().getTriple().isOSDarwin(); } /// GCC classifies <1 x long long> as SSE but some platform ABIs choose to /// classify it as INTEGER (for compatibility with older clang compilers). bool classifyIntegerMMXAsSSE() const { // Clang <= 3.8 did not do this. if (getContext().getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver3_8) return false; const llvm::Triple &Triple = getTarget().getTriple(); if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::PS4) return false; if (Triple.isOSFreeBSD() && Triple.getOSMajorVersion() >= 10) return false; return true; } // GCC classifies vectors of __int128 as memory. bool passInt128VectorsInMem() const { // Clang <= 9.0 did not do this. if (getContext().getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver9) return false; const llvm::Triple &T = getTarget().getTriple(); return T.isOSLinux() || T.isOSNetBSD(); } X86AVXABILevel AVXLevel; // Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on // 64-bit hardware. bool Has64BitPointers; public: X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) : SwiftABIInfo(CGT), AVXLevel(AVXLevel), Has64BitPointers(CGT.getDataLayout().getPointerSize(0) == 8) { } bool isPassedUsingAVXType(QualType type) const { unsigned neededInt, neededSSE; // The freeIntRegs argument doesn't matter here. ABIArgInfo info = classifyArgumentType(type, 0, neededInt, neededSSE, /*isNamedArg*/true); if (info.isDirect()) { llvm::Type *ty = info.getCoerceToType(); if (llvm::VectorType *vectorTy = dyn_cast_or_null(ty)) return (vectorTy->getBitWidth() > 128); } return false; } void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool has64BitPointers() const { return Has64BitPointers; } bool shouldPassIndirectlyForSwift(ArrayRef scalars, bool asReturnValue) const override { return occupiesMoreThan(CGT, scalars, /*total*/ 4); } bool isSwiftErrorInRegister() const override { return true; } }; /// WinX86_64ABIInfo - The Windows X86_64 ABI information. class WinX86_64ABIInfo : public SwiftABIInfo { public: WinX86_64ABIInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) : SwiftABIInfo(CGT), AVXLevel(AVXLevel), IsMingw64(getTarget().getTriple().isWindowsGNUEnvironment()) {} void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool isHomogeneousAggregateBaseType(QualType Ty) const override { // FIXME: Assumes vectorcall is in use. return isX86VectorTypeForVectorCall(getContext(), Ty); } bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t NumMembers) const override { // FIXME: Assumes vectorcall is in use. return isX86VectorCallAggregateSmallEnough(NumMembers); } bool shouldPassIndirectlyForSwift(ArrayRef scalars, bool asReturnValue) const override { return occupiesMoreThan(CGT, scalars, /*total*/ 4); } bool isSwiftErrorInRegister() const override { return true; } private: ABIArgInfo classify(QualType Ty, unsigned &FreeSSERegs, bool IsReturnType, bool IsVectorCall, bool IsRegCall) const; ABIArgInfo reclassifyHvaArgType(QualType Ty, unsigned &FreeSSERegs, const ABIArgInfo ¤t) const; void computeVectorCallArgs(CGFunctionInfo &FI, unsigned FreeSSERegs, bool IsVectorCall, bool IsRegCall) const; X86AVXABILevel AVXLevel; bool IsMingw64; }; class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) : TargetCodeGenInfo(new X86_64ABIInfo(CGT, AVXLevel)) {} const X86_64ABIInfo &getABIInfo() const { return static_cast(TargetCodeGenInfo::getABIInfo()); } /// Disable tail call on x86-64. The epilogue code before the tail jump blocks /// the autoreleaseRV/retainRV optimization. bool shouldSuppressTailCallsOfRetainAutoreleasedReturnValue() const override { return true; } int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { return 7; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override { llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8); // 0-15 are the 16 integer registers. // 16 is %rip. AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16); return false; } llvm::Type* adjustInlineAsmType(CodeGen::CodeGenFunction &CGF, StringRef Constraint, llvm::Type* Ty) const override { return X86AdjustInlineAsmType(CGF, Constraint, Ty); } bool isNoProtoCallVariadic(const CallArgList &args, const FunctionNoProtoType *fnType) const override { // The default CC on x86-64 sets %al to the number of SSA // registers used, and GCC sets this when calling an unprototyped // function, so we override the default behavior. However, don't do // that when AVX types are involved: the ABI explicitly states it is // undefined, and it doesn't work in practice because of how the ABI // defines varargs anyway. if (fnType->getCallConv() == CC_C) { bool HasAVXType = false; for (CallArgList::const_iterator it = args.begin(), ie = args.end(); it != ie; ++it) { if (getABIInfo().isPassedUsingAVXType(it->Ty)) { HasAVXType = true; break; } } if (!HasAVXType) return true; } return TargetCodeGenInfo::isNoProtoCallVariadic(args, fnType); } llvm::Constant * getUBSanFunctionSignature(CodeGen::CodeGenModule &CGM) const override { unsigned Sig = (0xeb << 0) | // jmp rel8 (0x06 << 8) | // .+0x08 ('v' << 16) | ('2' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { if (GV->isDeclaration()) return; if (const FunctionDecl *FD = dyn_cast_or_null(D)) { if (FD->hasAttr()) { llvm::Function *Fn = cast(GV); Fn->addFnAttr("stackrealign"); } if (FD->hasAttr()) { llvm::Function *Fn = cast(GV); Fn->setCallingConv(llvm::CallingConv::X86_INTR); } } } }; static std::string qualifyWindowsLibrary(llvm::StringRef Lib) { // If the argument does not end in .lib, automatically add the suffix. // If the argument contains a space, enclose it in quotes. // This matches the behavior of MSVC. bool Quote = (Lib.find(" ") != StringRef::npos); std::string ArgStr = Quote ? "\"" : ""; ArgStr += Lib; if (!Lib.endswith_lower(".lib") && !Lib.endswith_lower(".a")) ArgStr += ".lib"; ArgStr += Quote ? "\"" : ""; return ArgStr; } class WinX86_32TargetCodeGenInfo : public X86_32TargetCodeGenInfo { public: WinX86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool DarwinVectorABI, bool RetSmallStructInRegABI, bool Win32StructABI, unsigned NumRegisterParameters) : X86_32TargetCodeGenInfo(CGT, DarwinVectorABI, RetSmallStructInRegABI, Win32StructABI, NumRegisterParameters, false) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { Opt = "/DEFAULTLIB:"; Opt += qualifyWindowsLibrary(Lib); } void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, llvm::SmallString<32> &Opt) const override { Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; } }; static void addStackProbeTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) { if (llvm::Function *Fn = dyn_cast_or_null(GV)) { if (CGM.getCodeGenOpts().StackProbeSize != 4096) Fn->addFnAttr("stack-probe-size", llvm::utostr(CGM.getCodeGenOpts().StackProbeSize)); if (CGM.getCodeGenOpts().NoStackArgProbe) Fn->addFnAttr("no-stack-arg-probe"); } } void WinX86_32TargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { X86_32TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); if (GV->isDeclaration()) return; addStackProbeTargetAttributes(D, GV, CGM); } class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT, AVXLevel)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { return 7; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override { llvm::Value *Eight8 = llvm::ConstantInt::get(CGF.Int8Ty, 8); // 0-15 are the 16 integer registers. // 16 is %rip. AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16); return false; } void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { Opt = "/DEFAULTLIB:"; Opt += qualifyWindowsLibrary(Lib); } void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, llvm::SmallString<32> &Opt) const override { Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; } }; void WinX86_64TargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); if (GV->isDeclaration()) return; if (const FunctionDecl *FD = dyn_cast_or_null(D)) { if (FD->hasAttr()) { llvm::Function *Fn = cast(GV); Fn->addFnAttr("stackrealign"); } if (FD->hasAttr()) { llvm::Function *Fn = cast(GV); Fn->setCallingConv(llvm::CallingConv::X86_INTR); } } addStackProbeTargetAttributes(D, GV, CGM); } } void X86_64ABIInfo::postMerge(unsigned AggregateSize, Class &Lo, Class &Hi) const { // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done: // // (a) If one of the classes is Memory, the whole argument is passed in // memory. // // (b) If X87UP is not preceded by X87, the whole argument is passed in // memory. // // (c) If the size of the aggregate exceeds two eightbytes and the first // eightbyte isn't SSE or any other eightbyte isn't SSEUP, the whole // argument is passed in memory. NOTE: This is necessary to keep the // ABI working for processors that don't support the __m256 type. // // (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE. // // Some of these are enforced by the merging logic. Others can arise // only with unions; for example: // union { _Complex double; unsigned; } // // Note that clauses (b) and (c) were added in 0.98. // if (Hi == Memory) Lo = Memory; if (Hi == X87Up && Lo != X87 && honorsRevision0_98()) Lo = Memory; if (AggregateSize > 128 && (Lo != SSE || Hi != SSEUp)) Lo = Memory; if (Hi == SSEUp && Lo != SSE) Hi = SSE; } X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, Class Field) { // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is // classified recursively so that always two fields are // considered. The resulting class is calculated according to // the classes of the fields in the eightbyte: // // (a) If both classes are equal, this is the resulting class. // // (b) If one of the classes is NO_CLASS, the resulting class is // the other class. // // (c) If one of the classes is MEMORY, the result is the MEMORY // class. // // (d) If one of the classes is INTEGER, the result is the // INTEGER. // // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class, // MEMORY is used as class. // // (f) Otherwise class SSE is used. // Accum should never be memory (we should have returned) or // ComplexX87 (because this cannot be passed in a structure). assert((Accum != Memory && Accum != ComplexX87) && "Invalid accumulated classification during merge."); if (Accum == Field || Field == NoClass) return Accum; if (Field == Memory) return Memory; if (Accum == NoClass) return Field; if (Accum == Integer || Field == Integer) return Integer; if (Field == X87 || Field == X87Up || Field == ComplexX87 || Accum == X87 || Accum == X87Up) return Memory; return SSE; } void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo, Class &Hi, bool isNamedArg) const { // FIXME: This code can be simplified by introducing a simple value class for // Class pairs with appropriate constructor methods for the various // situations. // FIXME: Some of the split computations are wrong; unaligned vectors // shouldn't be passed in registers for example, so there is no chance they // can straddle an eightbyte. Verify & simplify. Lo = Hi = NoClass; Class &Current = OffsetBase < 64 ? Lo : Hi; Current = Memory; if (const BuiltinType *BT = Ty->getAs()) { BuiltinType::Kind k = BT->getKind(); if (k == BuiltinType::Void) { Current = NoClass; } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) { Lo = Integer; Hi = Integer; } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { Current = Integer; } else if (k == BuiltinType::Float || k == BuiltinType::Double) { Current = SSE; } else if (k == BuiltinType::LongDouble) { const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); if (LDF == &llvm::APFloat::IEEEquad()) { Lo = SSE; Hi = SSEUp; } else if (LDF == &llvm::APFloat::x87DoubleExtended()) { Lo = X87; Hi = X87Up; } else if (LDF == &llvm::APFloat::IEEEdouble()) { Current = SSE; } else llvm_unreachable("unexpected long double representation!"); } // FIXME: _Decimal32 and _Decimal64 are SSE. // FIXME: _float128 and _Decimal128 are (SSE, SSEUp). return; } if (const EnumType *ET = Ty->getAs()) { // Classify the underlying integer type. classify(ET->getDecl()->getIntegerType(), OffsetBase, Lo, Hi, isNamedArg); return; } if (Ty->hasPointerRepresentation()) { Current = Integer; return; } if (Ty->isMemberPointerType()) { if (Ty->isMemberFunctionPointerType()) { if (Has64BitPointers) { // If Has64BitPointers, this is an {i64, i64}, so classify both // Lo and Hi now. Lo = Hi = Integer; } else { // Otherwise, with 32-bit pointers, this is an {i32, i32}. If that // straddles an eightbyte boundary, Hi should be classified as well. uint64_t EB_FuncPtr = (OffsetBase) / 64; uint64_t EB_ThisAdj = (OffsetBase + 64 - 1) / 64; if (EB_FuncPtr != EB_ThisAdj) { Lo = Hi = Integer; } else { Current = Integer; } } } else { Current = Integer; } return; } if (const VectorType *VT = Ty->getAs()) { uint64_t Size = getContext().getTypeSize(VT); if (Size == 1 || Size == 8 || Size == 16 || Size == 32) { // gcc passes the following as integer: // 4 bytes - <4 x char>, <2 x short>, <1 x int>, <1 x float> // 2 bytes - <2 x char>, <1 x short> // 1 byte - <1 x char> Current = Integer; // If this type crosses an eightbyte boundary, it should be // split. uint64_t EB_Lo = (OffsetBase) / 64; uint64_t EB_Hi = (OffsetBase + Size - 1) / 64; if (EB_Lo != EB_Hi) Hi = Lo; } else if (Size == 64) { QualType ElementType = VT->getElementType(); // gcc passes <1 x double> in memory. :( if (ElementType->isSpecificBuiltinType(BuiltinType::Double)) return; // gcc passes <1 x long long> as SSE but clang used to unconditionally // pass them as integer. For platforms where clang is the de facto // platform compiler, we must continue to use integer. if (!classifyIntegerMMXAsSSE() && (ElementType->isSpecificBuiltinType(BuiltinType::LongLong) || ElementType->isSpecificBuiltinType(BuiltinType::ULongLong) || ElementType->isSpecificBuiltinType(BuiltinType::Long) || ElementType->isSpecificBuiltinType(BuiltinType::ULong))) Current = Integer; else Current = SSE; // If this type crosses an eightbyte boundary, it should be // split. if (OffsetBase && OffsetBase != 64) Hi = Lo; } else if (Size == 128 || (isNamedArg && Size <= getNativeVectorSizeForAVXABI(AVXLevel))) { QualType ElementType = VT->getElementType(); // gcc passes 256 and 512 bit vectors in memory. :( if (passInt128VectorsInMem() && Size != 128 && (ElementType->isSpecificBuiltinType(BuiltinType::Int128) || ElementType->isSpecificBuiltinType(BuiltinType::UInt128))) return; // Arguments of 256-bits are split into four eightbyte chunks. The // least significant one belongs to class SSE and all the others to class // SSEUP. The original Lo and Hi design considers that types can't be // greater than 128-bits, so a 64-bit split in Hi and Lo makes sense. // This design isn't correct for 256-bits, but since there're no cases // where the upper parts would need to be inspected, avoid adding // complexity and just consider Hi to match the 64-256 part. // // Note that per 3.5.7 of AMD64-ABI, 256-bit args are only passed in // registers if they are "named", i.e. not part of the "..." of a // variadic function. // // Similarly, per 3.2.3. of the AVX512 draft, 512-bits ("named") args are // split into eight eightbyte chunks, one SSE and seven SSEUP. Lo = SSE; Hi = SSEUp; } return; } if (const ComplexType *CT = Ty->getAs()) { QualType ET = getContext().getCanonicalType(CT->getElementType()); uint64_t Size = getContext().getTypeSize(Ty); if (ET->isIntegralOrEnumerationType()) { if (Size <= 64) Current = Integer; else if (Size <= 128) Lo = Hi = Integer; } else if (ET == getContext().FloatTy) { Current = SSE; } else if (ET == getContext().DoubleTy) { Lo = Hi = SSE; } else if (ET == getContext().LongDoubleTy) { const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); if (LDF == &llvm::APFloat::IEEEquad()) Current = Memory; else if (LDF == &llvm::APFloat::x87DoubleExtended()) Current = ComplexX87; else if (LDF == &llvm::APFloat::IEEEdouble()) Lo = Hi = SSE; else llvm_unreachable("unexpected long double representation!"); } // If this complex type crosses an eightbyte boundary then it // should be split. uint64_t EB_Real = (OffsetBase) / 64; uint64_t EB_Imag = (OffsetBase + getContext().getTypeSize(ET)) / 64; if (Hi == NoClass && EB_Real != EB_Imag) Hi = Lo; return; } if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { // Arrays are treated like structures. uint64_t Size = getContext().getTypeSize(Ty); // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger // than eight eightbytes, ..., it has class MEMORY. if (Size > 512) return; // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned // fields, it has class MEMORY. // // Only need to check alignment of array base. if (OffsetBase % getContext().getTypeAlign(AT->getElementType())) return; // Otherwise implement simplified merge. We could be smarter about // this, but it isn't worth it and would be harder to verify. Current = NoClass; uint64_t EltSize = getContext().getTypeSize(AT->getElementType()); uint64_t ArraySize = AT->getSize().getZExtValue(); // The only case a 256-bit wide vector could be used is when the array // contains a single 256-bit element. Since Lo and Hi logic isn't extended // to work for sizes wider than 128, early check and fallback to memory. // if (Size > 128 && (Size != EltSize || Size > getNativeVectorSizeForAVXABI(AVXLevel))) return; for (uint64_t i=0, Offset=OffsetBase; igetElementType(), Offset, FieldLo, FieldHi, isNamedArg); Lo = merge(Lo, FieldLo); Hi = merge(Hi, FieldHi); if (Lo == Memory || Hi == Memory) break; } postMerge(Size, Lo, Hi); assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification."); return; } if (const RecordType *RT = Ty->getAs()) { uint64_t Size = getContext().getTypeSize(Ty); // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger // than eight eightbytes, ..., it has class MEMORY. if (Size > 512) return; // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial // copy constructor or a non-trivial destructor, it is passed by invisible // reference. if (getRecordArgABI(RT, getCXXABI())) return; const RecordDecl *RD = RT->getDecl(); // Assume variable sized types are passed in memory. if (RD->hasFlexibleArrayMember()) return; const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); // Reset Lo class, this will be recomputed. Current = NoClass; // If this is a C++ record, classify the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) { assert(!I.isVirtual() && !I.getType()->isDependentType() && "Unexpected base class!"); const auto *Base = cast(I.getType()->castAs()->getDecl()); // Classify this field. // // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a // single eightbyte, each is classified separately. Each eightbyte gets // initialized to class NO_CLASS. Class FieldLo, FieldHi; uint64_t Offset = OffsetBase + getContext().toBits(Layout.getBaseClassOffset(Base)); classify(I.getType(), Offset, FieldLo, FieldHi, isNamedArg); Lo = merge(Lo, FieldLo); Hi = merge(Hi, FieldHi); if (Lo == Memory || Hi == Memory) { postMerge(Size, Lo, Hi); return; } } } // Classify the fields one at a time, merging the results. unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); bool BitField = i->isBitField(); // Ignore padding bit-fields. if (BitField && i->isUnnamedBitfield()) continue; // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger than // four eightbytes, or it contains unaligned fields, it has class MEMORY. // // The only case a 256-bit wide vector could be used is when the struct // contains a single 256-bit element. Since Lo and Hi logic isn't extended // to work for sizes wider than 128, early check and fallback to memory. // if (Size > 128 && (Size != getContext().getTypeSize(i->getType()) || Size > getNativeVectorSizeForAVXABI(AVXLevel))) { Lo = Memory; postMerge(Size, Lo, Hi); return; } // Note, skip this test for bit-fields, see below. if (!BitField && Offset % getContext().getTypeAlign(i->getType())) { Lo = Memory; postMerge(Size, Lo, Hi); return; } // Classify this field. // // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate // exceeds a single eightbyte, each is classified // separately. Each eightbyte gets initialized to class // NO_CLASS. Class FieldLo, FieldHi; // Bit-fields require special handling, they do not force the // structure to be passed in memory even if unaligned, and // therefore they can straddle an eightbyte. if (BitField) { assert(!i->isUnnamedBitfield()); uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx); uint64_t Size = i->getBitWidthValue(getContext()); uint64_t EB_Lo = Offset / 64; uint64_t EB_Hi = (Offset + Size - 1) / 64; if (EB_Lo) { assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes."); FieldLo = NoClass; FieldHi = Integer; } else { FieldLo = Integer; FieldHi = EB_Hi ? Integer : NoClass; } } else classify(i->getType(), Offset, FieldLo, FieldHi, isNamedArg); Lo = merge(Lo, FieldLo); Hi = merge(Hi, FieldHi); if (Lo == Memory || Hi == Memory) break; } postMerge(Size, Lo, Hi); } } ABIArgInfo X86_64ABIInfo::getIndirectReturnResult(QualType Ty) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right // place naturally. if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } return getNaturalAlignIndirect(Ty); } bool X86_64ABIInfo::IsIllegalVectorType(QualType Ty) const { if (const VectorType *VecTy = Ty->getAs()) { uint64_t Size = getContext().getTypeSize(VecTy); unsigned LargestVector = getNativeVectorSizeForAVXABI(AVXLevel); if (Size <= 64 || Size > LargestVector) return true; QualType EltTy = VecTy->getElementType(); if (passInt128VectorsInMem() && (EltTy->isSpecificBuiltinType(BuiltinType::Int128) || EltTy->isSpecificBuiltinType(BuiltinType::UInt128))) return true; } return false; } ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty, unsigned freeIntRegs) const { // If this is a scalar LLVM value then assume LLVM will pass it in the right // place naturally. // // This assumption is optimistic, as there could be free registers available // when we need to pass this argument in memory, and LLVM could try to pass // the argument in the free register. This does not seem to happen currently, // but this code would be much safer if we could mark the argument with // 'onstack'. See PR12193. if (!isAggregateTypeForABI(Ty) && !IsIllegalVectorType(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Compute the byval alignment. We specify the alignment of the byval in all // cases so that the mid-level optimizer knows the alignment of the byval. unsigned Align = std::max(getContext().getTypeAlign(Ty) / 8, 8U); // Attempt to avoid passing indirect results using byval when possible. This // is important for good codegen. // // We do this by coercing the value into a scalar type which the backend can // handle naturally (i.e., without using byval). // // For simplicity, we currently only do this when we have exhausted all of the // free integer registers. Doing this when there are free integer registers // would require more care, as we would have to ensure that the coerced value // did not claim the unused register. That would require either reording the // arguments to the function (so that any subsequent inreg values came first), // or only doing this optimization when there were no following arguments that // might be inreg. // // We currently expect it to be rare (particularly in well written code) for // arguments to be passed on the stack when there are still free integer // registers available (this would typically imply large structs being passed // by value), so this seems like a fair tradeoff for now. // // We can revisit this if the backend grows support for 'onstack' parameter // attributes. See PR12193. if (freeIntRegs == 0) { uint64_t Size = getContext().getTypeSize(Ty); // If this type fits in an eightbyte, coerce it into the matching integral // type, which will end up on the stack (with alignment 8). if (Align == 8 && Size <= 64) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } return ABIArgInfo::getIndirect(CharUnits::fromQuantity(Align)); } /// The ABI specifies that a value should be passed in a full vector XMM/YMM /// register. Pick an LLVM IR type that will be passed as a vector register. llvm::Type *X86_64ABIInfo::GetByteVectorType(QualType Ty) const { // Wrapper structs/arrays that only contain vectors are passed just like // vectors; strip them off if present. if (const Type *InnerTy = isSingleElementStruct(Ty, getContext())) Ty = QualType(InnerTy, 0); llvm::Type *IRType = CGT.ConvertType(Ty); if (isa(IRType)) { // Don't pass vXi128 vectors in their native type, the backend can't // legalize them. if (passInt128VectorsInMem() && IRType->getVectorElementType()->isIntegerTy(128)) { // Use a vXi64 vector. uint64_t Size = getContext().getTypeSize(Ty); return llvm::VectorType::get(llvm::Type::getInt64Ty(getVMContext()), Size / 64); } return IRType; } if (IRType->getTypeID() == llvm::Type::FP128TyID) return IRType; // We couldn't find the preferred IR vector type for 'Ty'. uint64_t Size = getContext().getTypeSize(Ty); assert((Size == 128 || Size == 256 || Size == 512) && "Invalid type found!"); // Return a LLVM IR vector type based on the size of 'Ty'. return llvm::VectorType::get(llvm::Type::getDoubleTy(getVMContext()), Size / 64); } /// BitsContainNoUserData - Return true if the specified [start,end) bit range /// is known to either be off the end of the specified type or being in /// alignment padding. The user type specified is known to be at most 128 bits /// in size, and have passed through X86_64ABIInfo::classify with a successful /// classification that put one of the two halves in the INTEGER class. /// /// It is conservatively correct to return false. static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, unsigned EndBit, ASTContext &Context) { // If the bytes being queried are off the end of the type, there is no user // data hiding here. This handles analysis of builtins, vectors and other // types that don't contain interesting padding. unsigned TySize = (unsigned)Context.getTypeSize(Ty); if (TySize <= StartBit) return true; if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { unsigned EltSize = (unsigned)Context.getTypeSize(AT->getElementType()); unsigned NumElts = (unsigned)AT->getSize().getZExtValue(); // Check each element to see if the element overlaps with the queried range. for (unsigned i = 0; i != NumElts; ++i) { // If the element is after the span we care about, then we're done.. unsigned EltOffset = i*EltSize; if (EltOffset >= EndBit) break; unsigned EltStart = EltOffset < StartBit ? StartBit-EltOffset :0; if (!BitsContainNoUserData(AT->getElementType(), EltStart, EndBit-EltOffset, Context)) return false; } // If it overlaps no elements, then it is safe to process as padding. return true; } if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) { assert(!I.isVirtual() && !I.getType()->isDependentType() && "Unexpected base class!"); const auto *Base = cast(I.getType()->castAs()->getDecl()); // If the base is after the span we care about, ignore it. unsigned BaseOffset = Context.toBits(Layout.getBaseClassOffset(Base)); if (BaseOffset >= EndBit) continue; unsigned BaseStart = BaseOffset < StartBit ? StartBit-BaseOffset :0; if (!BitsContainNoUserData(I.getType(), BaseStart, EndBit-BaseOffset, Context)) return false; } } // Verify that no field has data that overlaps the region of interest. Yes // this could be sped up a lot by being smarter about queried fields, // however we're only looking at structs up to 16 bytes, so we don't care // much. unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { unsigned FieldOffset = (unsigned)Layout.getFieldOffset(idx); // If we found a field after the region we care about, then we're done. if (FieldOffset >= EndBit) break; unsigned FieldStart = FieldOffset < StartBit ? StartBit-FieldOffset :0; if (!BitsContainNoUserData(i->getType(), FieldStart, EndBit-FieldOffset, Context)) return false; } // If nothing in this record overlapped the area of interest, then we're // clean. return true; } return false; } /// ContainsFloatAtOffset - Return true if the specified LLVM IR type has a /// float member at the specified offset. For example, {int,{float}} has a /// float at offset 4. It is conservatively correct for this routine to return /// false. static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset, const llvm::DataLayout &TD) { // Base case if we find a float. if (IROffset == 0 && IRType->isFloatTy()) return true; // If this is a struct, recurse into the field at the specified offset. if (llvm::StructType *STy = dyn_cast(IRType)) { const llvm::StructLayout *SL = TD.getStructLayout(STy); unsigned Elt = SL->getElementContainingOffset(IROffset); IROffset -= SL->getElementOffset(Elt); return ContainsFloatAtOffset(STy->getElementType(Elt), IROffset, TD); } // If this is an array, recurse into the field at the specified offset. if (llvm::ArrayType *ATy = dyn_cast(IRType)) { llvm::Type *EltTy = ATy->getElementType(); unsigned EltSize = TD.getTypeAllocSize(EltTy); IROffset -= IROffset/EltSize*EltSize; return ContainsFloatAtOffset(EltTy, IROffset, TD); } return false; } /// GetSSETypeAtOffset - Return a type that will be passed by the backend in the /// low 8 bytes of an XMM register, corresponding to the SSE class. llvm::Type *X86_64ABIInfo:: GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const { // The only three choices we have are either double, <2 x float>, or float. We // pass as float if the last 4 bytes is just padding. This happens for // structs that contain 3 floats. if (BitsContainNoUserData(SourceTy, SourceOffset*8+32, SourceOffset*8+64, getContext())) return llvm::Type::getFloatTy(getVMContext()); // We want to pass as <2 x float> if the LLVM IR type contains a float at // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the // case. if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) && ContainsFloatAtOffset(IRType, IROffset+4, getDataLayout())) return llvm::VectorType::get(llvm::Type::getFloatTy(getVMContext()), 2); return llvm::Type::getDoubleTy(getVMContext()); } /// GetINTEGERTypeAtOffset - The ABI specifies that a value should be passed in /// an 8-byte GPR. This means that we either have a scalar or we are talking /// about the high or low part of an up-to-16-byte struct. This routine picks /// the best LLVM IR type to represent this, which may be i64 or may be anything /// else that the backend will pass in a GPR that works better (e.g. i8, %foo*, /// etc). /// /// PrefType is an LLVM IR type that corresponds to (part of) the IR type for /// the source type. IROffset is an offset in bytes into the LLVM IR type that /// the 8-byte value references. PrefType may be null. /// /// SourceTy is the source-level type for the entire argument. SourceOffset is /// an offset into this that we're processing (which is always either 0 or 8). /// llvm::Type *X86_64ABIInfo:: GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const { // If we're dealing with an un-offset LLVM IR type, then it means that we're // returning an 8-byte unit starting with it. See if we can safely use it. if (IROffset == 0) { // Pointers and int64's always fill the 8-byte unit. if ((isa(IRType) && Has64BitPointers) || IRType->isIntegerTy(64)) return IRType; // If we have a 1/2/4-byte integer, we can use it only if the rest of the // goodness in the source type is just tail padding. This is allowed to // kick in for struct {double,int} on the int, but not on // struct{double,int,int} because we wouldn't return the second int. We // have to do this analysis on the source type because we can't depend on // unions being lowered a specific way etc. if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) || IRType->isIntegerTy(32) || (isa(IRType) && !Has64BitPointers)) { unsigned BitWidth = isa(IRType) ? 32 : cast(IRType)->getBitWidth(); if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth, SourceOffset*8+64, getContext())) return IRType; } } if (llvm::StructType *STy = dyn_cast(IRType)) { // If this is a struct, recurse into the field at the specified offset. const llvm::StructLayout *SL = getDataLayout().getStructLayout(STy); if (IROffset < SL->getSizeInBytes()) { unsigned FieldIdx = SL->getElementContainingOffset(IROffset); IROffset -= SL->getElementOffset(FieldIdx); return GetINTEGERTypeAtOffset(STy->getElementType(FieldIdx), IROffset, SourceTy, SourceOffset); } } if (llvm::ArrayType *ATy = dyn_cast(IRType)) { llvm::Type *EltTy = ATy->getElementType(); unsigned EltSize = getDataLayout().getTypeAllocSize(EltTy); unsigned EltOffset = IROffset/EltSize*EltSize; return GetINTEGERTypeAtOffset(EltTy, IROffset-EltOffset, SourceTy, SourceOffset); } // Okay, we don't have any better idea of what to pass, so we pass this in an // integer register that isn't too big to fit the rest of the struct. unsigned TySizeInBytes = (unsigned)getContext().getTypeSizeInChars(SourceTy).getQuantity(); assert(TySizeInBytes != SourceOffset && "Empty field?"); // It is always safe to classify this as an integer type up to i64 that // isn't larger than the structure. return llvm::IntegerType::get(getVMContext(), std::min(TySizeInBytes-SourceOffset, 8U)*8); } /// GetX86_64ByValArgumentPair - Given a high and low type that can ideally /// be used as elements of a two register pair to pass or return, return a /// first class aggregate to represent them. For example, if the low part of /// a by-value argument should be passed as i32* and the high part as float, /// return {i32*, float}. static llvm::Type * GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, const llvm::DataLayout &TD) { // In order to correctly satisfy the ABI, we need to the high part to start // at offset 8. If the high and low parts we inferred are both 4-byte types // (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have // the second element at offset 8. Check for this: unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo); unsigned HiAlign = TD.getABITypeAlignment(Hi); unsigned HiStart = llvm::alignTo(LoSize, HiAlign); assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!"); // To handle this, we have to increase the size of the low part so that the // second element will start at an 8 byte offset. We can't increase the size // of the second element because it might make us access off the end of the // struct. if (HiStart != 8) { // There are usually two sorts of types the ABI generation code can produce // for the low part of a pair that aren't 8 bytes in size: float or // i8/i16/i32. This can also include pointers when they are 32-bit (X32 and // NaCl). // Promote these to a larger type. if (Lo->isFloatTy()) Lo = llvm::Type::getDoubleTy(Lo->getContext()); else { assert((Lo->isIntegerTy() || Lo->isPointerTy()) && "Invalid/unknown lo type"); Lo = llvm::Type::getInt64Ty(Lo->getContext()); } } llvm::StructType *Result = llvm::StructType::get(Lo, Hi); // Verify that the second element is at an 8-byte offset. assert(TD.getStructLayout(Result)->getElementOffset(1) == 8 && "Invalid x86-64 argument pair!"); return Result; } ABIArgInfo X86_64ABIInfo:: classifyReturnType(QualType RetTy) const { // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the // classification algorithm. X86_64ABIInfo::Class Lo, Hi; classify(RetTy, 0, Lo, Hi, /*isNamedArg*/ true); // Check some invariants. assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); llvm::Type *ResType = nullptr; switch (Lo) { case NoClass: if (Hi == NoClass) return ABIArgInfo::getIgnore(); // If the low part is just padding, it takes no register, leave ResType // null. assert((Hi == SSE || Hi == Integer || Hi == X87Up) && "Unknown missing lo part"); break; case SSEUp: case X87Up: llvm_unreachable("Invalid classification for lo word."); // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via // hidden argument. case Memory: return getIndirectReturnResult(RetTy); // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next // available register of the sequence %rax, %rdx is used. case Integer: ResType = GetINTEGERTypeAtOffset(CGT.ConvertType(RetTy), 0, RetTy, 0); // If we have a sign or zero extended integer, make sure to return Extend // so that the parameter gets the right LLVM IR attributes. if (Hi == NoClass && isa(ResType)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); if (RetTy->isIntegralOrEnumerationType() && RetTy->isPromotableIntegerType()) return ABIArgInfo::getExtend(RetTy); } break; // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next // available SSE register of the sequence %xmm0, %xmm1 is used. case SSE: ResType = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 0, RetTy, 0); break; // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is // returned on the X87 stack in %st0 as 80-bit x87 number. case X87: ResType = llvm::Type::getX86_FP80Ty(getVMContext()); break; // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real // part of the value is returned in %st0 and the imaginary part in // %st1. case ComplexX87: assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification."); ResType = llvm::StructType::get(llvm::Type::getX86_FP80Ty(getVMContext()), llvm::Type::getX86_FP80Ty(getVMContext())); break; } llvm::Type *HighPart = nullptr; switch (Hi) { // Memory was handled previously and X87 should // never occur as a hi class. case Memory: case X87: llvm_unreachable("Invalid classification for hi word."); case ComplexX87: // Previously handled. case NoClass: break; case Integer: HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8); if (Lo == NoClass) // Return HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); break; case SSE: HighPart = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8); if (Lo == NoClass) // Return HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); break; // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte // is passed in the next available eightbyte chunk if the last used // vector register. // // SSEUP should always be preceded by SSE, just widen. case SSEUp: assert(Lo == SSE && "Unexpected SSEUp classification."); ResType = GetByteVectorType(RetTy); break; // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is // returned together with the previous X87 value in %st0. case X87Up: // If X87Up is preceded by X87, we don't need to do // anything. However, in some cases with unions it may not be // preceded by X87. In such situations we follow gcc and pass the // extra bits in an SSE reg. if (Lo != X87) { HighPart = GetSSETypeAtOffset(CGT.ConvertType(RetTy), 8, RetTy, 8); if (Lo == NoClass) // Return HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); } break; } // If a high part was specified, merge it together with the low part. It is // known to pass in the high eightbyte of the result. We do this by forming a // first class struct aggregate with the high and low part: {low, high} if (HighPart) ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout()); return ABIArgInfo::getDirect(ResType); } ABIArgInfo X86_64ABIInfo::classifyArgumentType( QualType Ty, unsigned freeIntRegs, unsigned &neededInt, unsigned &neededSSE, bool isNamedArg) const { Ty = useFirstFieldIfTransparentUnion(Ty); X86_64ABIInfo::Class Lo, Hi; classify(Ty, 0, Lo, Hi, isNamedArg); // Check some invariants. // FIXME: Enforce these by construction. assert((Hi != Memory || Lo == Memory) && "Invalid memory classification."); assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification."); neededInt = 0; neededSSE = 0; llvm::Type *ResType = nullptr; switch (Lo) { case NoClass: if (Hi == NoClass) return ABIArgInfo::getIgnore(); // If the low part is just padding, it takes no register, leave ResType // null. assert((Hi == SSE || Hi == Integer || Hi == X87Up) && "Unknown missing lo part"); break; // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument // on the stack. case Memory: // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or // COMPLEX_X87, it is passed in memory. case X87: case ComplexX87: if (getRecordArgABI(Ty, getCXXABI()) == CGCXXABI::RAA_Indirect) ++neededInt; return getIndirectResult(Ty, freeIntRegs); case SSEUp: case X87Up: llvm_unreachable("Invalid classification for lo word."); // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 // and %r9 is used. case Integer: ++neededInt; // Pick an 8-byte type based on the preferred type. ResType = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 0, Ty, 0); // If we have a sign or zero extended integer, make sure to return Extend // so that the parameter gets the right LLVM IR attributes. if (Hi == NoClass && isa(ResType)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); if (Ty->isIntegralOrEnumerationType() && Ty->isPromotableIntegerType()) return ABIArgInfo::getExtend(Ty); } break; // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next // available SSE register is used, the registers are taken in the // order from %xmm0 to %xmm7. case SSE: { llvm::Type *IRType = CGT.ConvertType(Ty); ResType = GetSSETypeAtOffset(IRType, 0, Ty, 0); ++neededSSE; break; } } llvm::Type *HighPart = nullptr; switch (Hi) { // Memory was handled previously, ComplexX87 and X87 should // never occur as hi classes, and X87Up must be preceded by X87, // which is passed in memory. case Memory: case X87: case ComplexX87: llvm_unreachable("Invalid classification for hi word."); case NoClass: break; case Integer: ++neededInt; // Pick an 8-byte type based on the preferred type. HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8); if (Lo == NoClass) // Pass HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); break; // X87Up generally doesn't occur here (long double is passed in // memory), except in situations involving unions. case X87Up: case SSE: HighPart = GetSSETypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8); if (Lo == NoClass) // Pass HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); ++neededSSE; break; // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the // eightbyte is passed in the upper half of the last used SSE // register. This only happens when 128-bit vectors are passed. case SSEUp: assert(Lo == SSE && "Unexpected SSEUp classification"); ResType = GetByteVectorType(Ty); break; } // If a high part was specified, merge it together with the low part. It is // known to pass in the high eightbyte of the result. We do this by forming a // first class struct aggregate with the high and low part: {low, high} if (HighPart) ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout()); return ABIArgInfo::getDirect(ResType); } ABIArgInfo X86_64ABIInfo::classifyRegCallStructTypeImpl(QualType Ty, unsigned &NeededInt, unsigned &NeededSSE) const { auto RT = Ty->getAs(); assert(RT && "classifyRegCallStructType only valid with struct types"); if (RT->getDecl()->hasFlexibleArrayMember()) return getIndirectReturnResult(Ty); // Sum up bases if (auto CXXRD = dyn_cast(RT->getDecl())) { if (CXXRD->isDynamicClass()) { NeededInt = NeededSSE = 0; return getIndirectReturnResult(Ty); } for (const auto &I : CXXRD->bases()) if (classifyRegCallStructTypeImpl(I.getType(), NeededInt, NeededSSE) .isIndirect()) { NeededInt = NeededSSE = 0; return getIndirectReturnResult(Ty); } } // Sum up members for (const auto *FD : RT->getDecl()->fields()) { if (FD->getType()->isRecordType() && !FD->getType()->isUnionType()) { if (classifyRegCallStructTypeImpl(FD->getType(), NeededInt, NeededSSE) .isIndirect()) { NeededInt = NeededSSE = 0; return getIndirectReturnResult(Ty); } } else { unsigned LocalNeededInt, LocalNeededSSE; if (classifyArgumentType(FD->getType(), UINT_MAX, LocalNeededInt, LocalNeededSSE, true) .isIndirect()) { NeededInt = NeededSSE = 0; return getIndirectReturnResult(Ty); } NeededInt += LocalNeededInt; NeededSSE += LocalNeededSSE; } } return ABIArgInfo::getDirect(); } ABIArgInfo X86_64ABIInfo::classifyRegCallStructType(QualType Ty, unsigned &NeededInt, unsigned &NeededSSE) const { NeededInt = 0; NeededSSE = 0; return classifyRegCallStructTypeImpl(Ty, NeededInt, NeededSSE); } void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { const unsigned CallingConv = FI.getCallingConvention(); // It is possible to force Win64 calling convention on any x86_64 target by // using __attribute__((ms_abi)). In such case to correctly emit Win64 // compatible code delegate this call to WinX86_64ABIInfo::computeInfo. if (CallingConv == llvm::CallingConv::Win64) { WinX86_64ABIInfo Win64ABIInfo(CGT, AVXLevel); Win64ABIInfo.computeInfo(FI); return; } bool IsRegCall = CallingConv == llvm::CallingConv::X86_RegCall; // Keep track of the number of assigned registers. unsigned FreeIntRegs = IsRegCall ? 11 : 6; unsigned FreeSSERegs = IsRegCall ? 16 : 8; unsigned NeededInt, NeededSSE; if (!::classifyReturnType(getCXXABI(), FI, *this)) { if (IsRegCall && FI.getReturnType()->getTypePtr()->isRecordType() && !FI.getReturnType()->getTypePtr()->isUnionType()) { FI.getReturnInfo() = classifyRegCallStructType(FI.getReturnType(), NeededInt, NeededSSE); if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) { FreeIntRegs -= NeededInt; FreeSSERegs -= NeededSSE; } else { FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); } } else if (IsRegCall && FI.getReturnType()->getAs()) { // Complex Long Double Type is passed in Memory when Regcall // calling convention is used. const ComplexType *CT = FI.getReturnType()->getAs(); if (getContext().getCanonicalType(CT->getElementType()) == getContext().LongDoubleTy) FI.getReturnInfo() = getIndirectReturnResult(FI.getReturnType()); } else FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); } // If the return value is indirect, then the hidden argument is consuming one // integer register. if (FI.getReturnInfo().isIndirect()) --FreeIntRegs; // The chain argument effectively gives us another free register. if (FI.isChainCall()) ++FreeIntRegs; unsigned NumRequiredArgs = FI.getNumRequiredArgs(); // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers // get assigned (in left-to-right order) for passing as follows... unsigned ArgNo = 0; for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it, ++ArgNo) { bool IsNamedArg = ArgNo < NumRequiredArgs; if (IsRegCall && it->type->isStructureOrClassType()) it->info = classifyRegCallStructType(it->type, NeededInt, NeededSSE); else it->info = classifyArgumentType(it->type, FreeIntRegs, NeededInt, NeededSSE, IsNamedArg); // AMD64-ABI 3.2.3p3: If there are no registers available for any // eightbyte of an argument, the whole argument is passed on the // stack. If registers have already been assigned for some // eightbytes of such an argument, the assignments get reverted. if (FreeIntRegs >= NeededInt && FreeSSERegs >= NeededSSE) { FreeIntRegs -= NeededInt; FreeSSERegs -= NeededSSE; } else { it->info = getIndirectResult(it->type, FreeIntRegs); } } } static Address EmitX86_64VAArgFromMemory(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) { Address overflow_arg_area_p = CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p"); llvm::Value *overflow_arg_area = CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area"); // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16 // byte boundary if alignment needed by type exceeds 8 byte boundary. // It isn't stated explicitly in the standard, but in practice we use // alignment greater than 16 where necessary. CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty); if (Align > CharUnits::fromQuantity(8)) { overflow_arg_area = emitRoundPointerUpToAlignment(CGF, overflow_arg_area, Align); } // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area. llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); llvm::Value *Res = CGF.Builder.CreateBitCast(overflow_arg_area, llvm::PointerType::getUnqual(LTy)); // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to: // l->overflow_arg_area + sizeof(type). // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to // an 8 byte boundary. uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8; llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, (SizeInBytes + 7) & ~7); overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset, "overflow_arg_area.next"); CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p); // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type. return Address(Res, Align); } Address X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { // Assume that va_list type is correct; should be pointer to LLVM type: // struct { // i32 gp_offset; // i32 fp_offset; // i8* overflow_arg_area; // i8* reg_save_area; // }; unsigned neededInt, neededSSE; Ty = getContext().getCanonicalType(Ty); ABIArgInfo AI = classifyArgumentType(Ty, 0, neededInt, neededSSE, /*isNamedArg*/false); // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed // in the registers. If not go to step 7. if (!neededInt && !neededSSE) return EmitX86_64VAArgFromMemory(CGF, VAListAddr, Ty); // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of // general purpose registers needed to pass type and num_fp to hold // the number of floating point registers needed. // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into // registers. In the case: l->gp_offset > 48 - num_gp * 8 or // l->fp_offset > 304 - num_fp * 16 go to step 7. // // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of // register save space). llvm::Value *InRegs = nullptr; Address gp_offset_p = Address::invalid(), fp_offset_p = Address::invalid(); llvm::Value *gp_offset = nullptr, *fp_offset = nullptr; if (neededInt) { gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p"); gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset"); InRegs = llvm::ConstantInt::get(CGF.Int32Ty, 48 - neededInt * 8); InRegs = CGF.Builder.CreateICmpULE(gp_offset, InRegs, "fits_in_gp"); } if (neededSSE) { fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p"); fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset"); llvm::Value *FitsInFP = llvm::ConstantInt::get(CGF.Int32Ty, 176 - neededSSE * 16); FitsInFP = CGF.Builder.CreateICmpULE(fp_offset, FitsInFP, "fits_in_fp"); InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP; } llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); // Emit code to load the value if it was passed in registers. CGF.EmitBlock(InRegBlock); // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with // an offset of l->gp_offset and/or l->fp_offset. This may require // copying to a temporary location in case the parameter is passed // in different register classes or requires an alignment greater // than 8 for general purpose registers and 16 for XMM registers. // // FIXME: This really results in shameful code when we end up needing to // collect arguments from different places; often what should result in a // simple assembling of a structure from scattered addresses has many more // loads than necessary. Can we clean this up? llvm::Type *LTy = CGF.ConvertTypeForMem(Ty); llvm::Value *RegSaveArea = CGF.Builder.CreateLoad( CGF.Builder.CreateStructGEP(VAListAddr, 3), "reg_save_area"); Address RegAddr = Address::invalid(); if (neededInt && neededSSE) { // FIXME: Cleanup. assert(AI.isDirect() && "Unexpected ABI info for mixed regs"); llvm::StructType *ST = cast(AI.getCoerceToType()); Address Tmp = CGF.CreateMemTemp(Ty); Tmp = CGF.Builder.CreateElementBitCast(Tmp, ST); assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs"); llvm::Type *TyLo = ST->getElementType(0); llvm::Type *TyHi = ST->getElementType(1); assert((TyLo->isFPOrFPVectorTy() ^ TyHi->isFPOrFPVectorTy()) && "Unexpected ABI info for mixed regs"); llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo); llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi); llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegSaveArea, gp_offset); llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegSaveArea, fp_offset); llvm::Value *RegLoAddr = TyLo->isFPOrFPVectorTy() ? FPAddr : GPAddr; llvm::Value *RegHiAddr = TyLo->isFPOrFPVectorTy() ? GPAddr : FPAddr; // Copy the first element. // FIXME: Our choice of alignment here and below is probably pessimistic. llvm::Value *V = CGF.Builder.CreateAlignedLoad( TyLo, CGF.Builder.CreateBitCast(RegLoAddr, PTyLo), CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(TyLo))); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); // Copy the second element. V = CGF.Builder.CreateAlignedLoad( TyHi, CGF.Builder.CreateBitCast(RegHiAddr, PTyHi), CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(TyHi))); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); RegAddr = CGF.Builder.CreateElementBitCast(Tmp, LTy); } else if (neededInt) { RegAddr = Address(CGF.Builder.CreateGEP(RegSaveArea, gp_offset), CharUnits::fromQuantity(8)); RegAddr = CGF.Builder.CreateElementBitCast(RegAddr, LTy); // Copy to a temporary if necessary to ensure the appropriate alignment. std::pair SizeAlign = getContext().getTypeInfoInChars(Ty); uint64_t TySize = SizeAlign.first.getQuantity(); CharUnits TyAlign = SizeAlign.second; // Copy into a temporary if the type is more aligned than the // register save area. if (TyAlign.getQuantity() > 8) { Address Tmp = CGF.CreateMemTemp(Ty); CGF.Builder.CreateMemCpy(Tmp, RegAddr, TySize, false); RegAddr = Tmp; } } else if (neededSSE == 1) { RegAddr = Address(CGF.Builder.CreateGEP(RegSaveArea, fp_offset), CharUnits::fromQuantity(16)); RegAddr = CGF.Builder.CreateElementBitCast(RegAddr, LTy); } else { assert(neededSSE == 2 && "Invalid number of needed registers!"); // SSE registers are spaced 16 bytes apart in the register save // area, we need to collect the two eightbytes together. // The ABI isn't explicit about this, but it seems reasonable // to assume that the slots are 16-byte aligned, since the stack is // naturally 16-byte aligned and the prologue is expected to store // all the SSE registers to the RSA. Address RegAddrLo = Address(CGF.Builder.CreateGEP(RegSaveArea, fp_offset), CharUnits::fromQuantity(16)); Address RegAddrHi = CGF.Builder.CreateConstInBoundsByteGEP(RegAddrLo, CharUnits::fromQuantity(16)); llvm::Type *ST = AI.canHaveCoerceToType() ? AI.getCoerceToType() : llvm::StructType::get(CGF.DoubleTy, CGF.DoubleTy); llvm::Value *V; Address Tmp = CGF.CreateMemTemp(Ty); Tmp = CGF.Builder.CreateElementBitCast(Tmp, ST); V = CGF.Builder.CreateLoad(CGF.Builder.CreateElementBitCast( RegAddrLo, ST->getStructElementType(0))); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0)); V = CGF.Builder.CreateLoad(CGF.Builder.CreateElementBitCast( RegAddrHi, ST->getStructElementType(1))); CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1)); RegAddr = CGF.Builder.CreateElementBitCast(Tmp, LTy); } // AMD64-ABI 3.5.7p5: Step 5. Set: // l->gp_offset = l->gp_offset + num_gp * 8 // l->fp_offset = l->fp_offset + num_fp * 16. if (neededInt) { llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, neededInt * 8); CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset), gp_offset_p); } if (neededSSE) { llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int32Ty, neededSSE * 16); CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset), fp_offset_p); } CGF.EmitBranch(ContBlock); // Emit code to load the value if it was passed in memory. CGF.EmitBlock(InMemBlock); Address MemAddr = EmitX86_64VAArgFromMemory(CGF, VAListAddr, Ty); // Return the appropriate result. CGF.EmitBlock(ContBlock); Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock, MemAddr, InMemBlock, "vaarg.addr"); return ResAddr; } Address X86_64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, CGF.getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(8), /*allowHigherAlign*/ false); } ABIArgInfo WinX86_64ABIInfo::reclassifyHvaArgType(QualType Ty, unsigned &FreeSSERegs, const ABIArgInfo ¤t) const { // Assumes vectorCall calling convention. const Type *Base = nullptr; uint64_t NumElts = 0; if (!Ty->isBuiltinType() && !Ty->isVectorType() && isHomogeneousAggregate(Ty, Base, NumElts) && FreeSSERegs >= NumElts) { FreeSSERegs -= NumElts; return getDirectX86Hva(); } return current; } ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs, bool IsReturnType, bool IsVectorCall, bool IsRegCall) const { if (Ty->isVoidType()) return ABIArgInfo::getIgnore(); if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); TypeInfo Info = getContext().getTypeInfo(Ty); uint64_t Width = Info.Width; CharUnits Align = getContext().toCharUnitsFromBits(Info.Align); const RecordType *RT = Ty->getAs(); if (RT) { if (!IsReturnType) { if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); } if (RT->getDecl()->hasFlexibleArrayMember()) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } const Type *Base = nullptr; uint64_t NumElts = 0; // vectorcall adds the concept of a homogenous vector aggregate, similar to // other targets. if ((IsVectorCall || IsRegCall) && isHomogeneousAggregate(Ty, Base, NumElts)) { if (IsRegCall) { if (FreeSSERegs >= NumElts) { FreeSSERegs -= NumElts; if (IsReturnType || Ty->isBuiltinType() || Ty->isVectorType()) return ABIArgInfo::getDirect(); return ABIArgInfo::getExpand(); } return ABIArgInfo::getIndirect(Align, /*ByVal=*/false); } else if (IsVectorCall) { if (FreeSSERegs >= NumElts && (IsReturnType || Ty->isBuiltinType() || Ty->isVectorType())) { FreeSSERegs -= NumElts; return ABIArgInfo::getDirect(); } else if (IsReturnType) { return ABIArgInfo::getExpand(); } else if (!Ty->isBuiltinType() && !Ty->isVectorType()) { // HVAs are delayed and reclassified in the 2nd step. return ABIArgInfo::getIndirect(Align, /*ByVal=*/false); } } } if (Ty->isMemberPointerType()) { // If the member pointer is represented by an LLVM int or ptr, pass it // directly. llvm::Type *LLTy = CGT.ConvertType(Ty); if (LLTy->isPointerTy() || LLTy->isIntegerTy()) return ABIArgInfo::getDirect(); } if (RT || Ty->isAnyComplexType() || Ty->isMemberPointerType()) { // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is // not 1, 2, 4, or 8 bytes, must be passed by reference." if (Width > 64 || !llvm::isPowerOf2_64(Width)) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); // Otherwise, coerce it to a small integer. return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Width)); } if (const BuiltinType *BT = Ty->getAs()) { switch (BT->getKind()) { case BuiltinType::Bool: // Bool type is always extended to the ABI, other builtin types are not // extended. return ABIArgInfo::getExtend(Ty); case BuiltinType::LongDouble: // Mingw64 GCC uses the old 80 bit extended precision floating point // unit. It passes them indirectly through memory. if (IsMingw64) { const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); if (LDF == &llvm::APFloat::x87DoubleExtended()) return ABIArgInfo::getIndirect(Align, /*ByVal=*/false); } break; case BuiltinType::Int128: case BuiltinType::UInt128: // If it's a parameter type, the normal ABI rule is that arguments larger // than 8 bytes are passed indirectly. GCC follows it. We follow it too, // even though it isn't particularly efficient. if (!IsReturnType) return ABIArgInfo::getIndirect(Align, /*ByVal=*/false); // Mingw64 GCC returns i128 in XMM0. Coerce to v2i64 to handle that. // Clang matches them for compatibility. return ABIArgInfo::getDirect( llvm::VectorType::get(llvm::Type::getInt64Ty(getVMContext()), 2)); default: break; } } return ABIArgInfo::getDirect(); } void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, unsigned FreeSSERegs, bool IsVectorCall, bool IsRegCall) const { unsigned Count = 0; for (auto &I : FI.arguments()) { // Vectorcall in x64 only permits the first 6 arguments to be passed // as XMM/YMM registers. if (Count < VectorcallMaxParamNumAsReg) I.info = classify(I.type, FreeSSERegs, false, IsVectorCall, IsRegCall); else { // Since these cannot be passed in registers, pretend no registers // are left. unsigned ZeroSSERegsAvail = 0; I.info = classify(I.type, /*FreeSSERegs=*/ZeroSSERegsAvail, false, IsVectorCall, IsRegCall); } ++Count; } for (auto &I : FI.arguments()) { I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info); } } void WinX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { const unsigned CC = FI.getCallingConvention(); bool IsVectorCall = CC == llvm::CallingConv::X86_VectorCall; bool IsRegCall = CC == llvm::CallingConv::X86_RegCall; // If __attribute__((sysv_abi)) is in use, use the SysV argument // classification rules. if (CC == llvm::CallingConv::X86_64_SysV) { X86_64ABIInfo SysVABIInfo(CGT, AVXLevel); SysVABIInfo.computeInfo(FI); return; } unsigned FreeSSERegs = 0; if (IsVectorCall) { // We can use up to 4 SSE return registers with vectorcall. FreeSSERegs = 4; } else if (IsRegCall) { // RegCall gives us 16 SSE registers. FreeSSERegs = 16; } if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classify(FI.getReturnType(), FreeSSERegs, true, IsVectorCall, IsRegCall); if (IsVectorCall) { // We can use up to 6 SSE register parameters with vectorcall. FreeSSERegs = 6; } else if (IsRegCall) { // RegCall gives us 16 SSE registers, we can reuse the return registers. FreeSSERegs = 16; } if (IsVectorCall) { computeVectorCallArgs(FI, FreeSSERegs, IsVectorCall, IsRegCall); } else { for (auto &I : FI.arguments()) I.info = classify(I.type, FreeSSERegs, false, IsVectorCall, IsRegCall); } } Address WinX86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { bool IsIndirect = false; // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is // not 1, 2, 4, or 8 bytes, must be passed by reference." if (isAggregateTypeForABI(Ty) || Ty->isMemberPointerType()) { uint64_t Width = getContext().getTypeSize(Ty); IsIndirect = Width > 64 || !llvm::isPowerOf2_64(Width); } return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, CGF.getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(8), /*allowHigherAlign*/ false); } // PowerPC-32 namespace { /// PPC32_SVR4_ABIInfo - The 32-bit PowerPC ELF (SVR4) ABI information. class PPC32_SVR4_ABIInfo : public DefaultABIInfo { bool IsSoftFloatABI; bool IsRetSmallStructInRegABI; CharUnits getParamTypeAlignment(QualType Ty) const; public: PPC32_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, bool SoftFloatABI, bool RetSmallStructInRegABI) : DefaultABIInfo(CGT), IsSoftFloatABI(SoftFloatABI), IsRetSmallStructInRegABI(RetSmallStructInRegABI) {} ABIArgInfo classifyReturnType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class PPC32TargetCodeGenInfo : public TargetCodeGenInfo { public: PPC32TargetCodeGenInfo(CodeGenTypes &CGT, bool SoftFloatABI, bool RetSmallStructInRegABI) : TargetCodeGenInfo(new PPC32_SVR4_ABIInfo(CGT, SoftFloatABI, RetSmallStructInRegABI)) {} static bool isStructReturnInRegABI(const llvm::Triple &Triple, const CodeGenOptions &Opts); int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { // This is recovered from gcc output. return 1; // r1 is the dedicated stack pointer } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; } CharUnits PPC32_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const { // Complex types are passed just like their elements if (const ComplexType *CTy = Ty->getAs()) Ty = CTy->getElementType(); if (Ty->isVectorType()) return CharUnits::fromQuantity(getContext().getTypeSize(Ty) == 128 ? 16 : 4); // For single-element float/vector structs, we consider the whole type // to have the same alignment requirements as its single element. const Type *AlignTy = nullptr; if (const Type *EltType = isSingleElementStruct(Ty, getContext())) { const BuiltinType *BT = EltType->getAs(); if ((EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) || (BT && BT->isFloatingPoint())) AlignTy = EltType; } if (AlignTy) return CharUnits::fromQuantity(AlignTy->isVectorType() ? 16 : 4); return CharUnits::fromQuantity(4); } ABIArgInfo PPC32_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const { uint64_t Size; // -msvr4-struct-return puts small aggregates in GPR3 and GPR4. if (isAggregateTypeForABI(RetTy) && IsRetSmallStructInRegABI && (Size = getContext().getTypeSize(RetTy)) <= 64) { // System V ABI (1995), page 3-22, specified: // > A structure or union whose size is less than or equal to 8 bytes // > shall be returned in r3 and r4, as if it were first stored in the // > 8-byte aligned memory area and then the low addressed word were // > loaded into r3 and the high-addressed word into r4. Bits beyond // > the last member of the structure or union are not defined. // // GCC for big-endian PPC32 inserts the pad before the first member, // not "beyond the last member" of the struct. To stay compatible // with GCC, we coerce the struct to an integer of the same size. // LLVM will extend it and return i32 in r3, or i64 in r3:r4. if (Size == 0) return ABIArgInfo::getIgnore(); else { llvm::Type *CoerceTy = llvm::Type::getIntNTy(getVMContext(), Size); return ABIArgInfo::getDirect(CoerceTy); } } return DefaultABIInfo::classifyReturnType(RetTy); } // TODO: this implementation is now likely redundant with // DefaultABIInfo::EmitVAArg. Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, QualType Ty) const { if (getTarget().getTriple().isOSDarwin()) { auto TI = getContext().getTypeInfoInChars(Ty); TI.second = getParamTypeAlignment(Ty); CharUnits SlotSize = CharUnits::fromQuantity(4); return emitVoidPtrVAArg(CGF, VAList, Ty, classifyArgumentType(Ty).isIndirect(), TI, SlotSize, /*AllowHigherAlign=*/true); } const unsigned OverflowLimit = 8; if (const ComplexType *CTy = Ty->getAs()) { // TODO: Implement this. For now ignore. (void)CTy; return Address::invalid(); // FIXME? } // struct __va_list_tag { // unsigned char gpr; // unsigned char fpr; // unsigned short reserved; // void *overflow_arg_area; // void *reg_save_area; // }; bool isI64 = Ty->isIntegerType() && getContext().getTypeSize(Ty) == 64; bool isInt = Ty->isIntegerType() || Ty->isPointerType() || Ty->isAggregateType(); bool isF64 = Ty->isFloatingType() && getContext().getTypeSize(Ty) == 64; // All aggregates are passed indirectly? That doesn't seem consistent // with the argument-lowering code. bool isIndirect = Ty->isAggregateType(); CGBuilderTy &Builder = CGF.Builder; // The calling convention either uses 1-2 GPRs or 1 FPR. Address NumRegsAddr = Address::invalid(); if (isInt || IsSoftFloatABI) { NumRegsAddr = Builder.CreateStructGEP(VAList, 0, "gpr"); } else { NumRegsAddr = Builder.CreateStructGEP(VAList, 1, "fpr"); } llvm::Value *NumRegs = Builder.CreateLoad(NumRegsAddr, "numUsedRegs"); // "Align" the register count when TY is i64. if (isI64 || (isF64 && IsSoftFloatABI)) { NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8(1)); NumRegs = Builder.CreateAnd(NumRegs, Builder.getInt8((uint8_t) ~1U)); } llvm::Value *CC = Builder.CreateICmpULT(NumRegs, Builder.getInt8(OverflowLimit), "cond"); llvm::BasicBlock *UsingRegs = CGF.createBasicBlock("using_regs"); llvm::BasicBlock *UsingOverflow = CGF.createBasicBlock("using_overflow"); llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); Builder.CreateCondBr(CC, UsingRegs, UsingOverflow); llvm::Type *DirectTy = CGF.ConvertType(Ty); if (isIndirect) DirectTy = DirectTy->getPointerTo(0); // Case 1: consume registers. Address RegAddr = Address::invalid(); { CGF.EmitBlock(UsingRegs); Address RegSaveAreaPtr = Builder.CreateStructGEP(VAList, 4); RegAddr = Address(Builder.CreateLoad(RegSaveAreaPtr), CharUnits::fromQuantity(8)); assert(RegAddr.getElementType() == CGF.Int8Ty); // Floating-point registers start after the general-purpose registers. if (!(isInt || IsSoftFloatABI)) { RegAddr = Builder.CreateConstInBoundsByteGEP(RegAddr, CharUnits::fromQuantity(32)); } // Get the address of the saved value by scaling the number of // registers we've used by the number of CharUnits RegSize = CharUnits::fromQuantity((isInt || IsSoftFloatABI) ? 4 : 8); llvm::Value *RegOffset = Builder.CreateMul(NumRegs, Builder.getInt8(RegSize.getQuantity())); RegAddr = Address(Builder.CreateInBoundsGEP(CGF.Int8Ty, RegAddr.getPointer(), RegOffset), RegAddr.getAlignment().alignmentOfArrayElement(RegSize)); RegAddr = Builder.CreateElementBitCast(RegAddr, DirectTy); // Increase the used-register count. NumRegs = Builder.CreateAdd(NumRegs, Builder.getInt8((isI64 || (isF64 && IsSoftFloatABI)) ? 2 : 1)); Builder.CreateStore(NumRegs, NumRegsAddr); CGF.EmitBranch(Cont); } // Case 2: consume space in the overflow area. Address MemAddr = Address::invalid(); { CGF.EmitBlock(UsingOverflow); Builder.CreateStore(Builder.getInt8(OverflowLimit), NumRegsAddr); // Everything in the overflow area is rounded up to a size of at least 4. CharUnits OverflowAreaAlign = CharUnits::fromQuantity(4); CharUnits Size; if (!isIndirect) { auto TypeInfo = CGF.getContext().getTypeInfoInChars(Ty); Size = TypeInfo.first.alignTo(OverflowAreaAlign); } else { Size = CGF.getPointerSize(); } Address OverflowAreaAddr = Builder.CreateStructGEP(VAList, 3); Address OverflowArea(Builder.CreateLoad(OverflowAreaAddr, "argp.cur"), OverflowAreaAlign); // Round up address of argument to alignment CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty); if (Align > OverflowAreaAlign) { llvm::Value *Ptr = OverflowArea.getPointer(); OverflowArea = Address(emitRoundPointerUpToAlignment(CGF, Ptr, Align), Align); } MemAddr = Builder.CreateElementBitCast(OverflowArea, DirectTy); // Increase the overflow area. OverflowArea = Builder.CreateConstInBoundsByteGEP(OverflowArea, Size); Builder.CreateStore(OverflowArea.getPointer(), OverflowAreaAddr); CGF.EmitBranch(Cont); } CGF.EmitBlock(Cont); // Merge the cases with a phi. Address Result = emitMergePHI(CGF, RegAddr, UsingRegs, MemAddr, UsingOverflow, "vaarg.addr"); // Load the pointer if the argument was passed indirectly. if (isIndirect) { Result = Address(Builder.CreateLoad(Result, "aggr"), getContext().getTypeAlignInChars(Ty)); } return Result; } bool PPC32TargetCodeGenInfo::isStructReturnInRegABI( const llvm::Triple &Triple, const CodeGenOptions &Opts) { assert(Triple.getArch() == llvm::Triple::ppc); switch (Opts.getStructReturnConvention()) { case CodeGenOptions::SRCK_Default: break; case CodeGenOptions::SRCK_OnStack: // -maix-struct-return return false; case CodeGenOptions::SRCK_InRegs: // -msvr4-struct-return return true; } if (Triple.isOSBinFormatELF() && !Triple.isOSLinux()) return true; return false; } bool PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { // This is calculated from the LLVM and GCC tables and verified // against gcc output. AFAIK all ABIs use the same encoding. CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::IntegerType *i8 = CGF.Int8Ty; llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16); // 0-31: r0-31, the 4-byte general-purpose registers AssignToArrayRange(Builder, Address, Four8, 0, 31); // 32-63: fp0-31, the 8-byte floating-point registers AssignToArrayRange(Builder, Address, Eight8, 32, 63); // 64-76 are various 4-byte special-purpose registers: // 64: mq // 65: lr // 66: ctr // 67: ap // 68-75 cr0-7 // 76: xer AssignToArrayRange(Builder, Address, Four8, 64, 76); // 77-108: v0-31, the 16-byte vector registers AssignToArrayRange(Builder, Address, Sixteen8, 77, 108); // 109: vrsave // 110: vscr // 111: spe_acc // 112: spefscr // 113: sfp AssignToArrayRange(Builder, Address, Four8, 109, 113); return false; } // PowerPC-64 namespace { /// PPC64_SVR4_ABIInfo - The 64-bit PowerPC ELF (SVR4) ABI information. class PPC64_SVR4_ABIInfo : public SwiftABIInfo { public: enum ABIKind { ELFv1 = 0, ELFv2 }; private: static const unsigned GPRBits = 64; ABIKind Kind; bool HasQPX; bool IsSoftFloatABI; // A vector of float or double will be promoted to <4 x f32> or <4 x f64> and // will be passed in a QPX register. bool IsQPXVectorTy(const Type *Ty) const { if (!HasQPX) return false; if (const VectorType *VT = Ty->getAs()) { unsigned NumElements = VT->getNumElements(); if (NumElements == 1) return false; if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double)) { if (getContext().getTypeSize(Ty) <= 256) return true; } else if (VT->getElementType()-> isSpecificBuiltinType(BuiltinType::Float)) { if (getContext().getTypeSize(Ty) <= 128) return true; } } return false; } bool IsQPXVectorTy(QualType Ty) const { return IsQPXVectorTy(Ty.getTypePtr()); } public: PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT, ABIKind Kind, bool HasQPX, bool SoftFloatABI) : SwiftABIInfo(CGT), Kind(Kind), HasQPX(HasQPX), IsSoftFloatABI(SoftFloatABI) {} bool isPromotableTypeForABI(QualType Ty) const; CharUnits getParamTypeAlignment(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t Members) const override; // TODO: We can add more logic to computeInfo to improve performance. // Example: For aggregate arguments that fit in a register, we could // use getDirectInReg (as is done below for structs containing a single // floating-point value) to avoid pushing them to memory on function // entry. This would require changing the logic in PPCISelLowering // when lowering the parameters in the caller and args in the callee. void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) { // We rely on the default argument classification for the most part. // One exception: An aggregate containing a single floating-point // or vector item must be passed in a register if one is available. const Type *T = isSingleElementStruct(I.type, getContext()); if (T) { const BuiltinType *BT = T->getAs(); if (IsQPXVectorTy(T) || (T->isVectorType() && getContext().getTypeSize(T) == 128) || (BT && BT->isFloatingPoint())) { QualType QT(T, 0); I.info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT)); continue; } } I.info = classifyArgumentType(I.type); } } Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool shouldPassIndirectlyForSwift(ArrayRef scalars, bool asReturnValue) const override { return occupiesMoreThan(CGT, scalars, /*total*/ 4); } bool isSwiftErrorInRegister() const override { return false; } }; class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo { public: PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT, PPC64_SVR4_ABIInfo::ABIKind Kind, bool HasQPX, bool SoftFloatABI) : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT, Kind, HasQPX, SoftFloatABI)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { // This is recovered from gcc output. return 1; // r1 is the dedicated stack pointer } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo { public: PPC64TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { // This is recovered from gcc output. return 1; // r1 is the dedicated stack pointer } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; } // Return true if the ABI requires Ty to be passed sign- or zero- // extended to 64 bits. bool PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // Promotable integer types are required to be promoted by the ABI. if (Ty->isPromotableIntegerType()) return true; // In addition to the usual promotable integer types, we also need to // extend all 32-bit types, since the ABI requires promotion to 64 bits. if (const BuiltinType *BT = Ty->getAs()) switch (BT->getKind()) { case BuiltinType::Int: case BuiltinType::UInt: return true; default: break; } return false; } /// isAlignedParamType - Determine whether a type requires 16-byte or /// higher alignment in the parameter area. Always returns at least 8. CharUnits PPC64_SVR4_ABIInfo::getParamTypeAlignment(QualType Ty) const { // Complex types are passed just like their elements. if (const ComplexType *CTy = Ty->getAs()) Ty = CTy->getElementType(); // Only vector types of size 16 bytes need alignment (larger types are // passed via reference, smaller types are not aligned). if (IsQPXVectorTy(Ty)) { if (getContext().getTypeSize(Ty) > 128) return CharUnits::fromQuantity(32); return CharUnits::fromQuantity(16); } else if (Ty->isVectorType()) { return CharUnits::fromQuantity(getContext().getTypeSize(Ty) == 128 ? 16 : 8); } // For single-element float/vector structs, we consider the whole type // to have the same alignment requirements as its single element. const Type *AlignAsType = nullptr; const Type *EltType = isSingleElementStruct(Ty, getContext()); if (EltType) { const BuiltinType *BT = EltType->getAs(); if (IsQPXVectorTy(EltType) || (EltType->isVectorType() && getContext().getTypeSize(EltType) == 128) || (BT && BT->isFloatingPoint())) AlignAsType = EltType; } // Likewise for ELFv2 homogeneous aggregates. const Type *Base = nullptr; uint64_t Members = 0; if (!AlignAsType && Kind == ELFv2 && isAggregateTypeForABI(Ty) && isHomogeneousAggregate(Ty, Base, Members)) AlignAsType = Base; // With special case aggregates, only vector base types need alignment. if (AlignAsType && IsQPXVectorTy(AlignAsType)) { if (getContext().getTypeSize(AlignAsType) > 128) return CharUnits::fromQuantity(32); return CharUnits::fromQuantity(16); } else if (AlignAsType) { return CharUnits::fromQuantity(AlignAsType->isVectorType() ? 16 : 8); } // Otherwise, we only need alignment for any aggregate type that // has an alignment requirement of >= 16 bytes. if (isAggregateTypeForABI(Ty) && getContext().getTypeAlign(Ty) >= 128) { if (HasQPX && getContext().getTypeAlign(Ty) >= 256) return CharUnits::fromQuantity(32); return CharUnits::fromQuantity(16); } return CharUnits::fromQuantity(8); } /// isHomogeneousAggregate - Return true if a type is an ELFv2 homogeneous /// aggregate. Base is set to the base element type, and Members is set /// to the number of base elements. bool ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base, uint64_t &Members) const { if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { uint64_t NElements = AT->getSize().getZExtValue(); if (NElements == 0) return false; if (!isHomogeneousAggregate(AT->getElementType(), Base, Members)) return false; Members *= NElements; } else if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return false; Members = 0; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { for (const auto &I : CXXRD->bases()) { // Ignore empty records. if (isEmptyRecord(getContext(), I.getType(), true)) continue; uint64_t FldMembers; if (!isHomogeneousAggregate(I.getType(), Base, FldMembers)) return false; Members += FldMembers; } } for (const auto *FD : RD->fields()) { // Ignore (non-zero arrays of) empty records. QualType FT = FD->getType(); while (const ConstantArrayType *AT = getContext().getAsConstantArrayType(FT)) { if (AT->getSize().getZExtValue() == 0) return false; FT = AT->getElementType(); } if (isEmptyRecord(getContext(), FT, true)) continue; // For compatibility with GCC, ignore empty bitfields in C++ mode. if (getContext().getLangOpts().CPlusPlus && FD->isZeroLengthBitField(getContext())) continue; uint64_t FldMembers; if (!isHomogeneousAggregate(FD->getType(), Base, FldMembers)) return false; Members = (RD->isUnion() ? std::max(Members, FldMembers) : Members + FldMembers); } if (!Base) return false; // Ensure there is no padding. if (getContext().getTypeSize(Base) * Members != getContext().getTypeSize(Ty)) return false; } else { Members = 1; if (const ComplexType *CT = Ty->getAs()) { Members = 2; Ty = CT->getElementType(); } // Most ABIs only support float, double, and some vector type widths. if (!isHomogeneousAggregateBaseType(Ty)) return false; // The base type must be the same for all members. Types that // agree in both total size and mode (float vs. vector) are // treated as being equivalent here. const Type *TyPtr = Ty.getTypePtr(); if (!Base) { Base = TyPtr; // If it's a non-power-of-2 vector, its size is already a power-of-2, // so make sure to widen it explicitly. if (const VectorType *VT = Base->getAs()) { QualType EltTy = VT->getElementType(); unsigned NumElements = getContext().getTypeSize(VT) / getContext().getTypeSize(EltTy); Base = getContext() .getVectorType(EltTy, NumElements, VT->getVectorKind()) .getTypePtr(); } } if (Base->isVectorType() != TyPtr->isVectorType() || getContext().getTypeSize(Base) != getContext().getTypeSize(TyPtr)) return false; } return Members > 0 && isHomogeneousAggregateSmallEnough(Base, Members); } bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // Homogeneous aggregates for ELFv2 must have base types of float, // double, long double, or 128-bit vectors. if (const BuiltinType *BT = Ty->getAs()) { if (BT->getKind() == BuiltinType::Float || BT->getKind() == BuiltinType::Double || BT->getKind() == BuiltinType::LongDouble || (getContext().getTargetInfo().hasFloat128Type() && (BT->getKind() == BuiltinType::Float128))) { if (IsSoftFloatABI) return false; return true; } } if (const VectorType *VT = Ty->getAs()) { if (getContext().getTypeSize(VT) == 128 || IsQPXVectorTy(Ty)) return true; } return false; } bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateSmallEnough( const Type *Base, uint64_t Members) const { // Vector and fp128 types require one register, other floating point types // require one or two registers depending on their size. uint32_t NumRegs = ((getContext().getTargetInfo().hasFloat128Type() && Base->isFloat128Type()) || Base->isVectorType()) ? 1 : (getContext().getTypeSize(Base) + 63) / 64; // Homogeneous Aggregates may occupy at most 8 registers. return Members * NumRegs <= 8; } ABIArgInfo PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); if (Ty->isAnyComplexType()) return ABIArgInfo::getDirect(); // Non-Altivec vector types are passed in GPRs (smaller than 16 bytes) // or via reference (larger than 16 bytes). if (Ty->isVectorType() && !IsQPXVectorTy(Ty)) { uint64_t Size = getContext().getTypeSize(Ty); if (Size > 128) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); else if (Size < 128) { llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size); return ABIArgInfo::getDirect(CoerceTy); } } if (isAggregateTypeForABI(Ty)) { if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); uint64_t ABIAlign = getParamTypeAlignment(Ty).getQuantity(); uint64_t TyAlign = getContext().getTypeAlignInChars(Ty).getQuantity(); // ELFv2 homogeneous aggregates are passed as array types. const Type *Base = nullptr; uint64_t Members = 0; if (Kind == ELFv2 && isHomogeneousAggregate(Ty, Base, Members)) { llvm::Type *BaseTy = CGT.ConvertType(QualType(Base, 0)); llvm::Type *CoerceTy = llvm::ArrayType::get(BaseTy, Members); return ABIArgInfo::getDirect(CoerceTy); } // If an aggregate may end up fully in registers, we do not // use the ByVal method, but pass the aggregate as array. // This is usually beneficial since we avoid forcing the // back-end to store the argument to memory. uint64_t Bits = getContext().getTypeSize(Ty); if (Bits > 0 && Bits <= 8 * GPRBits) { llvm::Type *CoerceTy; // Types up to 8 bytes are passed as integer type (which will be // properly aligned in the argument save area doubleword). if (Bits <= GPRBits) CoerceTy = llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8)); // Larger types are passed as arrays, with the base type selected // according to the required alignment in the save area. else { uint64_t RegBits = ABIAlign * 8; uint64_t NumRegs = llvm::alignTo(Bits, RegBits) / RegBits; llvm::Type *RegTy = llvm::IntegerType::get(getVMContext(), RegBits); CoerceTy = llvm::ArrayType::get(RegTy, NumRegs); } return ABIArgInfo::getDirect(CoerceTy); } // All other aggregates are passed ByVal. return ABIArgInfo::getIndirect(CharUnits::fromQuantity(ABIAlign), /*ByVal=*/true, /*Realign=*/TyAlign > ABIAlign); } return (isPromotableTypeForABI(Ty) ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } ABIArgInfo PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(); // Non-Altivec vector types are returned in GPRs (smaller than 16 bytes) // or via reference (larger than 16 bytes). if (RetTy->isVectorType() && !IsQPXVectorTy(RetTy)) { uint64_t Size = getContext().getTypeSize(RetTy); if (Size > 128) return getNaturalAlignIndirect(RetTy); else if (Size < 128) { llvm::Type *CoerceTy = llvm::IntegerType::get(getVMContext(), Size); return ABIArgInfo::getDirect(CoerceTy); } } if (isAggregateTypeForABI(RetTy)) { // ELFv2 homogeneous aggregates are returned as array types. const Type *Base = nullptr; uint64_t Members = 0; if (Kind == ELFv2 && isHomogeneousAggregate(RetTy, Base, Members)) { llvm::Type *BaseTy = CGT.ConvertType(QualType(Base, 0)); llvm::Type *CoerceTy = llvm::ArrayType::get(BaseTy, Members); return ABIArgInfo::getDirect(CoerceTy); } // ELFv2 small aggregates are returned in up to two registers. uint64_t Bits = getContext().getTypeSize(RetTy); if (Kind == ELFv2 && Bits <= 2 * GPRBits) { if (Bits == 0) return ABIArgInfo::getIgnore(); llvm::Type *CoerceTy; if (Bits > GPRBits) { CoerceTy = llvm::IntegerType::get(getVMContext(), GPRBits); CoerceTy = llvm::StructType::get(CoerceTy, CoerceTy); } else CoerceTy = llvm::IntegerType::get(getVMContext(), llvm::alignTo(Bits, 8)); return ABIArgInfo::getDirect(CoerceTy); } // All other aggregates are returned indirectly. return getNaturalAlignIndirect(RetTy); } return (isPromotableTypeForABI(RetTy) ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } // Based on ARMABIInfo::EmitVAArg, adjusted for 64-bit machine. Address PPC64_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { auto TypeInfo = getContext().getTypeInfoInChars(Ty); TypeInfo.second = getParamTypeAlignment(Ty); CharUnits SlotSize = CharUnits::fromQuantity(8); // If we have a complex type and the base type is smaller than 8 bytes, // the ABI calls for the real and imaginary parts to be right-adjusted // in separate doublewords. However, Clang expects us to produce a // pointer to a structure with the two parts packed tightly. So generate // loads of the real and imaginary parts relative to the va_list pointer, // and store them to a temporary structure. if (const ComplexType *CTy = Ty->getAs()) { CharUnits EltSize = TypeInfo.first / 2; if (EltSize < SlotSize) { Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty, SlotSize * 2, SlotSize, SlotSize, /*AllowHigher*/ true); Address RealAddr = Addr; Address ImagAddr = RealAddr; if (CGF.CGM.getDataLayout().isBigEndian()) { RealAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize - EltSize); ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr, 2 * SlotSize - EltSize); } else { ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize); } llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType()); RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy); ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy); llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal"); llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag"); Address Temp = CGF.CreateMemTemp(Ty, "vacplx"); CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty), /*init*/ true); return Temp; } } // Otherwise, just use the general rule. return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo, SlotSize, /*AllowHigher*/ true); } static bool PPC64_initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) { // This is calculated from the LLVM and GCC tables and verified // against gcc output. AFAIK all ABIs use the same encoding. CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::IntegerType *i8 = CGF.Int8Ty; llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); llvm::Value *Sixteen8 = llvm::ConstantInt::get(i8, 16); // 0-31: r0-31, the 8-byte general-purpose registers AssignToArrayRange(Builder, Address, Eight8, 0, 31); // 32-63: fp0-31, the 8-byte floating-point registers AssignToArrayRange(Builder, Address, Eight8, 32, 63); // 64-67 are various 8-byte special-purpose registers: // 64: mq // 65: lr // 66: ctr // 67: ap AssignToArrayRange(Builder, Address, Eight8, 64, 67); // 68-76 are various 4-byte special-purpose registers: // 68-75 cr0-7 // 76: xer AssignToArrayRange(Builder, Address, Four8, 68, 76); // 77-108: v0-31, the 16-byte vector registers AssignToArrayRange(Builder, Address, Sixteen8, 77, 108); // 109: vrsave // 110: vscr // 111: spe_acc // 112: spefscr // 113: sfp // 114: tfhar // 115: tfiar // 116: texasr AssignToArrayRange(Builder, Address, Eight8, 109, 116); return false; } bool PPC64_SVR4_TargetCodeGenInfo::initDwarfEHRegSizeTable( CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { return PPC64_initDwarfEHRegSizeTable(CGF, Address); } bool PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { return PPC64_initDwarfEHRegSizeTable(CGF, Address); } //===----------------------------------------------------------------------===// // AArch64 ABI Implementation //===----------------------------------------------------------------------===// namespace { class AArch64ABIInfo : public SwiftABIInfo { public: enum ABIKind { AAPCS = 0, DarwinPCS, Win64 }; private: ABIKind Kind; public: AArch64ABIInfo(CodeGenTypes &CGT, ABIKind Kind) : SwiftABIInfo(CGT), Kind(Kind) {} private: ABIKind getABIKind() const { return Kind; } bool isDarwinPCS() const { return Kind == DarwinPCS; } ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t Members) const override; bool isIllegalVectorType(QualType Ty) const; void computeInfo(CGFunctionInfo &FI) const override { if (!::classifyReturnType(getCXXABI(), FI, *this)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic()); for (auto &it : FI.arguments()) it.info = classifyArgumentType(it.type); } Address EmitDarwinVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const; Address EmitAAPCSVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override { return Kind == Win64 ? EmitMSVAArg(CGF, VAListAddr, Ty) : isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF) : EmitAAPCSVAArg(VAListAddr, Ty, CGF); } Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool shouldPassIndirectlyForSwift(ArrayRef scalars, bool asReturnValue) const override { return occupiesMoreThan(CGT, scalars, /*total*/ 4); } bool isSwiftErrorInRegister() const override { return true; } bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy, unsigned elts) const override; }; class AArch64TargetCodeGenInfo : public TargetCodeGenInfo { public: AArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind Kind) : TargetCodeGenInfo(new AArch64ABIInfo(CGT, Kind)) {} StringRef getARCRetainAutoreleasedReturnValueMarker() const override { return "mov\tfp, fp\t\t// marker for objc_retainAutoreleaseReturnValue"; } int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 31; } bool doesReturnSlotInterfereWithArgs() const override { return false; } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; CodeGenOptions::SignReturnAddressScope Scope = CGM.getCodeGenOpts().getSignReturnAddress(); CodeGenOptions::SignReturnAddressKeyValue Key = CGM.getCodeGenOpts().getSignReturnAddressKey(); bool BranchTargetEnforcement = CGM.getCodeGenOpts().BranchTargetEnforcement; if (const auto *TA = FD->getAttr()) { ParsedTargetAttr Attr = TA->parse(); if (!Attr.BranchProtection.empty()) { TargetInfo::BranchProtectionInfo BPI; StringRef Error; (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, BPI, Error); assert(Error.empty()); Scope = BPI.SignReturnAddr; Key = BPI.SignKey; BranchTargetEnforcement = BPI.BranchTargetEnforcement; } } auto *Fn = cast(GV); if (Scope != CodeGenOptions::SignReturnAddressScope::None) { Fn->addFnAttr("sign-return-address", Scope == CodeGenOptions::SignReturnAddressScope::All ? "all" : "non-leaf"); Fn->addFnAttr("sign-return-address-key", Key == CodeGenOptions::SignReturnAddressKeyValue::AKey ? "a_key" : "b_key"); } if (BranchTargetEnforcement) Fn->addFnAttr("branch-target-enforcement"); } }; class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo { public: WindowsAArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIInfo::ABIKind K) : AArch64TargetCodeGenInfo(CGT, K) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { Opt = "/DEFAULTLIB:" + qualifyWindowsLibrary(Lib); } void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, llvm::SmallString<32> &Opt) const override { Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; } }; void WindowsAArch64TargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { AArch64TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); if (GV->isDeclaration()) return; addStackProbeTargetAttributes(D, GV, CGM); } } ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); // Handle illegal vector types here. if (isIllegalVectorType(Ty)) { uint64_t Size = getContext().getTypeSize(Ty); // Android promotes <2 x i8> to i16, not i32 if (isAndroid() && (Size <= 16)) { llvm::Type *ResType = llvm::Type::getInt16Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (Size <= 32) { llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (Size == 64) { llvm::Type *ResType = llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2); return ABIArgInfo::getDirect(ResType); } if (Size == 128) { llvm::Type *ResType = llvm::VectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4); return ABIArgInfo::getDirect(ResType); } return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() && isDarwinPCS() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == CGCXXABI::RAA_DirectInMemory); } // Empty records are always ignored on Darwin, but actually passed in C++ mode // elsewhere for GNU compatibility. uint64_t Size = getContext().getTypeSize(Ty); bool IsEmpty = isEmptyRecord(getContext(), Ty, true); if (IsEmpty || Size == 0) { if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS()) return ABIArgInfo::getIgnore(); // GNU C mode. The only argument that gets ignored is an empty one with size // 0. if (IsEmpty && Size == 0) return ABIArgInfo::getIgnore(); return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); } // Homogeneous Floating-point Aggregates (HFAs) need to be expanded. const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(Ty, Base, Members)) { return ABIArgInfo::getDirect( llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members)); } // Aggregates <= 16 bytes are passed directly in registers or on the stack. if (Size <= 128) { // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of // same size and alignment. if (getTarget().isRenderScriptTarget()) { return coerceToIntArray(Ty, getContext(), getVMContext()); } unsigned Alignment; if (Kind == AArch64ABIInfo::AAPCS) { Alignment = getContext().getTypeUnadjustedAlign(Ty); Alignment = Alignment < 128 ? 64 : 128; } else { Alignment = std::max(getContext().getTypeAlign(Ty), (unsigned)getTarget().getPointerWidth(0)); } Size = llvm::alignTo(Size, Alignment); // We use a pair of i64 for 16-byte aggregate with 8-byte alignment. // For aggregates with 16-byte alignment, we use i128. llvm::Type *BaseTy = llvm::Type::getIntNTy(getVMContext(), Alignment); return ABIArgInfo::getDirect( Size == Alignment ? BaseTy : llvm::ArrayType::get(BaseTy, Size / Alignment)); } return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, bool IsVariadic) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // Large vector types should be returned via memory. if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128) return getNaturalAlignIndirect(RetTy); if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() && isDarwinPCS() ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } uint64_t Size = getContext().getTypeSize(RetTy); if (isEmptyRecord(getContext(), RetTy, true) || Size == 0) return ABIArgInfo::getIgnore(); const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(RetTy, Base, Members) && !(getTarget().getTriple().getArch() == llvm::Triple::aarch64_32 && IsVariadic)) // Homogeneous Floating-point Aggregates (HFAs) are returned directly. return ABIArgInfo::getDirect(); // Aggregates <= 16 bytes are returned directly in registers or on the stack. if (Size <= 128) { // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of // same size and alignment. if (getTarget().isRenderScriptTarget()) { return coerceToIntArray(RetTy, getContext(), getVMContext()); } unsigned Alignment = getContext().getTypeAlign(RetTy); Size = llvm::alignTo(Size, 64); // round up to multiple of 8 bytes // We use a pair of i64 for 16-byte aggregate with 8-byte alignment. // For aggregates with 16-byte alignment, we use i128. if (Alignment < 128 && Size == 128) { llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext()); return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64)); } return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } return getNaturalAlignIndirect(RetTy); } /// isIllegalVectorType - check whether the vector type is legal for AArch64. bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const { if (const VectorType *VT = Ty->getAs()) { // Check whether VT is legal. unsigned NumElements = VT->getNumElements(); uint64_t Size = getContext().getTypeSize(VT); // NumElements should be power of 2. if (!llvm::isPowerOf2_32(NumElements)) return true; // arm64_32 has to be compatible with the ARM logic here, which allows huge // vectors for some reason. llvm::Triple Triple = getTarget().getTriple(); if (Triple.getArch() == llvm::Triple::aarch64_32 && Triple.isOSBinFormatMachO()) return Size <= 32; return Size != 64 && (Size != 128 || NumElements == 1); } return false; } bool AArch64ABIInfo::isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy, unsigned elts) const { if (!llvm::isPowerOf2_32(elts)) return false; if (totalSize.getQuantity() != 8 && (totalSize.getQuantity() != 16 || elts == 1)) return false; return true; } bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // Homogeneous aggregates for AAPCS64 must have base types of a floating // point type or a short-vector type. This is the same as the 32-bit ABI, // but with the difference that any floating-point type is allowed, // including __fp16. if (const BuiltinType *BT = Ty->getAs()) { if (BT->isFloatingPoint()) return true; } else if (const VectorType *VT = Ty->getAs()) { unsigned VecSize = getContext().getTypeSize(VT); if (VecSize == 64 || VecSize == 128) return true; } return false; } bool AArch64ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const { return Members <= 4; } Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const { ABIArgInfo AI = classifyArgumentType(Ty); bool IsIndirect = AI.isIndirect(); llvm::Type *BaseTy = CGF.ConvertType(Ty); if (IsIndirect) BaseTy = llvm::PointerType::getUnqual(BaseTy); else if (AI.getCoerceToType()) BaseTy = AI.getCoerceToType(); unsigned NumRegs = 1; if (llvm::ArrayType *ArrTy = dyn_cast(BaseTy)) { BaseTy = ArrTy->getElementType(); NumRegs = ArrTy->getNumElements(); } bool IsFPR = BaseTy->isFloatingPointTy() || BaseTy->isVectorTy(); // The AArch64 va_list type and handling is specified in the Procedure Call // Standard, section B.4: // // struct { // void *__stack; // void *__gr_top; // void *__vr_top; // int __gr_offs; // int __vr_offs; // }; llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg"); llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); CharUnits TySize = getContext().getTypeSizeInChars(Ty); CharUnits TyAlign = getContext().getTypeUnadjustedAlignInChars(Ty); Address reg_offs_p = Address::invalid(); llvm::Value *reg_offs = nullptr; int reg_top_index; int RegSize = IsIndirect ? 8 : TySize.getQuantity(); if (!IsFPR) { // 3 is the field number of __gr_offs reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 3, "gr_offs_p"); reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs"); reg_top_index = 1; // field number for __gr_top RegSize = llvm::alignTo(RegSize, 8); } else { // 4 is the field number of __vr_offs. reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 4, "vr_offs_p"); reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs"); reg_top_index = 2; // field number for __vr_top RegSize = 16 * NumRegs; } //======================================= // Find out where argument was passed //======================================= // If reg_offs >= 0 we're already using the stack for this type of // argument. We don't want to keep updating reg_offs (in case it overflows, // though anyone passing 2GB of arguments, each at most 16 bytes, deserves // whatever they get). llvm::Value *UsingStack = nullptr; UsingStack = CGF.Builder.CreateICmpSGE( reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, 0)); CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, MaybeRegBlock); // Otherwise, at least some kind of argument could go in these registers, the // question is whether this particular type is too big. CGF.EmitBlock(MaybeRegBlock); // Integer arguments may need to correct register alignment (for example a // "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we // align __gr_offs to calculate the potential address. if (!IsFPR && !IsIndirect && TyAlign.getQuantity() > 8) { int Align = TyAlign.getQuantity(); reg_offs = CGF.Builder.CreateAdd( reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, Align - 1), "align_regoffs"); reg_offs = CGF.Builder.CreateAnd( reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, -Align), "aligned_regoffs"); } // Update the gr_offs/vr_offs pointer for next call to va_arg on this va_list. // The fact that this is done unconditionally reflects the fact that // allocating an argument to the stack also uses up all the remaining // registers of the appropriate kind. llvm::Value *NewOffset = nullptr; NewOffset = CGF.Builder.CreateAdd( reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, RegSize), "new_reg_offs"); CGF.Builder.CreateStore(NewOffset, reg_offs_p); // Now we're in a position to decide whether this argument really was in // registers or not. llvm::Value *InRegs = nullptr; InRegs = CGF.Builder.CreateICmpSLE( NewOffset, llvm::ConstantInt::get(CGF.Int32Ty, 0), "inreg"); CGF.Builder.CreateCondBr(InRegs, InRegBlock, OnStackBlock); //======================================= // Argument was in registers //======================================= // Now we emit the code for if the argument was originally passed in // registers. First start the appropriate block: CGF.EmitBlock(InRegBlock); llvm::Value *reg_top = nullptr; Address reg_top_p = CGF.Builder.CreateStructGEP(VAListAddr, reg_top_index, "reg_top_p"); reg_top = CGF.Builder.CreateLoad(reg_top_p, "reg_top"); Address BaseAddr(CGF.Builder.CreateInBoundsGEP(reg_top, reg_offs), CharUnits::fromQuantity(IsFPR ? 16 : 8)); Address RegAddr = Address::invalid(); llvm::Type *MemTy = CGF.ConvertTypeForMem(Ty); if (IsIndirect) { // If it's been passed indirectly (actually a struct), whatever we find from // stored registers or on the stack will actually be a struct **. MemTy = llvm::PointerType::getUnqual(MemTy); } const Type *Base = nullptr; uint64_t NumMembers = 0; bool IsHFA = isHomogeneousAggregate(Ty, Base, NumMembers); if (IsHFA && NumMembers > 1) { // Homogeneous aggregates passed in registers will have their elements split // and stored 16-bytes apart regardless of size (they're notionally in qN, // qN+1, ...). We reload and store into a temporary local variable // contiguously. assert(!IsIndirect && "Homogeneous aggregates should be passed directly"); auto BaseTyInfo = getContext().getTypeInfoInChars(QualType(Base, 0)); llvm::Type *BaseTy = CGF.ConvertType(QualType(Base, 0)); llvm::Type *HFATy = llvm::ArrayType::get(BaseTy, NumMembers); Address Tmp = CGF.CreateTempAlloca(HFATy, std::max(TyAlign, BaseTyInfo.second)); // On big-endian platforms, the value will be right-aligned in its slot. int Offset = 0; if (CGF.CGM.getDataLayout().isBigEndian() && BaseTyInfo.first.getQuantity() < 16) Offset = 16 - BaseTyInfo.first.getQuantity(); for (unsigned i = 0; i < NumMembers; ++i) { CharUnits BaseOffset = CharUnits::fromQuantity(16 * i + Offset); Address LoadAddr = CGF.Builder.CreateConstInBoundsByteGEP(BaseAddr, BaseOffset); LoadAddr = CGF.Builder.CreateElementBitCast(LoadAddr, BaseTy); Address StoreAddr = CGF.Builder.CreateConstArrayGEP(Tmp, i); llvm::Value *Elem = CGF.Builder.CreateLoad(LoadAddr); CGF.Builder.CreateStore(Elem, StoreAddr); } RegAddr = CGF.Builder.CreateElementBitCast(Tmp, MemTy); } else { // Otherwise the object is contiguous in memory. // It might be right-aligned in its slot. CharUnits SlotSize = BaseAddr.getAlignment(); if (CGF.CGM.getDataLayout().isBigEndian() && !IsIndirect && (IsHFA || !isAggregateTypeForABI(Ty)) && TySize < SlotSize) { CharUnits Offset = SlotSize - TySize; BaseAddr = CGF.Builder.CreateConstInBoundsByteGEP(BaseAddr, Offset); } RegAddr = CGF.Builder.CreateElementBitCast(BaseAddr, MemTy); } CGF.EmitBranch(ContBlock); //======================================= // Argument was on the stack //======================================= CGF.EmitBlock(OnStackBlock); Address stack_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "stack_p"); llvm::Value *OnStackPtr = CGF.Builder.CreateLoad(stack_p, "stack"); // Again, stack arguments may need realignment. In this case both integer and // floating-point ones might be affected. if (!IsIndirect && TyAlign.getQuantity() > 8) { int Align = TyAlign.getQuantity(); OnStackPtr = CGF.Builder.CreatePtrToInt(OnStackPtr, CGF.Int64Ty); OnStackPtr = CGF.Builder.CreateAdd( OnStackPtr, llvm::ConstantInt::get(CGF.Int64Ty, Align - 1), "align_stack"); OnStackPtr = CGF.Builder.CreateAnd( OnStackPtr, llvm::ConstantInt::get(CGF.Int64Ty, -Align), "align_stack"); OnStackPtr = CGF.Builder.CreateIntToPtr(OnStackPtr, CGF.Int8PtrTy); } Address OnStackAddr(OnStackPtr, std::max(CharUnits::fromQuantity(8), TyAlign)); // All stack slots are multiples of 8 bytes. CharUnits StackSlotSize = CharUnits::fromQuantity(8); CharUnits StackSize; if (IsIndirect) StackSize = StackSlotSize; else StackSize = TySize.alignTo(StackSlotSize); llvm::Value *StackSizeC = CGF.Builder.getSize(StackSize); llvm::Value *NewStack = CGF.Builder.CreateInBoundsGEP(OnStackPtr, StackSizeC, "new_stack"); // Write the new value of __stack for the next call to va_arg CGF.Builder.CreateStore(NewStack, stack_p); if (CGF.CGM.getDataLayout().isBigEndian() && !isAggregateTypeForABI(Ty) && TySize < StackSlotSize) { CharUnits Offset = StackSlotSize - TySize; OnStackAddr = CGF.Builder.CreateConstInBoundsByteGEP(OnStackAddr, Offset); } OnStackAddr = CGF.Builder.CreateElementBitCast(OnStackAddr, MemTy); CGF.EmitBranch(ContBlock); //======================================= // Tidy up //======================================= CGF.EmitBlock(ContBlock); Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock, OnStackAddr, OnStackBlock, "vaargs.addr"); if (IsIndirect) return Address(CGF.Builder.CreateLoad(ResAddr, "vaarg.addr"), TyAlign); return ResAddr; } Address AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const { // The backend's lowering doesn't support va_arg for aggregates or // illegal vector types. Lower VAArg here for these cases and use // the LLVM va_arg instruction for everything else. if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty)) return EmitVAArgInstr(CGF, VAListAddr, Ty, ABIArgInfo::getDirect()); uint64_t PointerSize = getTarget().getPointerWidth(0) / 8; CharUnits SlotSize = CharUnits::fromQuantity(PointerSize); // Empty records are ignored for parameter passing purposes. if (isEmptyRecord(getContext(), Ty, true)) { Address Addr(CGF.Builder.CreateLoad(VAListAddr, "ap.cur"), SlotSize); Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty)); return Addr; } // The size of the actual thing passed, which might end up just // being a pointer for indirect types. auto TyInfo = getContext().getTypeInfoInChars(Ty); // Arguments bigger than 16 bytes which aren't homogeneous // aggregates should be passed indirectly. bool IsIndirect = false; if (TyInfo.first.getQuantity() > 16) { const Type *Base = nullptr; uint64_t Members = 0; IsIndirect = !isHomogeneousAggregate(Ty, Base, Members); } return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TyInfo, SlotSize, /*AllowHigherAlign*/ true); } Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, CGF.getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(8), /*allowHigherAlign*/ false); } //===----------------------------------------------------------------------===// // ARM ABI Implementation //===----------------------------------------------------------------------===// namespace { class ARMABIInfo : public SwiftABIInfo { public: enum ABIKind { APCS = 0, AAPCS = 1, AAPCS_VFP = 2, AAPCS16_VFP = 3, }; private: ABIKind Kind; public: ARMABIInfo(CodeGenTypes &CGT, ABIKind _Kind) : SwiftABIInfo(CGT), Kind(_Kind) { setCCs(); } bool isEABI() const { switch (getTarget().getTriple().getEnvironment()) { case llvm::Triple::Android: case llvm::Triple::EABI: case llvm::Triple::EABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::GNUEABIHF: case llvm::Triple::MuslEABI: case llvm::Triple::MuslEABIHF: return true; default: return false; } } bool isEABIHF() const { switch (getTarget().getTriple().getEnvironment()) { case llvm::Triple::EABIHF: case llvm::Triple::GNUEABIHF: case llvm::Triple::MuslEABIHF: return true; default: return false; } } ABIKind getABIKind() const { return Kind; } private: ABIArgInfo classifyReturnType(QualType RetTy, bool isVariadic, unsigned functionCallConv) const; ABIArgInfo classifyArgumentType(QualType RetTy, bool isVariadic, unsigned functionCallConv) const; ABIArgInfo classifyHomogeneousAggregate(QualType Ty, const Type *Base, uint64_t Members) const; ABIArgInfo coerceIllegalVector(QualType Ty) const; bool isIllegalVectorType(QualType Ty) const; bool containsAnyFP16Vectors(QualType Ty) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, uint64_t Members) const override; bool isEffectivelyAAPCS_VFP(unsigned callConvention, bool acceptHalf) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; llvm::CallingConv::ID getLLVMDefaultCC() const; llvm::CallingConv::ID getABIDefaultCC() const; void setCCs(); bool shouldPassIndirectlyForSwift(ArrayRef scalars, bool asReturnValue) const override { return occupiesMoreThan(CGT, scalars, /*total*/ 4); } bool isSwiftErrorInRegister() const override { return true; } bool isLegalVectorTypeForSwift(CharUnits totalSize, llvm::Type *eltTy, unsigned elts) const override; }; class ARMTargetCodeGenInfo : public TargetCodeGenInfo { public: ARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K) :TargetCodeGenInfo(new ARMABIInfo(CGT, K)) {} const ARMABIInfo &getABIInfo() const { return static_cast(TargetCodeGenInfo::getABIInfo()); } int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 13; } StringRef getARCRetainAutoreleasedReturnValueMarker() const override { return "mov\tr7, r7\t\t// marker for objc_retainAutoreleaseReturnValue"; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override { llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4); // 0-15 are the 16 integer registers. AssignToArrayRange(CGF.Builder, Address, Four8, 0, 15); return false; } unsigned getSizeOfUnwindException() const override { if (getABIInfo().isEABI()) return 88; return TargetCodeGenInfo::getSizeOfUnwindException(); } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { if (GV->isDeclaration()) return; const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; const ARMInterruptAttr *Attr = FD->getAttr(); if (!Attr) return; const char *Kind; switch (Attr->getInterrupt()) { case ARMInterruptAttr::Generic: Kind = ""; break; case ARMInterruptAttr::IRQ: Kind = "IRQ"; break; case ARMInterruptAttr::FIQ: Kind = "FIQ"; break; case ARMInterruptAttr::SWI: Kind = "SWI"; break; case ARMInterruptAttr::ABORT: Kind = "ABORT"; break; case ARMInterruptAttr::UNDEF: Kind = "UNDEF"; break; } llvm::Function *Fn = cast(GV); Fn->addFnAttr("interrupt", Kind); ARMABIInfo::ABIKind ABI = cast(getABIInfo()).getABIKind(); if (ABI == ARMABIInfo::APCS) return; // AAPCS guarantees that sp will be 8-byte aligned on any public interface, // however this is not necessarily true on taking any interrupt. Instruct // the backend to perform a realignment as part of the function prologue. llvm::AttrBuilder B; B.addStackAlignmentAttr(8); Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); } }; class WindowsARMTargetCodeGenInfo : public ARMTargetCodeGenInfo { public: WindowsARMTargetCodeGenInfo(CodeGenTypes &CGT, ARMABIInfo::ABIKind K) : ARMTargetCodeGenInfo(CGT, K) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; void getDependentLibraryOption(llvm::StringRef Lib, llvm::SmallString<24> &Opt) const override { Opt = "/DEFAULTLIB:" + qualifyWindowsLibrary(Lib); } void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, llvm::SmallString<32> &Opt) const override { Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; } }; void WindowsARMTargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { ARMTargetCodeGenInfo::setTargetAttributes(D, GV, CGM); if (GV->isDeclaration()) return; addStackProbeTargetAttributes(D, GV, CGM); } } void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!::classifyReturnType(getCXXABI(), FI, *this)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.isVariadic(), FI.getCallingConvention()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type, FI.isVariadic(), FI.getCallingConvention()); // Always honor user-specified calling convention. if (FI.getCallingConvention() != llvm::CallingConv::C) return; llvm::CallingConv::ID cc = getRuntimeCC(); if (cc != llvm::CallingConv::C) FI.setEffectiveCallingConvention(cc); } /// Return the default calling convention that LLVM will use. llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const { // The default calling convention that LLVM will infer. if (isEABIHF() || getTarget().getTriple().isWatchABI()) return llvm::CallingConv::ARM_AAPCS_VFP; else if (isEABI()) return llvm::CallingConv::ARM_AAPCS; else return llvm::CallingConv::ARM_APCS; } /// Return the calling convention that our ABI would like us to use /// as the C calling convention. llvm::CallingConv::ID ARMABIInfo::getABIDefaultCC() const { switch (getABIKind()) { case APCS: return llvm::CallingConv::ARM_APCS; case AAPCS: return llvm::CallingConv::ARM_AAPCS; case AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP; case AAPCS16_VFP: return llvm::CallingConv::ARM_AAPCS_VFP; } llvm_unreachable("bad ABI kind"); } void ARMABIInfo::setCCs() { assert(getRuntimeCC() == llvm::CallingConv::C); // Don't muddy up the IR with a ton of explicit annotations if // they'd just match what LLVM will infer from the triple. llvm::CallingConv::ID abiCC = getABIDefaultCC(); if (abiCC != getLLVMDefaultCC()) RuntimeCC = abiCC; } ABIArgInfo ARMABIInfo::coerceIllegalVector(QualType Ty) const { uint64_t Size = getContext().getTypeSize(Ty); if (Size <= 32) { llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (Size == 64 || Size == 128) { llvm::Type *ResType = llvm::VectorType::get( llvm::Type::getInt32Ty(getVMContext()), Size / 32); return ABIArgInfo::getDirect(ResType); } return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } ABIArgInfo ARMABIInfo::classifyHomogeneousAggregate(QualType Ty, const Type *Base, uint64_t Members) const { assert(Base && "Base class should be set for homogeneous aggregate"); // Base can be a floating-point or a vector. if (const VectorType *VT = Base->getAs()) { // FP16 vectors should be converted to integer vectors if (!getTarget().hasLegalHalfType() && containsAnyFP16Vectors(Ty)) { uint64_t Size = getContext().getTypeSize(VT); llvm::Type *NewVecTy = llvm::VectorType::get( llvm::Type::getInt32Ty(getVMContext()), Size / 32); llvm::Type *Ty = llvm::ArrayType::get(NewVecTy, Members); return ABIArgInfo::getDirect(Ty, 0, nullptr, false); } } return ABIArgInfo::getDirect(nullptr, 0, nullptr, false); } ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, bool isVariadic, unsigned functionCallConv) const { // 6.1.2.1 The following argument types are VFP CPRCs: // A single-precision floating-point type (including promoted // half-precision types); A double-precision floating-point type; // A 64-bit or 128-bit containerized vector type; Homogeneous Aggregate // with a Base Type of a single- or double-precision floating-point type, // 64-bit containerized vectors or 128-bit containerized vectors with one // to four Elements. // Variadic functions should always marshal to the base standard. bool IsAAPCS_VFP = !isVariadic && isEffectivelyAAPCS_VFP(functionCallConv, /* AAPCS16 */ false); Ty = useFirstFieldIfTransparentUnion(Ty); // Handle illegal vector types here. if (isIllegalVectorType(Ty)) return coerceIllegalVector(Ty); // _Float16 and __fp16 get passed as if it were an int or float, but with // the top 16 bits unspecified. This is not done for OpenCL as it handles the // half type natively, and does not need to interwork with AAPCS code. if ((Ty->isFloat16Type() || Ty->isHalfType()) && !getContext().getLangOpts().NativeHalfArgsAndReturns) { llvm::Type *ResType = IsAAPCS_VFP ? llvm::Type::getFloatTy(getVMContext()) : llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) { Ty = EnumTy->getDecl()->getIntegerType(); } return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); } // Ignore empty records. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); if (IsAAPCS_VFP) { // Homogeneous Aggregates need to be expanded when we can fit the aggregate // into VFP registers. const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(Ty, Base, Members)) return classifyHomogeneousAggregate(Ty, Base, Members); } else if (getABIKind() == ARMABIInfo::AAPCS16_VFP) { // WatchOS does have homogeneous aggregates. Note that we intentionally use // this convention even for a variadic function: the backend will use GPRs // if needed. const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(Ty, Base, Members)) { assert(Base && Members <= 4 && "unexpected homogeneous aggregate"); llvm::Type *Ty = llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members); return ABIArgInfo::getDirect(Ty, 0, nullptr, false); } } if (getABIKind() == ARMABIInfo::AAPCS16_VFP && getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(16)) { // WatchOS is adopting the 64-bit AAPCS rule on composite types: if they're // bigger than 128-bits, they get placed in space allocated by the caller, // and a pointer is passed. return ABIArgInfo::getIndirect( CharUnits::fromQuantity(getContext().getTypeAlign(Ty) / 8), false); } // Support byval for ARM. // The ABI alignment for APCS is 4-byte and for AAPCS at least 4-byte and at // most 8-byte. We realign the indirect argument if type alignment is bigger // than ABI alignment. uint64_t ABIAlign = 4; uint64_t TyAlign; if (getABIKind() == ARMABIInfo::AAPCS_VFP || getABIKind() == ARMABIInfo::AAPCS) { TyAlign = getContext().getTypeUnadjustedAlignInChars(Ty).getQuantity(); ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8); } else { TyAlign = getContext().getTypeAlignInChars(Ty).getQuantity(); } if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) { assert(getABIKind() != ARMABIInfo::AAPCS16_VFP && "unexpected byval"); return ABIArgInfo::getIndirect(CharUnits::fromQuantity(ABIAlign), /*ByVal=*/true, /*Realign=*/TyAlign > ABIAlign); } // On RenderScript, coerce Aggregates <= 64 bytes to an integer array of // same size and alignment. if (getTarget().isRenderScriptTarget()) { return coerceToIntArray(Ty, getContext(), getVMContext()); } // Otherwise, pass by coercing to a structure of the appropriate size. llvm::Type* ElemTy; unsigned SizeRegs; // FIXME: Try to match the types of the arguments more accurately where // we can. if (TyAlign <= 4) { ElemTy = llvm::Type::getInt32Ty(getVMContext()); SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32; } else { ElemTy = llvm::Type::getInt64Ty(getVMContext()); SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64; } return ABIArgInfo::getDirect(llvm::ArrayType::get(ElemTy, SizeRegs)); } static bool isIntegerLikeType(QualType Ty, ASTContext &Context, llvm::LLVMContext &VMContext) { // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure // is called integer-like if its size is less than or equal to one word, and // the offset of each of its addressable sub-fields is zero. uint64_t Size = Context.getTypeSize(Ty); // Check that the type fits in a word. if (Size > 32) return false; // FIXME: Handle vector types! if (Ty->isVectorType()) return false; // Float types are never treated as "integer like". if (Ty->isRealFloatingType()) return false; // If this is a builtin or pointer type then it is ok. if (Ty->getAs() || Ty->isPointerType()) return true; // Small complex integer types are "integer like". if (const ComplexType *CT = Ty->getAs()) return isIntegerLikeType(CT->getElementType(), Context, VMContext); // Single element and zero sized arrays should be allowed, by the definition // above, but they are not. // Otherwise, it must be a record type. const RecordType *RT = Ty->getAs(); if (!RT) return false; // Ignore records with flexible arrays. const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return false; // Check that all sub-fields are at offset 0, and are themselves "integer // like". const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); bool HadField = false; unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { const FieldDecl *FD = *i; // Bit-fields are not addressable, we only need to verify they are "integer // like". We still have to disallow a subsequent non-bitfield, for example: // struct { int : 0; int x } // is non-integer like according to gcc. if (FD->isBitField()) { if (!RD->isUnion()) HadField = true; if (!isIntegerLikeType(FD->getType(), Context, VMContext)) return false; continue; } // Check if this field is at offset 0. if (Layout.getFieldOffset(idx) != 0) return false; if (!isIntegerLikeType(FD->getType(), Context, VMContext)) return false; // Only allow at most one field in a structure. This doesn't match the // wording above, but follows gcc in situations with a field following an // empty structure. if (!RD->isUnion()) { if (HadField) return false; HadField = true; } } return true; } ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy, bool isVariadic, unsigned functionCallConv) const { // Variadic functions should always marshal to the base standard. bool IsAAPCS_VFP = !isVariadic && isEffectivelyAAPCS_VFP(functionCallConv, /* AAPCS16 */ true); if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (const VectorType *VT = RetTy->getAs()) { // Large vector types should be returned via memory. if (getContext().getTypeSize(RetTy) > 128) return getNaturalAlignIndirect(RetTy); // FP16 vectors should be converted to integer vectors if (!getTarget().hasLegalHalfType() && (VT->getElementType()->isFloat16Type() || VT->getElementType()->isHalfType())) return coerceIllegalVector(RetTy); } // _Float16 and __fp16 get returned as if it were an int or float, but with // the top 16 bits unspecified. This is not done for OpenCL as it handles the // half type natively, and does not need to interwork with AAPCS code. if ((RetTy->isFloat16Type() || RetTy->isHalfType()) && !getContext().getLangOpts().NativeHalfArgsAndReturns) { llvm::Type *ResType = IsAAPCS_VFP ? llvm::Type::getFloatTy(getVMContext()) : llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(ResType); } if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect(); } // Are we following APCS? if (getABIKind() == APCS) { if (isEmptyRecord(getContext(), RetTy, false)) return ABIArgInfo::getIgnore(); // Complex types are all returned as packed integers. // // FIXME: Consider using 2 x vector types if the back end handles them // correctly. if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(llvm::IntegerType::get( getVMContext(), getContext().getTypeSize(RetTy))); // Integer like structures are returned in r0. if (isIntegerLikeType(RetTy, getContext(), getVMContext())) { // Return in the smallest viable integer type. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 8) return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); } // Otherwise return in memory. return getNaturalAlignIndirect(RetTy); } // Otherwise this is an AAPCS variant. if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Check for homogeneous aggregates with AAPCS-VFP. if (IsAAPCS_VFP) { const Type *Base = nullptr; uint64_t Members = 0; if (isHomogeneousAggregate(RetTy, Base, Members)) return classifyHomogeneousAggregate(RetTy, Base, Members); } // Aggregates <= 4 bytes are returned in r0; other aggregates // are returned indirectly. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 32) { // On RenderScript, coerce Aggregates <= 4 bytes to an integer array of // same size and alignment. if (getTarget().isRenderScriptTarget()) { return coerceToIntArray(RetTy, getContext(), getVMContext()); } if (getDataLayout().isBigEndian()) // Return in 32 bit integer integer type (as if loaded by LDR, AAPCS 5.4) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); // Return in the smallest viable integer type. if (Size <= 8) return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); } else if (Size <= 128 && getABIKind() == AAPCS16_VFP) { llvm::Type *Int32Ty = llvm::Type::getInt32Ty(getVMContext()); llvm::Type *CoerceTy = llvm::ArrayType::get(Int32Ty, llvm::alignTo(Size, 32) / 32); return ABIArgInfo::getDirect(CoerceTy); } return getNaturalAlignIndirect(RetTy); } /// isIllegalVector - check whether Ty is an illegal vector type. bool ARMABIInfo::isIllegalVectorType(QualType Ty) const { if (const VectorType *VT = Ty->getAs ()) { // On targets that don't support FP16, FP16 is expanded into float, and we // don't want the ABI to depend on whether or not FP16 is supported in // hardware. Thus return false to coerce FP16 vectors into integer vectors. if (!getTarget().hasLegalHalfType() && (VT->getElementType()->isFloat16Type() || VT->getElementType()->isHalfType())) return true; if (isAndroid()) { // Android shipped using Clang 3.1, which supported a slightly different // vector ABI. The primary differences were that 3-element vector types // were legal, and so were sub 32-bit vectors (i.e. <2 x i8>). This path // accepts that legacy behavior for Android only. // Check whether VT is legal. unsigned NumElements = VT->getNumElements(); // NumElements should be power of 2 or equal to 3. if (!llvm::isPowerOf2_32(NumElements) && NumElements != 3) return true; } else { // Check whether VT is legal. unsigned NumElements = VT->getNumElements(); uint64_t Size = getContext().getTypeSize(VT); // NumElements should be power of 2. if (!llvm::isPowerOf2_32(NumElements)) return true; // Size should be greater than 32 bits. return Size <= 32; } } return false; } /// Return true if a type contains any 16-bit floating point vectors bool ARMABIInfo::containsAnyFP16Vectors(QualType Ty) const { if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { uint64_t NElements = AT->getSize().getZExtValue(); if (NElements == 0) return false; return containsAnyFP16Vectors(AT->getElementType()); } else if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) if (llvm::any_of(CXXRD->bases(), [this](const CXXBaseSpecifier &B) { return containsAnyFP16Vectors(B.getType()); })) return true; if (llvm::any_of(RD->fields(), [this](FieldDecl *FD) { return FD && containsAnyFP16Vectors(FD->getType()); })) return true; return false; } else { if (const VectorType *VT = Ty->getAs()) return (VT->getElementType()->isFloat16Type() || VT->getElementType()->isHalfType()); return false; } } bool ARMABIInfo::isLegalVectorTypeForSwift(CharUnits vectorSize, llvm::Type *eltTy, unsigned numElts) const { if (!llvm::isPowerOf2_32(numElts)) return false; unsigned size = getDataLayout().getTypeStoreSizeInBits(eltTy); if (size > 64) return false; if (vectorSize.getQuantity() != 8 && (vectorSize.getQuantity() != 16 || numElts == 1)) return false; return true; } bool ARMABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { // Homogeneous aggregates for AAPCS-VFP must have base types of float, // double, or 64-bit or 128-bit vectors. if (const BuiltinType *BT = Ty->getAs()) { if (BT->getKind() == BuiltinType::Float || BT->getKind() == BuiltinType::Double || BT->getKind() == BuiltinType::LongDouble) return true; } else if (const VectorType *VT = Ty->getAs()) { unsigned VecSize = getContext().getTypeSize(VT); if (VecSize == 64 || VecSize == 128) return true; } return false; } bool ARMABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const { return Members <= 4; } bool ARMABIInfo::isEffectivelyAAPCS_VFP(unsigned callConvention, bool acceptHalf) const { // Give precedence to user-specified calling conventions. if (callConvention != llvm::CallingConv::C) return (callConvention == llvm::CallingConv::ARM_AAPCS_VFP); else return (getABIKind() == AAPCS_VFP) || (acceptHalf && (getABIKind() == AAPCS16_VFP)); } Address ARMABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { CharUnits SlotSize = CharUnits::fromQuantity(4); // Empty records are ignored for parameter passing purposes. if (isEmptyRecord(getContext(), Ty, true)) { Address Addr(CGF.Builder.CreateLoad(VAListAddr), SlotSize); Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty)); return Addr; } CharUnits TySize = getContext().getTypeSizeInChars(Ty); CharUnits TyAlignForABI = getContext().getTypeUnadjustedAlignInChars(Ty); // Use indirect if size of the illegal vector is bigger than 16 bytes. bool IsIndirect = false; const Type *Base = nullptr; uint64_t Members = 0; if (TySize > CharUnits::fromQuantity(16) && isIllegalVectorType(Ty)) { IsIndirect = true; // ARMv7k passes structs bigger than 16 bytes indirectly, in space // allocated by the caller. } else if (TySize > CharUnits::fromQuantity(16) && getABIKind() == ARMABIInfo::AAPCS16_VFP && !isHomogeneousAggregate(Ty, Base, Members)) { IsIndirect = true; // Otherwise, bound the type's ABI alignment. // The ABI alignment for 64-bit or 128-bit vectors is 8 for AAPCS and 4 for // APCS. For AAPCS, the ABI alignment is at least 4-byte and at most 8-byte. // Our callers should be prepared to handle an under-aligned address. } else if (getABIKind() == ARMABIInfo::AAPCS_VFP || getABIKind() == ARMABIInfo::AAPCS) { TyAlignForABI = std::max(TyAlignForABI, CharUnits::fromQuantity(4)); TyAlignForABI = std::min(TyAlignForABI, CharUnits::fromQuantity(8)); } else if (getABIKind() == ARMABIInfo::AAPCS16_VFP) { // ARMv7k allows type alignment up to 16 bytes. TyAlignForABI = std::max(TyAlignForABI, CharUnits::fromQuantity(4)); TyAlignForABI = std::min(TyAlignForABI, CharUnits::fromQuantity(16)); } else { TyAlignForABI = CharUnits::fromQuantity(4); } std::pair TyInfo = { TySize, TyAlignForABI }; return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TyInfo, SlotSize, /*AllowHigherAlign*/ true); } //===----------------------------------------------------------------------===// // NVPTX ABI Implementation //===----------------------------------------------------------------------===// namespace { class NVPTXABIInfo : public ABIInfo { public: NVPTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo { public: NVPTXTargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new NVPTXABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; bool shouldEmitStaticExternCAliases() const override; private: // Adds a NamedMDNode with F, Name, and Operand as operands, and adds the // resulting MDNode to the nvvm.annotations MDNode. static void addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand); }; /// Checks if the type is unsupported directly by the current target. static bool isUnsupportedType(ASTContext &Context, QualType T) { if (!Context.getTargetInfo().hasFloat16Type() && T->isFloat16Type()) return true; if (!Context.getTargetInfo().hasFloat128Type() && (T->isFloat128Type() || (T->isRealFloatingType() && Context.getTypeSize(T) == 128))) return true; if (!Context.getTargetInfo().hasInt128Type() && T->isIntegerType() && Context.getTypeSize(T) > 64) return true; if (const auto *AT = T->getAsArrayTypeUnsafe()) return isUnsupportedType(Context, AT->getElementType()); const auto *RT = T->getAs(); if (!RT) return false; const RecordDecl *RD = RT->getDecl(); // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) for (const CXXBaseSpecifier &I : CXXRD->bases()) if (isUnsupportedType(Context, I.getType())) return true; for (const FieldDecl *I : RD->fields()) if (isUnsupportedType(Context, I->getType())) return true; return false; } /// Coerce the given type into an array with maximum allowed size of elements. static ABIArgInfo coerceToIntArrayWithLimit(QualType Ty, ASTContext &Context, llvm::LLVMContext &LLVMContext, unsigned MaxSize) { // Alignment and Size are measured in bits. const uint64_t Size = Context.getTypeSize(Ty); const uint64_t Alignment = Context.getTypeAlign(Ty); const unsigned Div = std::min(MaxSize, Alignment); llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Div); const uint64_t NumElements = (Size + Div - 1) / Div; return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements)); } ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (getContext().getLangOpts().OpenMP && getContext().getLangOpts().OpenMPIsDevice && isUnsupportedType(getContext(), RetTy)) return coerceToIntArrayWithLimit(RetTy, getContext(), getVMContext(), 64); // note: this is different from default ABI if (!RetTy->isScalarType()) return ABIArgInfo::getDirect(); // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // Return aggregates type as indirect by value if (isAggregateTypeForABI(Ty)) return getNaturalAlignIndirect(Ty, /* byval */ true); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } void NVPTXABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); // Always honor user-specified calling convention. if (FI.getCallingConvention() != llvm::CallingConv::C) return; FI.setEffectiveCallingConvention(getRuntimeCC()); } Address NVPTXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { llvm_unreachable("NVPTX does not support varargs"); } void NVPTXTargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { if (GV->isDeclaration()) return; const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; llvm::Function *F = cast(GV); // Perform special handling in OpenCL mode if (M.getLangOpts().OpenCL) { // Use OpenCL function attributes to check for kernel functions // By default, all functions are device functions if (FD->hasAttr()) { // OpenCL __kernel functions get kernel metadata // Create !{, metadata !"kernel", i32 1} node addNVVMMetadata(F, "kernel", 1); // And kernel functions are not subject to inlining F->addFnAttr(llvm::Attribute::NoInline); } } // Perform special handling in CUDA mode. if (M.getLangOpts().CUDA) { // CUDA __global__ functions get a kernel metadata entry. Since // __global__ functions cannot be called from the device, we do not // need to set the noinline attribute. if (FD->hasAttr()) { // Create !{, metadata !"kernel", i32 1} node addNVVMMetadata(F, "kernel", 1); } if (CUDALaunchBoundsAttr *Attr = FD->getAttr()) { // Create !{, metadata !"maxntidx", i32 } node llvm::APSInt MaxThreads(32); MaxThreads = Attr->getMaxThreads()->EvaluateKnownConstInt(M.getContext()); if (MaxThreads > 0) addNVVMMetadata(F, "maxntidx", MaxThreads.getExtValue()); // min blocks is an optional argument for CUDALaunchBoundsAttr. If it was // not specified in __launch_bounds__ or if the user specified a 0 value, // we don't have to add a PTX directive. if (Attr->getMinBlocks()) { llvm::APSInt MinBlocks(32); MinBlocks = Attr->getMinBlocks()->EvaluateKnownConstInt(M.getContext()); if (MinBlocks > 0) // Create !{, metadata !"minctasm", i32 } node addNVVMMetadata(F, "minctasm", MinBlocks.getExtValue()); } } } } void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand) { llvm::Module *M = F->getParent(); llvm::LLVMContext &Ctx = M->getContext(); // Get "nvvm.annotations" metadata node llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations"); llvm::Metadata *MDVals[] = { llvm::ConstantAsMetadata::get(F), llvm::MDString::get(Ctx, Name), llvm::ConstantAsMetadata::get( llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))}; // Append metadata to nvvm.annotations MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); } bool NVPTXTargetCodeGenInfo::shouldEmitStaticExternCAliases() const { return false; } } //===----------------------------------------------------------------------===// // SystemZ ABI Implementation //===----------------------------------------------------------------------===// namespace { class SystemZABIInfo : public SwiftABIInfo { bool HasVector; public: SystemZABIInfo(CodeGenTypes &CGT, bool HV) : SwiftABIInfo(CGT), HasVector(HV) {} bool isPromotableIntegerType(QualType Ty) const; bool isCompoundType(QualType Ty) const; bool isVectorArgumentType(QualType Ty) const; bool isFPArgumentType(QualType Ty) const; QualType GetSingleElementType(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType ArgTy) const; void computeInfo(CGFunctionInfo &FI) const override { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; bool shouldPassIndirectlyForSwift(ArrayRef scalars, bool asReturnValue) const override { return occupiesMoreThan(CGT, scalars, /*total*/ 4); } bool isSwiftErrorInRegister() const override { return false; } }; class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { public: SystemZTargetCodeGenInfo(CodeGenTypes &CGT, bool HasVector) : TargetCodeGenInfo(new SystemZABIInfo(CGT, HasVector)) {} }; } bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // Promotable integer types are required to be promoted by the ABI. if (Ty->isPromotableIntegerType()) return true; // 32-bit values must also be promoted. if (const BuiltinType *BT = Ty->getAs()) switch (BT->getKind()) { case BuiltinType::Int: case BuiltinType::UInt: return true; default: return false; } return false; } bool SystemZABIInfo::isCompoundType(QualType Ty) const { return (Ty->isAnyComplexType() || Ty->isVectorType() || isAggregateTypeForABI(Ty)); } bool SystemZABIInfo::isVectorArgumentType(QualType Ty) const { return (HasVector && Ty->isVectorType() && getContext().getTypeSize(Ty) <= 128); } bool SystemZABIInfo::isFPArgumentType(QualType Ty) const { if (const BuiltinType *BT = Ty->getAs()) switch (BT->getKind()) { case BuiltinType::Float: case BuiltinType::Double: return true; default: return false; } return false; } QualType SystemZABIInfo::GetSingleElementType(QualType Ty) const { if (const RecordType *RT = Ty->getAsStructureType()) { const RecordDecl *RD = RT->getDecl(); QualType Found; // If this is a C++ record, check the bases first. if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) for (const auto &I : CXXRD->bases()) { QualType Base = I.getType(); // Empty bases don't affect things either way. if (isEmptyRecord(getContext(), Base, true)) continue; if (!Found.isNull()) return Ty; Found = GetSingleElementType(Base); } // Check the fields. for (const auto *FD : RD->fields()) { // For compatibility with GCC, ignore empty bitfields in C++ mode. // Unlike isSingleElementStruct(), empty structure and array fields // do count. So do anonymous bitfields that aren't zero-sized. if (getContext().getLangOpts().CPlusPlus && FD->isZeroLengthBitField(getContext())) continue; // Unlike isSingleElementStruct(), arrays do not count. // Nested structures still do though. if (!Found.isNull()) return Ty; Found = GetSingleElementType(FD->getType()); } // Unlike isSingleElementStruct(), trailing padding is allowed. // An 8-byte aligned struct s { float f; } is passed as a double. if (!Found.isNull()) return Found; } return Ty; } Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { // Assume that va_list type is correct; should be pointer to LLVM type: // struct { // i64 __gpr; // i64 __fpr; // i8 *__overflow_arg_area; // i8 *__reg_save_area; // }; // Every non-vector argument occupies 8 bytes and is passed by preference // in either GPRs or FPRs. Vector arguments occupy 8 or 16 bytes and are // always passed on the stack. Ty = getContext().getCanonicalType(Ty); auto TyInfo = getContext().getTypeInfoInChars(Ty); llvm::Type *ArgTy = CGF.ConvertTypeForMem(Ty); llvm::Type *DirectTy = ArgTy; ABIArgInfo AI = classifyArgumentType(Ty); bool IsIndirect = AI.isIndirect(); bool InFPRs = false; bool IsVector = false; CharUnits UnpaddedSize; CharUnits DirectAlign; if (IsIndirect) { DirectTy = llvm::PointerType::getUnqual(DirectTy); UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8); } else { if (AI.getCoerceToType()) ArgTy = AI.getCoerceToType(); InFPRs = ArgTy->isFloatTy() || ArgTy->isDoubleTy(); IsVector = ArgTy->isVectorTy(); UnpaddedSize = TyInfo.first; DirectAlign = TyInfo.second; } CharUnits PaddedSize = CharUnits::fromQuantity(8); if (IsVector && UnpaddedSize > PaddedSize) PaddedSize = CharUnits::fromQuantity(16); assert((UnpaddedSize <= PaddedSize) && "Invalid argument size."); CharUnits Padding = (PaddedSize - UnpaddedSize); llvm::Type *IndexTy = CGF.Int64Ty; llvm::Value *PaddedSizeV = llvm::ConstantInt::get(IndexTy, PaddedSize.getQuantity()); if (IsVector) { // Work out the address of a vector argument on the stack. // Vector arguments are always passed in the high bits of a // single (8 byte) or double (16 byte) stack slot. Address OverflowArgAreaPtr = CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_ptr"); Address OverflowArgArea = Address(CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area"), TyInfo.second); Address MemAddr = CGF.Builder.CreateElementBitCast(OverflowArgArea, DirectTy, "mem_addr"); // Update overflow_arg_area_ptr pointer llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP(OverflowArgArea.getPointer(), PaddedSizeV, "overflow_arg_area"); CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); return MemAddr; } assert(PaddedSize.getQuantity() == 8); unsigned MaxRegs, RegCountField, RegSaveIndex; CharUnits RegPadding; if (InFPRs) { MaxRegs = 4; // Maximum of 4 FPR arguments RegCountField = 1; // __fpr RegSaveIndex = 16; // save offset for f0 RegPadding = CharUnits(); // floats are passed in the high bits of an FPR } else { MaxRegs = 5; // Maximum of 5 GPR arguments RegCountField = 0; // __gpr RegSaveIndex = 2; // save offset for r2 RegPadding = Padding; // values are passed in the low bits of a GPR } Address RegCountPtr = CGF.Builder.CreateStructGEP(VAListAddr, RegCountField, "reg_count_ptr"); llvm::Value *RegCount = CGF.Builder.CreateLoad(RegCountPtr, "reg_count"); llvm::Value *MaxRegsV = llvm::ConstantInt::get(IndexTy, MaxRegs); llvm::Value *InRegs = CGF.Builder.CreateICmpULT(RegCount, MaxRegsV, "fits_in_regs"); llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem"); llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); // Emit code to load the value if it was passed in registers. CGF.EmitBlock(InRegBlock); // Work out the address of an argument register. llvm::Value *ScaledRegCount = CGF.Builder.CreateMul(RegCount, PaddedSizeV, "scaled_reg_count"); llvm::Value *RegBase = llvm::ConstantInt::get(IndexTy, RegSaveIndex * PaddedSize.getQuantity() + RegPadding.getQuantity()); llvm::Value *RegOffset = CGF.Builder.CreateAdd(ScaledRegCount, RegBase, "reg_offset"); Address RegSaveAreaPtr = CGF.Builder.CreateStructGEP(VAListAddr, 3, "reg_save_area_ptr"); llvm::Value *RegSaveArea = CGF.Builder.CreateLoad(RegSaveAreaPtr, "reg_save_area"); Address RawRegAddr(CGF.Builder.CreateGEP(RegSaveArea, RegOffset, "raw_reg_addr"), PaddedSize); Address RegAddr = CGF.Builder.CreateElementBitCast(RawRegAddr, DirectTy, "reg_addr"); // Update the register count llvm::Value *One = llvm::ConstantInt::get(IndexTy, 1); llvm::Value *NewRegCount = CGF.Builder.CreateAdd(RegCount, One, "reg_count"); CGF.Builder.CreateStore(NewRegCount, RegCountPtr); CGF.EmitBranch(ContBlock); // Emit code to load the value if it was passed in memory. CGF.EmitBlock(InMemBlock); // Work out the address of a stack argument. Address OverflowArgAreaPtr = CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_ptr"); Address OverflowArgArea = Address(CGF.Builder.CreateLoad(OverflowArgAreaPtr, "overflow_arg_area"), PaddedSize); Address RawMemAddr = CGF.Builder.CreateConstByteGEP(OverflowArgArea, Padding, "raw_mem_addr"); Address MemAddr = CGF.Builder.CreateElementBitCast(RawMemAddr, DirectTy, "mem_addr"); // Update overflow_arg_area_ptr pointer llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP(OverflowArgArea.getPointer(), PaddedSizeV, "overflow_arg_area"); CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); CGF.EmitBranch(ContBlock); // Return the appropriate result. CGF.EmitBlock(ContBlock); Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock, MemAddr, InMemBlock, "va_arg.addr"); if (IsIndirect) ResAddr = Address(CGF.Builder.CreateLoad(ResAddr, "indirect_arg"), TyInfo.second); return ResAddr; } ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); if (isVectorArgumentType(RetTy)) return ABIArgInfo::getDirect(); if (isCompoundType(RetTy) || getContext().getTypeSize(RetTy) > 64) return getNaturalAlignIndirect(RetTy); return (isPromotableIntegerType(RetTy) ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty) const { // Handle the generic C++ ABI. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Integers and enums are extended to full register width. if (isPromotableIntegerType(Ty)) return ABIArgInfo::getExtend(Ty); // Handle vector types and vector-like structure types. Note that // as opposed to float-like structure types, we do not allow any // padding for vector-like structures, so verify the sizes match. uint64_t Size = getContext().getTypeSize(Ty); QualType SingleElementTy = GetSingleElementType(Ty); if (isVectorArgumentType(SingleElementTy) && getContext().getTypeSize(SingleElementTy) == Size) return ABIArgInfo::getDirect(CGT.ConvertType(SingleElementTy)); // Values that are not 1, 2, 4 or 8 bytes in size are passed indirectly. if (Size != 8 && Size != 16 && Size != 32 && Size != 64) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); // Handle small structures. if (const RecordType *RT = Ty->getAs()) { // Structures with flexible arrays have variable length, so really // fail the size test above. const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); // The structure is passed as an unextended integer, a float, or a double. llvm::Type *PassTy; if (isFPArgumentType(SingleElementTy)) { assert(Size == 32 || Size == 64); if (Size == 32) PassTy = llvm::Type::getFloatTy(getVMContext()); else PassTy = llvm::Type::getDoubleTy(getVMContext()); } else PassTy = llvm::IntegerType::get(getVMContext(), Size); return ABIArgInfo::getDirect(PassTy); } // Non-structure compounds are passed indirectly. if (isCompoundType(Ty)) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); return ABIArgInfo::getDirect(nullptr); } //===----------------------------------------------------------------------===// // MSP430 ABI Implementation //===----------------------------------------------------------------------===// namespace { class MSP430TargetCodeGenInfo : public TargetCodeGenInfo { public: MSP430TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; }; } void MSP430TargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { if (GV->isDeclaration()) return; if (const FunctionDecl *FD = dyn_cast_or_null(D)) { const auto *InterruptAttr = FD->getAttr(); if (!InterruptAttr) return; // Handle 'interrupt' attribute: llvm::Function *F = cast(GV); // Step 1: Set ISR calling convention. F->setCallingConv(llvm::CallingConv::MSP430_INTR); // Step 2: Add attributes goodness. F->addFnAttr(llvm::Attribute::NoInline); F->addFnAttr("interrupt", llvm::utostr(InterruptAttr->getNumber())); } } //===----------------------------------------------------------------------===// // MIPS ABI Implementation. This works for both little-endian and // big-endian variants. //===----------------------------------------------------------------------===// namespace { class MipsABIInfo : public ABIInfo { bool IsO32; unsigned MinABIStackAlignInBytes, StackAlignInBytes; void CoerceToIntArgs(uint64_t TySize, SmallVectorImpl &ArgList) const; llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const; llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const; llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const; public: MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) : ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8), StackAlignInBytes(IsO32 ? 8 : 16) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; ABIArgInfo extendType(QualType Ty) const; }; class MIPSTargetCodeGenInfo : public TargetCodeGenInfo { unsigned SizeOfUnwindException; public: MIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32) : TargetCodeGenInfo(new MipsABIInfo(CGT, IsO32)), SizeOfUnwindException(IsO32 ? 24 : 32) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { return 29; } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; llvm::Function *Fn = cast(GV); if (FD->hasAttr()) Fn->addFnAttr("long-call"); else if (FD->hasAttr()) Fn->addFnAttr("short-call"); // Other attributes do not have a meaning for declarations. if (GV->isDeclaration()) return; if (FD->hasAttr()) { Fn->addFnAttr("mips16"); } else if (FD->hasAttr()) { Fn->addFnAttr("nomips16"); } if (FD->hasAttr()) Fn->addFnAttr("micromips"); else if (FD->hasAttr()) Fn->addFnAttr("nomicromips"); const MipsInterruptAttr *Attr = FD->getAttr(); if (!Attr) return; const char *Kind; switch (Attr->getInterrupt()) { case MipsInterruptAttr::eic: Kind = "eic"; break; case MipsInterruptAttr::sw0: Kind = "sw0"; break; case MipsInterruptAttr::sw1: Kind = "sw1"; break; case MipsInterruptAttr::hw0: Kind = "hw0"; break; case MipsInterruptAttr::hw1: Kind = "hw1"; break; case MipsInterruptAttr::hw2: Kind = "hw2"; break; case MipsInterruptAttr::hw3: Kind = "hw3"; break; case MipsInterruptAttr::hw4: Kind = "hw4"; break; case MipsInterruptAttr::hw5: Kind = "hw5"; break; } Fn->addFnAttr("interrupt", Kind); } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; unsigned getSizeOfUnwindException() const override { return SizeOfUnwindException; } }; } void MipsABIInfo::CoerceToIntArgs( uint64_t TySize, SmallVectorImpl &ArgList) const { llvm::IntegerType *IntTy = llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8); // Add (TySize / MinABIStackAlignInBytes) args of IntTy. for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N) ArgList.push_back(IntTy); // If necessary, add one more integer type to ArgList. unsigned R = TySize % (MinABIStackAlignInBytes * 8); if (R) ArgList.push_back(llvm::IntegerType::get(getVMContext(), R)); } // In N32/64, an aligned double precision floating point field is passed in // a register. llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const { SmallVector ArgList, IntArgList; if (IsO32) { CoerceToIntArgs(TySize, ArgList); return llvm::StructType::get(getVMContext(), ArgList); } if (Ty->isComplexType()) return CGT.ConvertType(Ty); const RecordType *RT = Ty->getAs(); // Unions/vectors are passed in integer registers. if (!RT || !RT->isStructureOrClassType()) { CoerceToIntArgs(TySize, ArgList); return llvm::StructType::get(getVMContext(), ArgList); } const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); assert(!(TySize % 8) && "Size of structure must be multiple of 8."); uint64_t LastOffset = 0; unsigned idx = 0; llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64); // Iterate over fields in the struct/class and check if there are any aligned // double fields. for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { const QualType Ty = i->getType(); const BuiltinType *BT = Ty->getAs(); if (!BT || BT->getKind() != BuiltinType::Double) continue; uint64_t Offset = Layout.getFieldOffset(idx); if (Offset % 64) // Ignore doubles that are not aligned. continue; // Add ((Offset - LastOffset) / 64) args of type i64. for (unsigned j = (Offset - LastOffset) / 64; j > 0; --j) ArgList.push_back(I64); // Add double type. ArgList.push_back(llvm::Type::getDoubleTy(getVMContext())); LastOffset = Offset + 64; } CoerceToIntArgs(TySize - LastOffset, IntArgList); ArgList.append(IntArgList.begin(), IntArgList.end()); return llvm::StructType::get(getVMContext(), ArgList); } llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset, uint64_t Offset) const { if (OrigOffset + MinABIStackAlignInBytes > Offset) return nullptr; return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8); } ABIArgInfo MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { Ty = useFirstFieldIfTransparentUnion(Ty); uint64_t OrigOffset = Offset; uint64_t TySize = getContext().getTypeSize(Ty); uint64_t Align = getContext().getTypeAlign(Ty) / 8; Align = std::min(std::max(Align, (uint64_t)MinABIStackAlignInBytes), (uint64_t)StackAlignInBytes); unsigned CurrOffset = llvm::alignTo(Offset, Align); Offset = CurrOffset + llvm::alignTo(TySize, Align * 8) / 8; if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) { // Ignore empty aggregates. if (TySize == 0) return ABIArgInfo::getIgnore(); if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { Offset = OrigOffset + MinABIStackAlignInBytes; return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); } // If we have reached here, aggregates are passed directly by coercing to // another structure type. Padding is inserted if the offset of the // aggregate is unaligned. ABIArgInfo ArgInfo = ABIArgInfo::getDirect(HandleAggregates(Ty, TySize), 0, getPaddingType(OrigOffset, CurrOffset)); ArgInfo.setInReg(true); return ArgInfo; } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // All integral types are promoted to the GPR width. if (Ty->isIntegralOrEnumerationType()) return extendType(Ty); return ABIArgInfo::getDirect( nullptr, 0, IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset)); } llvm::Type* MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const { const RecordType *RT = RetTy->getAs(); SmallVector RTList; if (RT && RT->isStructureOrClassType()) { const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); unsigned FieldCnt = Layout.getFieldCount(); // N32/64 returns struct/classes in floating point registers if the // following conditions are met: // 1. The size of the struct/class is no larger than 128-bit. // 2. The struct/class has one or two fields all of which are floating // point types. // 3. The offset of the first field is zero (this follows what gcc does). // // Any other composite results are returned in integer registers. // if (FieldCnt && (FieldCnt <= 2) && !Layout.getFieldOffset(0)) { RecordDecl::field_iterator b = RD->field_begin(), e = RD->field_end(); for (; b != e; ++b) { const BuiltinType *BT = b->getType()->getAs(); if (!BT || !BT->isFloatingPoint()) break; RTList.push_back(CGT.ConvertType(b->getType())); } if (b == e) return llvm::StructType::get(getVMContext(), RTList, RD->hasAttr()); RTList.clear(); } } CoerceToIntArgs(Size, RTList); return llvm::StructType::get(getVMContext(), RTList); } ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { uint64_t Size = getContext().getTypeSize(RetTy); if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // O32 doesn't treat zero-sized structs differently from other structs. // However, N32/N64 ignores zero sized return values. if (!IsO32 && Size == 0) return ABIArgInfo::getIgnore(); if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) { if (Size <= 128) { if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirect(); // O32 returns integer vectors in registers and N32/N64 returns all small // aggregates in registers. if (!IsO32 || (RetTy->isVectorType() && !RetTy->hasFloatingRepresentation())) { ABIArgInfo ArgInfo = ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); ArgInfo.setInReg(true); return ArgInfo; } } return getNaturalAlignIndirect(RetTy); } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); if (RetTy->isPromotableIntegerType()) return ABIArgInfo::getExtend(RetTy); if ((RetTy->isUnsignedIntegerOrEnumerationType() || RetTy->isSignedIntegerOrEnumerationType()) && Size == 32 && !IsO32) return ABIArgInfo::getSignExtend(RetTy); return ABIArgInfo::getDirect(); } void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const { ABIArgInfo &RetInfo = FI.getReturnInfo(); if (!getCXXABI().classifyReturnType(FI)) RetInfo = classifyReturnType(FI.getReturnType()); // Check if a pointer to an aggregate is passed as a hidden argument. uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0; for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type, Offset); } Address MipsABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType OrigTy) const { QualType Ty = OrigTy; // Integer arguments are promoted to 32-bit on O32 and 64-bit on N32/N64. // Pointers are also promoted in the same way but this only matters for N32. unsigned SlotSizeInBits = IsO32 ? 32 : 64; unsigned PtrWidth = getTarget().getPointerWidth(0); bool DidPromote = false; if ((Ty->isIntegerType() && getContext().getIntWidth(Ty) < SlotSizeInBits) || (Ty->isPointerType() && PtrWidth < SlotSizeInBits)) { DidPromote = true; Ty = getContext().getIntTypeForBitwidth(SlotSizeInBits, Ty->isSignedIntegerType()); } auto TyInfo = getContext().getTypeInfoInChars(Ty); // The alignment of things in the argument area is never larger than // StackAlignInBytes. TyInfo.second = std::min(TyInfo.second, CharUnits::fromQuantity(StackAlignInBytes)); // MinABIStackAlignInBytes is the size of argument slots on the stack. CharUnits ArgSlotSize = CharUnits::fromQuantity(MinABIStackAlignInBytes); Address Addr = emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, TyInfo, ArgSlotSize, /*AllowHigherAlign*/ true); // If there was a promotion, "unpromote" into a temporary. // TODO: can we just use a pointer into a subset of the original slot? if (DidPromote) { Address Temp = CGF.CreateMemTemp(OrigTy, "vaarg.promotion-temp"); llvm::Value *Promoted = CGF.Builder.CreateLoad(Addr); // Truncate down to the right width. llvm::Type *IntTy = (OrigTy->isIntegerType() ? Temp.getElementType() : CGF.IntPtrTy); llvm::Value *V = CGF.Builder.CreateTrunc(Promoted, IntTy); if (OrigTy->isPointerType()) V = CGF.Builder.CreateIntToPtr(V, Temp.getElementType()); CGF.Builder.CreateStore(V, Temp); Addr = Temp; } return Addr; } ABIArgInfo MipsABIInfo::extendType(QualType Ty) const { int TySize = getContext().getTypeSize(Ty); // MIPS64 ABI requires unsigned 32 bit integers to be sign extended. if (Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32) return ABIArgInfo::getSignExtend(Ty); return ABIArgInfo::getExtend(Ty); } bool MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { // This information comes from gcc's implementation, which seems to // as canonical as it gets. // Everything on MIPS is 4 bytes. Double-precision FP registers // are aliased to pairs of single-precision FP registers. llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4); // 0-31 are the general purpose registers, $0 - $31. // 32-63 are the floating-point registers, $f0 - $f31. // 64 and 65 are the multiply/divide registers, $hi and $lo. // 66 is the (notional, I think) register for signal-handler return. AssignToArrayRange(CGF.Builder, Address, Four8, 0, 65); // 67-74 are the floating-point status registers, $fcc0 - $fcc7. // They are one bit wide and ignored here. // 80-111 are the coprocessor 0 registers, $c0r0 - $c0r31. // (coprocessor 1 is the FP unit) // 112-143 are the coprocessor 2 registers, $c2r0 - $c2r31. // 144-175 are the coprocessor 3 registers, $c3r0 - $c3r31. // 176-181 are the DSP accumulator registers. AssignToArrayRange(CGF.Builder, Address, Four8, 80, 181); return false; } //===----------------------------------------------------------------------===// // AVR ABI Implementation. //===----------------------------------------------------------------------===// namespace { class AVRTargetCodeGenInfo : public TargetCodeGenInfo { public: AVRTargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) { } void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { if (GV->isDeclaration()) return; const auto *FD = dyn_cast_or_null(D); if (!FD) return; auto *Fn = cast(GV); if (FD->getAttr()) Fn->addFnAttr("interrupt"); if (FD->getAttr()) Fn->addFnAttr("signal"); } }; } //===----------------------------------------------------------------------===// // TCE ABI Implementation (see http://tce.cs.tut.fi). Uses mostly the defaults. // Currently subclassed only to implement custom OpenCL C function attribute // handling. //===----------------------------------------------------------------------===// namespace { class TCETargetCodeGenInfo : public DefaultTargetCodeGenInfo { public: TCETargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; }; void TCETargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { if (GV->isDeclaration()) return; const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; llvm::Function *F = cast(GV); if (M.getLangOpts().OpenCL) { if (FD->hasAttr()) { // OpenCL C Kernel functions are not subject to inlining F->addFnAttr(llvm::Attribute::NoInline); const ReqdWorkGroupSizeAttr *Attr = FD->getAttr(); if (Attr) { // Convert the reqd_work_group_size() attributes to metadata. llvm::LLVMContext &Context = F->getContext(); llvm::NamedMDNode *OpenCLMetadata = M.getModule().getOrInsertNamedMetadata( "opencl.kernel_wg_size_info"); SmallVector Operands; Operands.push_back(llvm::ConstantAsMetadata::get(F)); Operands.push_back( llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue( M.Int32Ty, llvm::APInt(32, Attr->getXDim())))); Operands.push_back( llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue( M.Int32Ty, llvm::APInt(32, Attr->getYDim())))); Operands.push_back( llvm::ConstantAsMetadata::get(llvm::Constant::getIntegerValue( M.Int32Ty, llvm::APInt(32, Attr->getZDim())))); // Add a boolean constant operand for "required" (true) or "hint" // (false) for implementing the work_group_size_hint attr later. // Currently always true as the hint is not yet implemented. Operands.push_back( llvm::ConstantAsMetadata::get(llvm::ConstantInt::getTrue(Context))); OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Operands)); } } } } } //===----------------------------------------------------------------------===// // Hexagon ABI Implementation //===----------------------------------------------------------------------===// namespace { class HexagonABIInfo : public ABIInfo { public: HexagonABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} private: ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class HexagonTargetCodeGenInfo : public TargetCodeGenInfo { public: HexagonTargetCodeGenInfo(CodeGenTypes &CGT) :TargetCodeGenInfo(new HexagonABIInfo(CGT)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 29; } }; } void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const { if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type); } ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const { if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Ignore empty records. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); uint64_t Size = getContext().getTypeSize(Ty); if (Size > 64) return getNaturalAlignIndirect(Ty, /*ByVal=*/true); // Pass in the smallest viable integer type. else if (Size > 32) return ABIArgInfo::getDirect(llvm::Type::getInt64Ty(getVMContext())); else if (Size > 16) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); else if (Size > 8) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); else return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); } ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); // Large vector types should be returned via memory. if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 64) return getNaturalAlignIndirect(RetTy); if (!isAggregateTypeForABI(RetTy)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = RetTy->getAs()) RetTy = EnumTy->getDecl()->getIntegerType(); return (RetTy->isPromotableIntegerType() ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Aggregates <= 8 bytes are returned in r0; other aggregates // are returned indirectly. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 64) { // Return in the smallest viable integer type. if (Size <= 8) return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); if (Size <= 16) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); if (Size <= 32) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); return ABIArgInfo::getDirect(llvm::Type::getInt64Ty(getVMContext())); } return getNaturalAlignIndirect(RetTy, /*ByVal=*/true); } Address HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { // FIXME: Someone needs to audit that this handle alignment correctly. return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(4), /*AllowHigherAlign*/ true); } //===----------------------------------------------------------------------===// // Lanai ABI Implementation //===----------------------------------------------------------------------===// namespace { class LanaiABIInfo : public DefaultABIInfo { public: LanaiABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} bool shouldUseInReg(QualType Ty, CCState &State) const; void computeInfo(CGFunctionInfo &FI) const override { CCState State(FI); // Lanai uses 4 registers to pass arguments unless the function has the // regparm attribute set. if (FI.getHasRegParm()) { State.FreeRegs = FI.getRegParm(); } else { State.FreeRegs = 4; } if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) I.info = classifyArgumentType(I.type, State); } ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, CCState &State) const; ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; }; } // end anonymous namespace bool LanaiABIInfo::shouldUseInReg(QualType Ty, CCState &State) const { unsigned Size = getContext().getTypeSize(Ty); unsigned SizeInRegs = llvm::alignTo(Size, 32U) / 32U; if (SizeInRegs == 0) return false; if (SizeInRegs > State.FreeRegs) { State.FreeRegs = 0; return false; } State.FreeRegs -= SizeInRegs; return true; } ABIArgInfo LanaiABIInfo::getIndirectResult(QualType Ty, bool ByVal, CCState &State) const { if (!ByVal) { if (State.FreeRegs) { --State.FreeRegs; // Non-byval indirects just use one pointer. return getNaturalAlignIndirectInReg(Ty); } return getNaturalAlignIndirect(Ty, false); } // Compute the byval alignment. const unsigned MinABIStackAlignInBytes = 4; unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true, /*Realign=*/TypeAlign > MinABIStackAlignInBytes); } ABIArgInfo LanaiABIInfo::classifyArgumentType(QualType Ty, CCState &State) const { // Check with the C++ ABI first. const RecordType *RT = Ty->getAs(); if (RT) { CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); if (RAA == CGCXXABI::RAA_Indirect) { return getIndirectResult(Ty, /*ByVal=*/false, State); } else if (RAA == CGCXXABI::RAA_DirectInMemory) { return getNaturalAlignIndirect(Ty, /*ByRef=*/true); } } if (isAggregateTypeForABI(Ty)) { // Structures with flexible arrays are always indirect. if (RT && RT->getDecl()->hasFlexibleArrayMember()) return getIndirectResult(Ty, /*ByVal=*/true, State); // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); llvm::LLVMContext &LLVMContext = getVMContext(); unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; if (SizeInRegs <= State.FreeRegs) { llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); SmallVector Elements(SizeInRegs, Int32); llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); State.FreeRegs -= SizeInRegs; return ABIArgInfo::getDirectInReg(Result); } else { State.FreeRegs = 0; } return getIndirectResult(Ty, true, State); } // Treat an enum type as its underlying type. if (const auto *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); bool InReg = shouldUseInReg(Ty, State); if (Ty->isPromotableIntegerType()) { if (InReg) return ABIArgInfo::getDirectInReg(); return ABIArgInfo::getExtend(Ty); } if (InReg) return ABIArgInfo::getDirectInReg(); return ABIArgInfo::getDirect(); } namespace { class LanaiTargetCodeGenInfo : public TargetCodeGenInfo { public: LanaiTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new LanaiABIInfo(CGT)) {} }; } //===----------------------------------------------------------------------===// // AMDGPU ABI Implementation //===----------------------------------------------------------------------===// namespace { class AMDGPUABIInfo final : public DefaultABIInfo { private: static const unsigned MaxNumRegsForArgsRet = 16; unsigned numRegsForType(QualType Ty) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const override; // Coerce HIP pointer arguments from generic pointers to global ones. llvm::Type *coerceKernelArgumentType(llvm::Type *Ty, unsigned FromAS, unsigned ToAS) const { // Structure types. if (auto STy = dyn_cast(Ty)) { SmallVector EltTys; bool Changed = false; for (auto T : STy->elements()) { auto NT = coerceKernelArgumentType(T, FromAS, ToAS); EltTys.push_back(NT); Changed |= (NT != T); } // Skip if there is no change in element types. if (!Changed) return STy; if (STy->hasName()) return llvm::StructType::create( EltTys, (STy->getName() + ".coerce").str(), STy->isPacked()); return llvm::StructType::get(getVMContext(), EltTys, STy->isPacked()); } // Arrary types. if (auto ATy = dyn_cast(Ty)) { auto T = ATy->getElementType(); auto NT = coerceKernelArgumentType(T, FromAS, ToAS); // Skip if there is no change in that element type. if (NT == T) return ATy; return llvm::ArrayType::get(NT, ATy->getNumElements()); } // Single value types. if (Ty->isPointerTy() && Ty->getPointerAddressSpace() == FromAS) return llvm::PointerType::get( cast(Ty)->getElementType(), ToAS); return Ty; } public: explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyKernelArgumentType(QualType Ty) const; ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegsLeft) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; bool AMDGPUABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { return true; } bool AMDGPUABIInfo::isHomogeneousAggregateSmallEnough( const Type *Base, uint64_t Members) const { uint32_t NumRegs = (getContext().getTypeSize(Base) + 31) / 32; // Homogeneous Aggregates may occupy at most 16 registers. return Members * NumRegs <= MaxNumRegsForArgsRet; } /// Estimate number of registers the type will use when passed in registers. unsigned AMDGPUABIInfo::numRegsForType(QualType Ty) const { unsigned NumRegs = 0; if (const VectorType *VT = Ty->getAs()) { // Compute from the number of elements. The reported size is based on the // in-memory size, which includes the padding 4th element for 3-vectors. QualType EltTy = VT->getElementType(); unsigned EltSize = getContext().getTypeSize(EltTy); // 16-bit element vectors should be passed as packed. if (EltSize == 16) return (VT->getNumElements() + 1) / 2; unsigned EltNumRegs = (EltSize + 31) / 32; return EltNumRegs * VT->getNumElements(); } if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); assert(!RD->hasFlexibleArrayMember()); for (const FieldDecl *Field : RD->fields()) { QualType FieldTy = Field->getType(); NumRegs += numRegsForType(FieldTy); } return NumRegs; } return (getContext().getTypeSize(Ty) + 31) / 32; } void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const { llvm::CallingConv::ID CC = FI.getCallingConvention(); if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); unsigned NumRegsLeft = MaxNumRegsForArgsRet; for (auto &Arg : FI.arguments()) { if (CC == llvm::CallingConv::AMDGPU_KERNEL) { Arg.info = classifyKernelArgumentType(Arg.type); } else { Arg.info = classifyArgumentType(Arg.type, NumRegsLeft); } } } Address AMDGPUABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { llvm_unreachable("AMDGPU does not support varargs"); } ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const { if (isAggregateTypeForABI(RetTy)) { // Records with non-trivial destructors/copy-constructors should not be // returned by value. if (!getRecordArgABI(RetTy, getCXXABI())) { // Ignore empty structs/unions. if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); // Lower single-element structs to just return a regular value. if (const Type *SeltTy = isSingleElementStruct(RetTy, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); if (const RecordType *RT = RetTy->getAs()) { const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return DefaultABIInfo::classifyReturnType(RetTy); } // Pack aggregates <= 4 bytes into single VGPR or pair. uint64_t Size = getContext().getTypeSize(RetTy); if (Size <= 16) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); if (Size <= 32) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); if (Size <= 64) { llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2)); } if (numRegsForType(RetTy) <= MaxNumRegsForArgsRet) return ABIArgInfo::getDirect(); } } // Otherwise just do the default thing. return DefaultABIInfo::classifyReturnType(RetTy); } /// For kernels all parameters are really passed in a special buffer. It doesn't /// make sense to pass anything byval, so everything must be direct. ABIArgInfo AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); // TODO: Can we omit empty structs? llvm::Type *LTy = nullptr; if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) LTy = CGT.ConvertType(QualType(SeltTy, 0)); if (getContext().getLangOpts().HIP) { if (!LTy) LTy = CGT.ConvertType(Ty); LTy = coerceKernelArgumentType( LTy, /*FromAS=*/getContext().getTargetAddressSpace(LangAS::Default), /*ToAS=*/getContext().getTargetAddressSpace(LangAS::cuda_device)); } // If we set CanBeFlattened to true, CodeGen will expand the struct to its // individual elements, which confuses the Clover OpenCL backend; therefore we // have to set it to false here. Other args of getDirect() are just defaults. return ABIArgInfo::getDirect(LTy, 0, nullptr, false); } ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, unsigned &NumRegsLeft) const { assert(NumRegsLeft <= MaxNumRegsForArgsRet && "register estimate underflow"); Ty = useFirstFieldIfTransparentUnion(Ty); if (isAggregateTypeForABI(Ty)) { // Records with non-trivial destructors/copy-constructors should not be // passed by value. if (auto RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); // Lower single-element structs to just pass a regular value. TODO: We // could do reasonable-size multiple-element structs too, using getExpand(), // though watch out for things like bitfields. if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); if (RD->hasFlexibleArrayMember()) return DefaultABIInfo::classifyArgumentType(Ty); } // Pack aggregates <= 8 bytes into single VGPR or pair. uint64_t Size = getContext().getTypeSize(Ty); if (Size <= 64) { unsigned NumRegs = (Size + 31) / 32; NumRegsLeft -= std::min(NumRegsLeft, NumRegs); if (Size <= 16) return ABIArgInfo::getDirect(llvm::Type::getInt16Ty(getVMContext())); if (Size <= 32) return ABIArgInfo::getDirect(llvm::Type::getInt32Ty(getVMContext())); // XXX: Should this be i64 instead, and should the limit increase? llvm::Type *I32Ty = llvm::Type::getInt32Ty(getVMContext()); return ABIArgInfo::getDirect(llvm::ArrayType::get(I32Ty, 2)); } if (NumRegsLeft > 0) { unsigned NumRegs = numRegsForType(Ty); if (NumRegsLeft >= NumRegs) { NumRegsLeft -= NumRegs; return ABIArgInfo::getDirect(); } } } // Otherwise just do the default thing. ABIArgInfo ArgInfo = DefaultABIInfo::classifyArgumentType(Ty); if (!ArgInfo.isIndirect()) { unsigned NumRegs = numRegsForType(Ty); NumRegsLeft -= std::min(NumRegs, NumRegsLeft); } return ArgInfo; } class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo { public: AMDGPUTargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new AMDGPUABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; unsigned getOpenCLKernelCallingConv() const override; llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM, llvm::PointerType *T, QualType QT) const override; LangAS getASTAllocaAddressSpace() const override { return getLangASFromTargetAS( getABIInfo().getDataLayout().getAllocaAddrSpace()); } LangAS getGlobalVarAddressSpace(CodeGenModule &CGM, const VarDecl *D) const override; llvm::SyncScope::ID getLLVMSyncScopeID(const LangOptions &LangOpts, SyncScope Scope, llvm::AtomicOrdering Ordering, llvm::LLVMContext &Ctx) const override; llvm::Function * createEnqueuedBlockKernel(CodeGenFunction &CGF, llvm::Function *BlockInvokeFunc, llvm::Value *BlockLiteral) const override; bool shouldEmitStaticExternCAliases() const override; void setCUDAKernelCallingConvention(const FunctionType *&FT) const override; }; } static bool requiresAMDGPUProtectedVisibility(const Decl *D, llvm::GlobalValue *GV) { if (GV->getVisibility() != llvm::GlobalValue::HiddenVisibility) return false; return D->hasAttr() || (isa(D) && D->hasAttr()) || (isa(D) && (D->hasAttr() || D->hasAttr() || D->hasAttr())); } static bool requiresAMDGPUDefaultVisibility(const Decl *D, llvm::GlobalValue *GV) { if (GV->getVisibility() != llvm::GlobalValue::HiddenVisibility) return false; return isa(D) && D->hasAttr(); } void AMDGPUTargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { if (requiresAMDGPUDefaultVisibility(D, GV)) { GV->setVisibility(llvm::GlobalValue::DefaultVisibility); GV->setDSOLocal(false); } else if (requiresAMDGPUProtectedVisibility(D, GV)) { GV->setVisibility(llvm::GlobalValue::ProtectedVisibility); GV->setDSOLocal(true); } if (GV->isDeclaration()) return; const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; llvm::Function *F = cast(GV); const auto *ReqdWGS = M.getLangOpts().OpenCL ? FD->getAttr() : nullptr; const bool IsOpenCLKernel = M.getLangOpts().OpenCL && FD->hasAttr(); const bool IsHIPKernel = M.getLangOpts().HIP && FD->hasAttr(); if ((IsOpenCLKernel || IsHIPKernel) && (M.getTriple().getOS() == llvm::Triple::AMDHSA)) F->addFnAttr("amdgpu-implicitarg-num-bytes", "56"); const auto *FlatWGS = FD->getAttr(); if (ReqdWGS || FlatWGS) { unsigned Min = 0; unsigned Max = 0; if (FlatWGS) { Min = FlatWGS->getMin() ->EvaluateKnownConstInt(M.getContext()) .getExtValue(); Max = FlatWGS->getMax() ->EvaluateKnownConstInt(M.getContext()) .getExtValue(); } if (ReqdWGS && Min == 0 && Max == 0) Min = Max = ReqdWGS->getXDim() * ReqdWGS->getYDim() * ReqdWGS->getZDim(); if (Min != 0) { assert(Min <= Max && "Min must be less than or equal Max"); std::string AttrVal = llvm::utostr(Min) + "," + llvm::utostr(Max); F->addFnAttr("amdgpu-flat-work-group-size", AttrVal); } else assert(Max == 0 && "Max must be zero"); } else if (IsOpenCLKernel || IsHIPKernel) { // By default, restrict the maximum size to a value specified by // --gpu-max-threads-per-block=n or its default value. std::string AttrVal = std::string("1,") + llvm::utostr(M.getLangOpts().GPUMaxThreadsPerBlock); F->addFnAttr("amdgpu-flat-work-group-size", AttrVal); } if (const auto *Attr = FD->getAttr()) { unsigned Min = Attr->getMin()->EvaluateKnownConstInt(M.getContext()).getExtValue(); unsigned Max = Attr->getMax() ? Attr->getMax() ->EvaluateKnownConstInt(M.getContext()) .getExtValue() : 0; if (Min != 0) { assert((Max == 0 || Min <= Max) && "Min must be less than or equal Max"); std::string AttrVal = llvm::utostr(Min); if (Max != 0) AttrVal = AttrVal + "," + llvm::utostr(Max); F->addFnAttr("amdgpu-waves-per-eu", AttrVal); } else assert(Max == 0 && "Max must be zero"); } if (const auto *Attr = FD->getAttr()) { unsigned NumSGPR = Attr->getNumSGPR(); if (NumSGPR != 0) F->addFnAttr("amdgpu-num-sgpr", llvm::utostr(NumSGPR)); } if (const auto *Attr = FD->getAttr()) { uint32_t NumVGPR = Attr->getNumVGPR(); if (NumVGPR != 0) F->addFnAttr("amdgpu-num-vgpr", llvm::utostr(NumVGPR)); } } unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const { return llvm::CallingConv::AMDGPU_KERNEL; } // Currently LLVM assumes null pointers always have value 0, // which results in incorrectly transformed IR. Therefore, instead of // emitting null pointers in private and local address spaces, a null // pointer in generic address space is emitted which is casted to a // pointer in local or private address space. llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer( const CodeGen::CodeGenModule &CGM, llvm::PointerType *PT, QualType QT) const { if (CGM.getContext().getTargetNullPointerValue(QT) == 0) return llvm::ConstantPointerNull::get(PT); auto &Ctx = CGM.getContext(); auto NPT = llvm::PointerType::get(PT->getElementType(), Ctx.getTargetAddressSpace(LangAS::opencl_generic)); return llvm::ConstantExpr::getAddrSpaceCast( llvm::ConstantPointerNull::get(NPT), PT); } LangAS AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, const VarDecl *D) const { assert(!CGM.getLangOpts().OpenCL && !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && "Address space agnostic languages only"); LangAS DefaultGlobalAS = getLangASFromTargetAS( CGM.getContext().getTargetAddressSpace(LangAS::opencl_global)); if (!D) return DefaultGlobalAS; LangAS AddrSpace = D->getType().getAddressSpace(); assert(AddrSpace == LangAS::Default || isTargetAddressSpace(AddrSpace)); if (AddrSpace != LangAS::Default) return AddrSpace; if (CGM.isTypeConstant(D->getType(), false)) { if (auto ConstAS = CGM.getTarget().getConstantAddressSpace()) return ConstAS.getValue(); } return DefaultGlobalAS; } llvm::SyncScope::ID AMDGPUTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts, SyncScope Scope, llvm::AtomicOrdering Ordering, llvm::LLVMContext &Ctx) const { std::string Name; switch (Scope) { case SyncScope::OpenCLWorkGroup: Name = "workgroup"; break; case SyncScope::OpenCLDevice: Name = "agent"; break; case SyncScope::OpenCLAllSVMDevices: Name = ""; break; case SyncScope::OpenCLSubGroup: Name = "wavefront"; } if (Ordering != llvm::AtomicOrdering::SequentiallyConsistent) { if (!Name.empty()) Name = Twine(Twine(Name) + Twine("-")).str(); Name = Twine(Twine(Name) + Twine("one-as")).str(); } return Ctx.getOrInsertSyncScopeID(Name); } bool AMDGPUTargetCodeGenInfo::shouldEmitStaticExternCAliases() const { return false; } void AMDGPUTargetCodeGenInfo::setCUDAKernelCallingConvention( const FunctionType *&FT) const { FT = getABIInfo().getContext().adjustFunctionType( FT, FT->getExtInfo().withCallingConv(CC_OpenCLKernel)); } //===----------------------------------------------------------------------===// // SPARC v8 ABI Implementation. // Based on the SPARC Compliance Definition version 2.4.1. // // Ensures that complex values are passed in registers. // namespace { class SparcV8ABIInfo : public DefaultABIInfo { public: SparcV8ABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} private: ABIArgInfo classifyReturnType(QualType RetTy) const; void computeInfo(CGFunctionInfo &FI) const override; }; } // end anonymous namespace ABIArgInfo SparcV8ABIInfo::classifyReturnType(QualType Ty) const { if (Ty->isAnyComplexType()) { return ABIArgInfo::getDirect(); } else { return DefaultABIInfo::classifyReturnType(Ty); } } void SparcV8ABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &Arg : FI.arguments()) Arg.info = classifyArgumentType(Arg.type); } namespace { class SparcV8TargetCodeGenInfo : public TargetCodeGenInfo { public: SparcV8TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new SparcV8ABIInfo(CGT)) {} }; } // end anonymous namespace //===----------------------------------------------------------------------===// // SPARC v9 ABI Implementation. // Based on the SPARC Compliance Definition version 2.4.1. // // Function arguments a mapped to a nominal "parameter array" and promoted to // registers depending on their type. Each argument occupies 8 or 16 bytes in // the array, structs larger than 16 bytes are passed indirectly. // // One case requires special care: // // struct mixed { // int i; // float f; // }; // // When a struct mixed is passed by value, it only occupies 8 bytes in the // parameter array, but the int is passed in an integer register, and the float // is passed in a floating point register. This is represented as two arguments // with the LLVM IR inreg attribute: // // declare void f(i32 inreg %i, float inreg %f) // // The code generator will only allocate 4 bytes from the parameter array for // the inreg arguments. All other arguments are allocated a multiple of 8 // bytes. // namespace { class SparcV9ABIInfo : public ABIInfo { public: SparcV9ABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} private: ABIArgInfo classifyType(QualType RetTy, unsigned SizeLimit) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; // Coercion type builder for structs passed in registers. The coercion type // serves two purposes: // // 1. Pad structs to a multiple of 64 bits, so they are passed 'left-aligned' // in registers. // 2. Expose aligned floating point elements as first-level elements, so the // code generator knows to pass them in floating point registers. // // We also compute the InReg flag which indicates that the struct contains // aligned 32-bit floats. // struct CoerceBuilder { llvm::LLVMContext &Context; const llvm::DataLayout &DL; SmallVector Elems; uint64_t Size; bool InReg; CoerceBuilder(llvm::LLVMContext &c, const llvm::DataLayout &dl) : Context(c), DL(dl), Size(0), InReg(false) {} // Pad Elems with integers until Size is ToSize. void pad(uint64_t ToSize) { assert(ToSize >= Size && "Cannot remove elements"); if (ToSize == Size) return; // Finish the current 64-bit word. uint64_t Aligned = llvm::alignTo(Size, 64); if (Aligned > Size && Aligned <= ToSize) { Elems.push_back(llvm::IntegerType::get(Context, Aligned - Size)); Size = Aligned; } // Add whole 64-bit words. while (Size + 64 <= ToSize) { Elems.push_back(llvm::Type::getInt64Ty(Context)); Size += 64; } // Final in-word padding. if (Size < ToSize) { Elems.push_back(llvm::IntegerType::get(Context, ToSize - Size)); Size = ToSize; } } // Add a floating point element at Offset. void addFloat(uint64_t Offset, llvm::Type *Ty, unsigned Bits) { // Unaligned floats are treated as integers. if (Offset % Bits) return; // The InReg flag is only required if there are any floats < 64 bits. if (Bits < 64) InReg = true; pad(Offset); Elems.push_back(Ty); Size = Offset + Bits; } // Add a struct type to the coercion type, starting at Offset (in bits). void addStruct(uint64_t Offset, llvm::StructType *StrTy) { const llvm::StructLayout *Layout = DL.getStructLayout(StrTy); for (unsigned i = 0, e = StrTy->getNumElements(); i != e; ++i) { llvm::Type *ElemTy = StrTy->getElementType(i); uint64_t ElemOffset = Offset + Layout->getElementOffsetInBits(i); switch (ElemTy->getTypeID()) { case llvm::Type::StructTyID: addStruct(ElemOffset, cast(ElemTy)); break; case llvm::Type::FloatTyID: addFloat(ElemOffset, ElemTy, 32); break; case llvm::Type::DoubleTyID: addFloat(ElemOffset, ElemTy, 64); break; case llvm::Type::FP128TyID: addFloat(ElemOffset, ElemTy, 128); break; case llvm::Type::PointerTyID: if (ElemOffset % 64 == 0) { pad(ElemOffset); Elems.push_back(ElemTy); Size += 64; } break; default: break; } } } // Check if Ty is a usable substitute for the coercion type. bool isUsableType(llvm::StructType *Ty) const { return llvm::makeArrayRef(Elems) == Ty->elements(); } // Get the coercion type as a literal struct type. llvm::Type *getType() const { if (Elems.size() == 1) return Elems.front(); else return llvm::StructType::get(Context, Elems); } }; }; } // end anonymous namespace ABIArgInfo SparcV9ABIInfo::classifyType(QualType Ty, unsigned SizeLimit) const { if (Ty->isVoidType()) return ABIArgInfo::getIgnore(); uint64_t Size = getContext().getTypeSize(Ty); // Anything too big to fit in registers is passed with an explicit indirect // pointer / sret pointer. if (Size > SizeLimit) return getNaturalAlignIndirect(Ty, /*ByVal=*/false); // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // Integer types smaller than a register are extended. if (Size < 64 && Ty->isIntegerType()) return ABIArgInfo::getExtend(Ty); // Other non-aggregates go in registers. if (!isAggregateTypeForABI(Ty)) return ABIArgInfo::getDirect(); // If a C++ object has either a non-trivial copy constructor or a non-trivial // destructor, it is passed with an explicit indirect pointer / sret pointer. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); // This is a small aggregate type that should be passed in registers. // Build a coercion type from the LLVM struct type. llvm::StructType *StrTy = dyn_cast(CGT.ConvertType(Ty)); if (!StrTy) return ABIArgInfo::getDirect(); CoerceBuilder CB(getVMContext(), getDataLayout()); CB.addStruct(0, StrTy); CB.pad(llvm::alignTo(CB.DL.getTypeSizeInBits(StrTy), 64)); // Try to use the original type for coercion. llvm::Type *CoerceTy = CB.isUsableType(StrTy) ? StrTy : CB.getType(); if (CB.InReg) return ABIArgInfo::getDirectInReg(CoerceTy); else return ABIArgInfo::getDirect(CoerceTy); } Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { ABIArgInfo AI = classifyType(Ty, 16 * 8); llvm::Type *ArgTy = CGT.ConvertType(Ty); if (AI.canHaveCoerceToType() && !AI.getCoerceToType()) AI.setCoerceToType(ArgTy); CharUnits SlotSize = CharUnits::fromQuantity(8); CGBuilderTy &Builder = CGF.Builder; Address Addr(Builder.CreateLoad(VAListAddr, "ap.cur"), SlotSize); llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy); auto TypeInfo = getContext().getTypeInfoInChars(Ty); Address ArgAddr = Address::invalid(); CharUnits Stride; switch (AI.getKind()) { case ABIArgInfo::Expand: case ABIArgInfo::CoerceAndExpand: case ABIArgInfo::InAlloca: llvm_unreachable("Unsupported ABI kind for va_arg"); case ABIArgInfo::Extend: { Stride = SlotSize; CharUnits Offset = SlotSize - TypeInfo.first; ArgAddr = Builder.CreateConstInBoundsByteGEP(Addr, Offset, "extend"); break; } case ABIArgInfo::Direct: { auto AllocSize = getDataLayout().getTypeAllocSize(AI.getCoerceToType()); Stride = CharUnits::fromQuantity(AllocSize).alignTo(SlotSize); ArgAddr = Addr; break; } case ABIArgInfo::Indirect: Stride = SlotSize; ArgAddr = Builder.CreateElementBitCast(Addr, ArgPtrTy, "indirect"); ArgAddr = Address(Builder.CreateLoad(ArgAddr, "indirect.arg"), TypeInfo.second); break; case ABIArgInfo::Ignore: return Address(llvm::UndefValue::get(ArgPtrTy), TypeInfo.second); } // Update VAList. Address NextPtr = Builder.CreateConstInBoundsByteGEP(Addr, Stride, "ap.next"); Builder.CreateStore(NextPtr.getPointer(), VAListAddr); return Builder.CreateBitCast(ArgAddr, ArgPtrTy, "arg.addr"); } void SparcV9ABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyType(FI.getReturnType(), 32 * 8); for (auto &I : FI.arguments()) I.info = classifyType(I.type, 16 * 8); } namespace { class SparcV9TargetCodeGenInfo : public TargetCodeGenInfo { public: SparcV9TargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 14; } bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; }; } // end anonymous namespace bool SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const { // This is calculated from the LLVM and GCC tables and verified // against gcc output. AFAIK all ABIs use the same encoding. CodeGen::CGBuilderTy &Builder = CGF.Builder; llvm::IntegerType *i8 = CGF.Int8Ty; llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); // 0-31: the 8-byte general-purpose registers AssignToArrayRange(Builder, Address, Eight8, 0, 31); // 32-63: f0-31, the 4-byte floating-point registers AssignToArrayRange(Builder, Address, Four8, 32, 63); // Y = 64 // PSR = 65 // WIM = 66 // TBR = 67 // PC = 68 // NPC = 69 // FSR = 70 // CSR = 71 AssignToArrayRange(Builder, Address, Eight8, 64, 71); // 72-87: d0-15, the 8-byte floating-point registers AssignToArrayRange(Builder, Address, Eight8, 72, 87); return false; } // ARC ABI implementation. namespace { class ARCABIInfo : public DefaultABIInfo { public: using DefaultABIInfo::DefaultABIInfo; private: Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const { if (!State.FreeRegs) return; if (Info.isIndirect() && Info.getInReg()) State.FreeRegs--; else if (Info.isDirect() && Info.getInReg()) { unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32; if (sz < State.FreeRegs) State.FreeRegs -= sz; else State.FreeRegs = 0; } } void computeInfo(CGFunctionInfo &FI) const override { CCState State(FI); // ARC uses 8 registers to pass arguments. State.FreeRegs = 8; if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); updateState(FI.getReturnInfo(), FI.getReturnType(), State); for (auto &I : FI.arguments()) { I.info = classifyArgumentType(I.type, State.FreeRegs); updateState(I.info, I.type, State); } } ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const; ABIArgInfo getIndirectByValue(QualType Ty) const; ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const; ABIArgInfo classifyReturnType(QualType RetTy) const; }; class ARCTargetCodeGenInfo : public TargetCodeGenInfo { public: ARCTargetCodeGenInfo(CodeGenTypes &CGT) : TargetCodeGenInfo(new ARCABIInfo(CGT)) {} }; ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) : getNaturalAlignIndirect(Ty, false); } ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const { // Compute the byval alignment. const unsigned MinABIStackAlignInBytes = 4; unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true, TypeAlign > MinABIStackAlignInBytes); } Address ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, getContext().getTypeInfoInChars(Ty), CharUnits::fromQuantity(4), true); } ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, uint8_t FreeRegs) const { // Handle the generic C++ ABI. const RecordType *RT = Ty->getAs(); if (RT) { CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); if (RAA == CGCXXABI::RAA_Indirect) return getIndirectByRef(Ty, FreeRegs > 0); if (RAA == CGCXXABI::RAA_DirectInMemory) return getIndirectByValue(Ty); } // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; if (isAggregateTypeForABI(Ty)) { // Structures with flexible arrays are always indirect. if (RT && RT->getDecl()->hasFlexibleArrayMember()) return getIndirectByValue(Ty); // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); llvm::LLVMContext &LLVMContext = getVMContext(); llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); SmallVector Elements(SizeInRegs, Int32); llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); return FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg(Result) : ABIArgInfo::getDirect(Result, 0, nullptr, false); } return Ty->isPromotableIntegerType() ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) : ABIArgInfo::getExtend(Ty)) : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() : ABIArgInfo::getDirect()); } ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isAnyComplexType()) return ABIArgInfo::getDirectInReg(); // Arguments of size > 4 registers are indirect. auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; if (RetSize > 4) return getIndirectByRef(RetTy, /*HasFreeRegs*/ true); return DefaultABIInfo::classifyReturnType(RetTy); } } // End anonymous namespace. //===----------------------------------------------------------------------===// // XCore ABI Implementation //===----------------------------------------------------------------------===// namespace { /// A SmallStringEnc instance is used to build up the TypeString by passing /// it by reference between functions that append to it. typedef llvm::SmallString<128> SmallStringEnc; /// TypeStringCache caches the meta encodings of Types. /// /// The reason for caching TypeStrings is two fold: /// 1. To cache a type's encoding for later uses; /// 2. As a means to break recursive member type inclusion. /// /// A cache Entry can have a Status of: /// NonRecursive: The type encoding is not recursive; /// Recursive: The type encoding is recursive; /// Incomplete: An incomplete TypeString; /// IncompleteUsed: An incomplete TypeString that has been used in a /// Recursive type encoding. /// /// A NonRecursive entry will have all of its sub-members expanded as fully /// as possible. Whilst it may contain types which are recursive, the type /// itself is not recursive and thus its encoding may be safely used whenever /// the type is encountered. /// /// A Recursive entry will have all of its sub-members expanded as fully as /// possible. The type itself is recursive and it may contain other types which /// are recursive. The Recursive encoding must not be used during the expansion /// of a recursive type's recursive branch. For simplicity the code uses /// IncompleteCount to reject all usage of Recursive encodings for member types. /// /// An Incomplete entry is always a RecordType and only encodes its /// identifier e.g. "s(S){}". Incomplete 'StubEnc' entries are ephemeral and /// are placed into the cache during type expansion as a means to identify and /// handle recursive inclusion of types as sub-members. If there is recursion /// the entry becomes IncompleteUsed. /// /// During the expansion of a RecordType's members: /// /// If the cache contains a NonRecursive encoding for the member type, the /// cached encoding is used; /// /// If the cache contains a Recursive encoding for the member type, the /// cached encoding is 'Swapped' out, as it may be incorrect, and... /// /// If the member is a RecordType, an Incomplete encoding is placed into the /// cache to break potential recursive inclusion of itself as a sub-member; /// /// Once a member RecordType has been expanded, its temporary incomplete /// entry is removed from the cache. If a Recursive encoding was swapped out /// it is swapped back in; /// /// If an incomplete entry is used to expand a sub-member, the incomplete /// entry is marked as IncompleteUsed. The cache keeps count of how many /// IncompleteUsed entries it currently contains in IncompleteUsedCount; /// /// If a member's encoding is found to be a NonRecursive or Recursive viz: /// IncompleteUsedCount==0, the member's encoding is added to the cache. /// Else the member is part of a recursive type and thus the recursion has /// been exited too soon for the encoding to be correct for the member. /// class TypeStringCache { enum Status {NonRecursive, Recursive, Incomplete, IncompleteUsed}; struct Entry { std::string Str; // The encoded TypeString for the type. enum Status State; // Information about the encoding in 'Str'. std::string Swapped; // A temporary place holder for a Recursive encoding // during the expansion of RecordType's members. }; std::map Map; unsigned IncompleteCount; // Number of Incomplete entries in the Map. unsigned IncompleteUsedCount; // Number of IncompleteUsed entries in the Map. public: TypeStringCache() : IncompleteCount(0), IncompleteUsedCount(0) {} void addIncomplete(const IdentifierInfo *ID, std::string StubEnc); bool removeIncomplete(const IdentifierInfo *ID); void addIfComplete(const IdentifierInfo *ID, StringRef Str, bool IsRecursive); StringRef lookupStr(const IdentifierInfo *ID); }; /// TypeString encodings for enum & union fields must be order. /// FieldEncoding is a helper for this ordering process. class FieldEncoding { bool HasName; std::string Enc; public: FieldEncoding(bool b, SmallStringEnc &e) : HasName(b), Enc(e.c_str()) {} StringRef str() { return Enc; } bool operator<(const FieldEncoding &rhs) const { if (HasName != rhs.HasName) return HasName; return Enc < rhs.Enc; } }; class XCoreABIInfo : public DefaultABIInfo { public: XCoreABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; }; class XCoreTargetCodeGenInfo : public TargetCodeGenInfo { mutable TypeStringCache TSC; public: XCoreTargetCodeGenInfo(CodeGenTypes &CGT) :TargetCodeGenInfo(new XCoreABIInfo(CGT)) {} void emitTargetMD(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; }; } // End anonymous namespace. // TODO: this implementation is likely now redundant with the default // EmitVAArg. Address XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { CGBuilderTy &Builder = CGF.Builder; // Get the VAList. CharUnits SlotSize = CharUnits::fromQuantity(4); Address AP(Builder.CreateLoad(VAListAddr), SlotSize); // Handle the argument. ABIArgInfo AI = classifyArgumentType(Ty); CharUnits TypeAlign = getContext().getTypeAlignInChars(Ty); llvm::Type *ArgTy = CGT.ConvertType(Ty); if (AI.canHaveCoerceToType() && !AI.getCoerceToType()) AI.setCoerceToType(ArgTy); llvm::Type *ArgPtrTy = llvm::PointerType::getUnqual(ArgTy); Address Val = Address::invalid(); CharUnits ArgSize = CharUnits::Zero(); switch (AI.getKind()) { case ABIArgInfo::Expand: case ABIArgInfo::CoerceAndExpand: case ABIArgInfo::InAlloca: llvm_unreachable("Unsupported ABI kind for va_arg"); case ABIArgInfo::Ignore: Val = Address(llvm::UndefValue::get(ArgPtrTy), TypeAlign); ArgSize = CharUnits::Zero(); break; case ABIArgInfo::Extend: case ABIArgInfo::Direct: Val = Builder.CreateBitCast(AP, ArgPtrTy); ArgSize = CharUnits::fromQuantity( getDataLayout().getTypeAllocSize(AI.getCoerceToType())); ArgSize = ArgSize.alignTo(SlotSize); break; case ABIArgInfo::Indirect: Val = Builder.CreateElementBitCast(AP, ArgPtrTy); Val = Address(Builder.CreateLoad(Val), TypeAlign); ArgSize = SlotSize; break; } // Increment the VAList. if (!ArgSize.isZero()) { Address APN = Builder.CreateConstInBoundsByteGEP(AP, ArgSize); Builder.CreateStore(APN.getPointer(), VAListAddr); } return Val; } /// During the expansion of a RecordType, an incomplete TypeString is placed /// into the cache as a means to identify and break recursion. /// If there is a Recursive encoding in the cache, it is swapped out and will /// be reinserted by removeIncomplete(). /// All other types of encoding should have been used rather than arriving here. void TypeStringCache::addIncomplete(const IdentifierInfo *ID, std::string StubEnc) { if (!ID) return; Entry &E = Map[ID]; assert( (E.Str.empty() || E.State == Recursive) && "Incorrectly use of addIncomplete"); assert(!StubEnc.empty() && "Passing an empty string to addIncomplete()"); E.Swapped.swap(E.Str); // swap out the Recursive E.Str.swap(StubEnc); E.State = Incomplete; ++IncompleteCount; } /// Once the RecordType has been expanded, the temporary incomplete TypeString /// must be removed from the cache. /// If a Recursive was swapped out by addIncomplete(), it will be replaced. /// Returns true if the RecordType was defined recursively. bool TypeStringCache::removeIncomplete(const IdentifierInfo *ID) { if (!ID) return false; auto I = Map.find(ID); assert(I != Map.end() && "Entry not present"); Entry &E = I->second; assert( (E.State == Incomplete || E.State == IncompleteUsed) && "Entry must be an incomplete type"); bool IsRecursive = false; if (E.State == IncompleteUsed) { // We made use of our Incomplete encoding, thus we are recursive. IsRecursive = true; --IncompleteUsedCount; } if (E.Swapped.empty()) Map.erase(I); else { // Swap the Recursive back. E.Swapped.swap(E.Str); E.Swapped.clear(); E.State = Recursive; } --IncompleteCount; return IsRecursive; } /// Add the encoded TypeString to the cache only if it is NonRecursive or /// Recursive (viz: all sub-members were expanded as fully as possible). void TypeStringCache::addIfComplete(const IdentifierInfo *ID, StringRef Str, bool IsRecursive) { if (!ID || IncompleteUsedCount) return; // No key or it is is an incomplete sub-type so don't add. Entry &E = Map[ID]; if (IsRecursive && !E.Str.empty()) { assert(E.State==Recursive && E.Str.size() == Str.size() && "This is not the same Recursive entry"); // The parent container was not recursive after all, so we could have used // this Recursive sub-member entry after all, but we assumed the worse when // we started viz: IncompleteCount!=0. return; } assert(E.Str.empty() && "Entry already present"); E.Str = Str.str(); E.State = IsRecursive? Recursive : NonRecursive; } /// Return a cached TypeString encoding for the ID. If there isn't one, or we /// are recursively expanding a type (IncompleteCount != 0) and the cached /// encoding is Recursive, return an empty StringRef. StringRef TypeStringCache::lookupStr(const IdentifierInfo *ID) { if (!ID) return StringRef(); // We have no key. auto I = Map.find(ID); if (I == Map.end()) return StringRef(); // We have no encoding. Entry &E = I->second; if (E.State == Recursive && IncompleteCount) return StringRef(); // We don't use Recursive encodings for member types. if (E.State == Incomplete) { // The incomplete type is being used to break out of recursion. E.State = IncompleteUsed; ++IncompleteUsedCount; } return E.Str; } /// The XCore ABI includes a type information section that communicates symbol /// type information to the linker. The linker uses this information to verify /// safety/correctness of things such as array bound and pointers et al. /// The ABI only requires C (and XC) language modules to emit TypeStrings. /// This type information (TypeString) is emitted into meta data for all global /// symbols: definitions, declarations, functions & variables. /// /// The TypeString carries type, qualifier, name, size & value details. /// Please see 'Tools Development Guide' section 2.16.2 for format details: /// https://www.xmos.com/download/public/Tools-Development-Guide%28X9114A%29.pdf /// The output is tested by test/CodeGen/xcore-stringtype.c. /// static bool getTypeString(SmallStringEnc &Enc, const Decl *D, CodeGen::CodeGenModule &CGM, TypeStringCache &TSC); /// XCore uses emitTargetMD to emit TypeString metadata for global symbols. void XCoreTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { SmallStringEnc Enc; if (getTypeString(Enc, D, CGM, TSC)) { llvm::LLVMContext &Ctx = CGM.getModule().getContext(); llvm::Metadata *MDVals[] = {llvm::ConstantAsMetadata::get(GV), llvm::MDString::get(Ctx, Enc.str())}; llvm::NamedMDNode *MD = CGM.getModule().getOrInsertNamedMetadata("xcore.typestrings"); MD->addOperand(llvm::MDNode::get(Ctx, MDVals)); } } //===----------------------------------------------------------------------===// // SPIR ABI Implementation //===----------------------------------------------------------------------===// namespace { class SPIRTargetCodeGenInfo : public TargetCodeGenInfo { public: SPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} unsigned getOpenCLKernelCallingConv() const override; }; } // End anonymous namespace. namespace clang { namespace CodeGen { void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { DefaultABIInfo SPIRABI(CGM.getTypes()); SPIRABI.computeInfo(FI); } } } unsigned SPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const { return llvm::CallingConv::SPIR_KERNEL; } static bool appendType(SmallStringEnc &Enc, QualType QType, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC); /// Helper function for appendRecordType(). /// Builds a SmallVector containing the encoded field types in declaration /// order. static bool extractFieldType(SmallVectorImpl &FE, const RecordDecl *RD, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { for (const auto *Field : RD->fields()) { SmallStringEnc Enc; Enc += "m("; Enc += Field->getName(); Enc += "){"; if (Field->isBitField()) { Enc += "b("; llvm::raw_svector_ostream OS(Enc); OS << Field->getBitWidthValue(CGM.getContext()); Enc += ':'; } if (!appendType(Enc, Field->getType(), CGM, TSC)) return false; if (Field->isBitField()) Enc += ')'; Enc += '}'; FE.emplace_back(!Field->getName().empty(), Enc); } return true; } /// Appends structure and union types to Enc and adds encoding to cache. /// Recursively calls appendType (via extractFieldType) for each field. /// Union types have their fields ordered according to the ABI. static bool appendRecordType(SmallStringEnc &Enc, const RecordType *RT, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC, const IdentifierInfo *ID) { // Append the cached TypeString if we have one. StringRef TypeString = TSC.lookupStr(ID); if (!TypeString.empty()) { Enc += TypeString; return true; } // Start to emit an incomplete TypeString. size_t Start = Enc.size(); Enc += (RT->isUnionType()? 'u' : 's'); Enc += '('; if (ID) Enc += ID->getName(); Enc += "){"; // We collect all encoded fields and order as necessary. bool IsRecursive = false; const RecordDecl *RD = RT->getDecl()->getDefinition(); if (RD && !RD->field_empty()) { // An incomplete TypeString stub is placed in the cache for this RecordType // so that recursive calls to this RecordType will use it whilst building a // complete TypeString for this RecordType. SmallVector FE; std::string StubEnc(Enc.substr(Start).str()); StubEnc += '}'; // StubEnc now holds a valid incomplete TypeString. TSC.addIncomplete(ID, std::move(StubEnc)); if (!extractFieldType(FE, RD, CGM, TSC)) { (void) TSC.removeIncomplete(ID); return false; } IsRecursive = TSC.removeIncomplete(ID); // The ABI requires unions to be sorted but not structures. // See FieldEncoding::operator< for sort algorithm. if (RT->isUnionType()) llvm::sort(FE); // We can now complete the TypeString. unsigned E = FE.size(); for (unsigned I = 0; I != E; ++I) { if (I) Enc += ','; Enc += FE[I].str(); } } Enc += '}'; TSC.addIfComplete(ID, Enc.substr(Start), IsRecursive); return true; } /// Appends enum types to Enc and adds the encoding to the cache. static bool appendEnumType(SmallStringEnc &Enc, const EnumType *ET, TypeStringCache &TSC, const IdentifierInfo *ID) { // Append the cached TypeString if we have one. StringRef TypeString = TSC.lookupStr(ID); if (!TypeString.empty()) { Enc += TypeString; return true; } size_t Start = Enc.size(); Enc += "e("; if (ID) Enc += ID->getName(); Enc += "){"; // We collect all encoded enumerations and order them alphanumerically. if (const EnumDecl *ED = ET->getDecl()->getDefinition()) { SmallVector FE; for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) { SmallStringEnc EnumEnc; EnumEnc += "m("; EnumEnc += I->getName(); EnumEnc += "){"; I->getInitVal().toString(EnumEnc); EnumEnc += '}'; FE.push_back(FieldEncoding(!I->getName().empty(), EnumEnc)); } llvm::sort(FE); unsigned E = FE.size(); for (unsigned I = 0; I != E; ++I) { if (I) Enc += ','; Enc += FE[I].str(); } } Enc += '}'; TSC.addIfComplete(ID, Enc.substr(Start), false); return true; } /// Appends type's qualifier to Enc. /// This is done prior to appending the type's encoding. static void appendQualifier(SmallStringEnc &Enc, QualType QT) { // Qualifiers are emitted in alphabetical order. static const char *const Table[]={"","c:","r:","cr:","v:","cv:","rv:","crv:"}; int Lookup = 0; if (QT.isConstQualified()) Lookup += 1<<0; if (QT.isRestrictQualified()) Lookup += 1<<1; if (QT.isVolatileQualified()) Lookup += 1<<2; Enc += Table[Lookup]; } /// Appends built-in types to Enc. static bool appendBuiltinType(SmallStringEnc &Enc, const BuiltinType *BT) { const char *EncType; switch (BT->getKind()) { case BuiltinType::Void: EncType = "0"; break; case BuiltinType::Bool: EncType = "b"; break; case BuiltinType::Char_U: EncType = "uc"; break; case BuiltinType::UChar: EncType = "uc"; break; case BuiltinType::SChar: EncType = "sc"; break; case BuiltinType::UShort: EncType = "us"; break; case BuiltinType::Short: EncType = "ss"; break; case BuiltinType::UInt: EncType = "ui"; break; case BuiltinType::Int: EncType = "si"; break; case BuiltinType::ULong: EncType = "ul"; break; case BuiltinType::Long: EncType = "sl"; break; case BuiltinType::ULongLong: EncType = "ull"; break; case BuiltinType::LongLong: EncType = "sll"; break; case BuiltinType::Float: EncType = "ft"; break; case BuiltinType::Double: EncType = "d"; break; case BuiltinType::LongDouble: EncType = "ld"; break; default: return false; } Enc += EncType; return true; } /// Appends a pointer encoding to Enc before calling appendType for the pointee. static bool appendPointerType(SmallStringEnc &Enc, const PointerType *PT, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { Enc += "p("; if (!appendType(Enc, PT->getPointeeType(), CGM, TSC)) return false; Enc += ')'; return true; } /// Appends array encoding to Enc before calling appendType for the element. static bool appendArrayType(SmallStringEnc &Enc, QualType QT, const ArrayType *AT, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC, StringRef NoSizeEnc) { if (AT->getSizeModifier() != ArrayType::Normal) return false; Enc += "a("; if (const ConstantArrayType *CAT = dyn_cast(AT)) CAT->getSize().toStringUnsigned(Enc); else Enc += NoSizeEnc; // Global arrays use "*", otherwise it is "". Enc += ':'; // The Qualifiers should be attached to the type rather than the array. appendQualifier(Enc, QT); if (!appendType(Enc, AT->getElementType(), CGM, TSC)) return false; Enc += ')'; return true; } /// Appends a function encoding to Enc, calling appendType for the return type /// and the arguments. static bool appendFunctionType(SmallStringEnc &Enc, const FunctionType *FT, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { Enc += "f{"; if (!appendType(Enc, FT->getReturnType(), CGM, TSC)) return false; Enc += "}("; if (const FunctionProtoType *FPT = FT->getAs()) { // N.B. we are only interested in the adjusted param types. auto I = FPT->param_type_begin(); auto E = FPT->param_type_end(); if (I != E) { do { if (!appendType(Enc, *I, CGM, TSC)) return false; ++I; if (I != E) Enc += ','; } while (I != E); if (FPT->isVariadic()) Enc += ",va"; } else { if (FPT->isVariadic()) Enc += "va"; else Enc += '0'; } } Enc += ')'; return true; } /// Handles the type's qualifier before dispatching a call to handle specific /// type encodings. static bool appendType(SmallStringEnc &Enc, QualType QType, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { QualType QT = QType.getCanonicalType(); if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) // The Qualifiers should be attached to the type rather than the array. // Thus we don't call appendQualifier() here. return appendArrayType(Enc, QT, AT, CGM, TSC, ""); appendQualifier(Enc, QT); if (const BuiltinType *BT = QT->getAs()) return appendBuiltinType(Enc, BT); if (const PointerType *PT = QT->getAs()) return appendPointerType(Enc, PT, CGM, TSC); if (const EnumType *ET = QT->getAs()) return appendEnumType(Enc, ET, TSC, QT.getBaseTypeIdentifier()); if (const RecordType *RT = QT->getAsStructureType()) return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); if (const RecordType *RT = QT->getAsUnionType()) return appendRecordType(Enc, RT, CGM, TSC, QT.getBaseTypeIdentifier()); if (const FunctionType *FT = QT->getAs()) return appendFunctionType(Enc, FT, CGM, TSC); return false; } static bool getTypeString(SmallStringEnc &Enc, const Decl *D, CodeGen::CodeGenModule &CGM, TypeStringCache &TSC) { if (!D) return false; if (const FunctionDecl *FD = dyn_cast(D)) { if (FD->getLanguageLinkage() != CLanguageLinkage) return false; return appendType(Enc, FD->getType(), CGM, TSC); } if (const VarDecl *VD = dyn_cast(D)) { if (VD->getLanguageLinkage() != CLanguageLinkage) return false; QualType QT = VD->getType().getCanonicalType(); if (const ArrayType *AT = QT->getAsArrayTypeUnsafe()) { // Global ArrayTypes are given a size of '*' if the size is unknown. // The Qualifiers should be attached to the type rather than the array. // Thus we don't call appendQualifier() here. return appendArrayType(Enc, QT, AT, CGM, TSC, "*"); } return appendType(Enc, QT, CGM, TSC); } return false; } //===----------------------------------------------------------------------===// // RISCV ABI Implementation //===----------------------------------------------------------------------===// namespace { class RISCVABIInfo : public DefaultABIInfo { private: // Size of the integer ('x') registers in bits. unsigned XLen; // Size of the floating point ('f') registers in bits. Note that the target // ISA might have a wider FLen than the selected ABI (e.g. an RV32IF target // with soft float ABI has FLen==0). unsigned FLen; static const int NumArgGPRs = 8; static const int NumArgFPRs = 8; bool detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, llvm::Type *&Field1Ty, CharUnits &Field1Off, llvm::Type *&Field2Ty, CharUnits &Field2Off) const; public: RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen) : DefaultABIInfo(CGT), XLen(XLen), FLen(FLen) {} // DefaultABIInfo's classifyReturnType and classifyArgumentType are // non-virtual, but computeInfo is virtual, so we overload it. void computeInfo(CGFunctionInfo &FI) const override; ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, int &ArgFPRsLeft) const; ABIArgInfo classifyReturnType(QualType RetTy) const; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; ABIArgInfo extendType(QualType Ty) const; bool detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off, llvm::Type *&Field2Ty, CharUnits &Field2Off, int &NeededArgGPRs, int &NeededArgFPRs) const; ABIArgInfo coerceAndExpandFPCCEligibleStruct(llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty, CharUnits Field2Off) const; }; } // end anonymous namespace void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { QualType RetTy = FI.getReturnType(); if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(RetTy); // IsRetIndirect is true if classifyArgumentType indicated the value should // be passed indirect, or if the type size is a scalar greater than 2*XLen // and not a complex type with elements <= FLen. e.g. fp128 is passed direct // in LLVM IR, relying on the backend lowering code to rewrite the argument // list and pass indirectly on RV32. bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect; if (!IsRetIndirect && RetTy->isScalarType() && getContext().getTypeSize(RetTy) > (2 * XLen)) { if (RetTy->isComplexType() && FLen) { QualType EltTy = RetTy->getAs()->getElementType(); IsRetIndirect = getContext().getTypeSize(EltTy) > FLen; } else { // This is a normal scalar > 2*XLen, such as fp128 on RV32. IsRetIndirect = true; } } // We must track the number of GPRs used in order to conform to the RISC-V // ABI, as integer scalars passed in registers should have signext/zeroext // when promoted, but are anyext if passed on the stack. As GPR usage is // different for variadic arguments, we must also track whether we are // examining a vararg or not. int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; int ArgFPRsLeft = FLen ? NumArgFPRs : 0; int NumFixedArgs = FI.getNumRequiredArgs(); int ArgNum = 0; for (auto &ArgInfo : FI.arguments()) { bool IsFixed = ArgNum < NumFixedArgs; ArgInfo.info = classifyArgumentType(ArgInfo.type, IsFixed, ArgGPRsLeft, ArgFPRsLeft); ArgNum++; } } // Returns true if the struct is a potential candidate for the floating point // calling convention. If this function returns true, the caller is // responsible for checking that if there is only a single field then that // field is a float. bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, llvm::Type *&Field1Ty, CharUnits &Field1Off, llvm::Type *&Field2Ty, CharUnits &Field2Off) const { bool IsInt = Ty->isIntegralOrEnumerationType(); bool IsFloat = Ty->isRealFloatingType(); if (IsInt || IsFloat) { uint64_t Size = getContext().getTypeSize(Ty); if (IsInt && Size > XLen) return false; // Can't be eligible if larger than the FP registers. Half precision isn't // currently supported on RISC-V and the ABI hasn't been confirmed, so // default to the integer ABI in that case. if (IsFloat && (Size > FLen || Size < 32)) return false; // Can't be eligible if an integer type was already found (int+int pairs // are not eligible). if (IsInt && Field1Ty && Field1Ty->isIntegerTy()) return false; if (!Field1Ty) { Field1Ty = CGT.ConvertType(Ty); Field1Off = CurOff; return true; } if (!Field2Ty) { Field2Ty = CGT.ConvertType(Ty); Field2Off = CurOff; return true; } return false; } if (auto CTy = Ty->getAs()) { if (Field1Ty) return false; QualType EltTy = CTy->getElementType(); if (getContext().getTypeSize(EltTy) > FLen) return false; Field1Ty = CGT.ConvertType(EltTy); Field1Off = CurOff; assert(CurOff.isZero() && "Unexpected offset for first field"); Field2Ty = Field1Ty; Field2Off = Field1Off + getContext().getTypeSizeInChars(EltTy); return true; } if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) { uint64_t ArraySize = ATy->getSize().getZExtValue(); QualType EltTy = ATy->getElementType(); CharUnits EltSize = getContext().getTypeSizeInChars(EltTy); for (uint64_t i = 0; i < ArraySize; ++i) { bool Ret = detectFPCCEligibleStructHelper(EltTy, CurOff, Field1Ty, Field1Off, Field2Ty, Field2Off); if (!Ret) return false; CurOff += EltSize; } return true; } if (const auto *RTy = Ty->getAs()) { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are not eligible for the FP calling convention. if (getRecordArgABI(Ty, CGT.getCXXABI())) return false; if (isEmptyRecord(getContext(), Ty, true)) return true; const RecordDecl *RD = RTy->getDecl(); // Unions aren't eligible unless they're empty (which is caught above). if (RD->isUnion()) return false; int ZeroWidthBitFieldCount = 0; for (const FieldDecl *FD : RD->fields()) { const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex()); QualType QTy = FD->getType(); if (FD->isBitField()) { unsigned BitWidth = FD->getBitWidthValue(getContext()); // Allow a bitfield with a type greater than XLen as long as the // bitwidth is XLen or less. if (getContext().getTypeSize(QTy) > XLen && BitWidth <= XLen) QTy = getContext().getIntTypeForBitwidth(XLen, false); if (BitWidth == 0) { ZeroWidthBitFieldCount++; continue; } } bool Ret = detectFPCCEligibleStructHelper( QTy, CurOff + getContext().toCharUnitsFromBits(FieldOffInBits), Field1Ty, Field1Off, Field2Ty, Field2Off); if (!Ret) return false; // As a quirk of the ABI, zero-width bitfields aren't ignored for fp+fp // or int+fp structs, but are ignored for a struct with an fp field and // any number of zero-width bitfields. if (Field2Ty && ZeroWidthBitFieldCount > 0) return false; } return Field1Ty != nullptr; } return false; } // Determine if a struct is eligible for passing according to the floating // point calling convention (i.e., when flattened it contains a single fp // value, fp+fp, or int+fp of appropriate size). If so, NeededArgFPRs and // NeededArgGPRs are incremented appropriately. bool RISCVABIInfo::detectFPCCEligibleStruct(QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off, llvm::Type *&Field2Ty, CharUnits &Field2Off, int &NeededArgGPRs, int &NeededArgFPRs) const { Field1Ty = nullptr; Field2Ty = nullptr; NeededArgGPRs = 0; NeededArgFPRs = 0; bool IsCandidate = detectFPCCEligibleStructHelper( Ty, CharUnits::Zero(), Field1Ty, Field1Off, Field2Ty, Field2Off); // Not really a candidate if we have a single int but no float. if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy()) return false; if (!IsCandidate) return false; if (Field1Ty && Field1Ty->isFloatingPointTy()) NeededArgFPRs++; else if (Field1Ty) NeededArgGPRs++; if (Field2Ty && Field2Ty->isFloatingPointTy()) NeededArgFPRs++; else if (Field2Ty) NeededArgGPRs++; return IsCandidate; } // Call getCoerceAndExpand for the two-element flattened struct described by // Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an // appropriate coerceToType and unpaddedCoerceToType. ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct( llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty, CharUnits Field2Off) const { SmallVector CoerceElts; SmallVector UnpaddedCoerceElts; if (!Field1Off.isZero()) CoerceElts.push_back(llvm::ArrayType::get( llvm::Type::getInt8Ty(getVMContext()), Field1Off.getQuantity())); CoerceElts.push_back(Field1Ty); UnpaddedCoerceElts.push_back(Field1Ty); if (!Field2Ty) { return ABIArgInfo::getCoerceAndExpand( llvm::StructType::get(getVMContext(), CoerceElts, !Field1Off.isZero()), UnpaddedCoerceElts[0]); } CharUnits Field2Align = CharUnits::fromQuantity(getDataLayout().getABITypeAlignment(Field2Ty)); CharUnits Field1Size = CharUnits::fromQuantity(getDataLayout().getTypeStoreSize(Field1Ty)); CharUnits Field2OffNoPadNoPack = Field1Size.alignTo(Field2Align); CharUnits Padding = CharUnits::Zero(); if (Field2Off > Field2OffNoPadNoPack) Padding = Field2Off - Field2OffNoPadNoPack; else if (Field2Off != Field2Align && Field2Off > Field1Size) Padding = Field2Off - Field1Size; bool IsPacked = !Field2Off.isMultipleOf(Field2Align); if (!Padding.isZero()) CoerceElts.push_back(llvm::ArrayType::get( llvm::Type::getInt8Ty(getVMContext()), Padding.getQuantity())); CoerceElts.push_back(Field2Ty); UnpaddedCoerceElts.push_back(Field2Ty); auto CoerceToType = llvm::StructType::get(getVMContext(), CoerceElts, IsPacked); auto UnpaddedCoerceToType = llvm::StructType::get(getVMContext(), UnpaddedCoerceElts, IsPacked); return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType); } ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, bool IsFixed, int &ArgGPRsLeft, int &ArgFPRsLeft) const { assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); Ty = useFirstFieldIfTransparentUnion(Ty); // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always passed indirectly. if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { if (ArgGPRsLeft) ArgGPRsLeft -= 1; return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == CGCXXABI::RAA_DirectInMemory); } // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); uint64_t Size = getContext().getTypeSize(Ty); // Pass floating point values via FPRs if possible. - if (IsFixed && Ty->isFloatingType() && FLen >= Size && ArgFPRsLeft) { + if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() && + FLen >= Size && ArgFPRsLeft) { ArgFPRsLeft--; return ABIArgInfo::getDirect(); } // Complex types for the hard float ABI must be passed direct rather than // using CoerceAndExpand. if (IsFixed && Ty->isComplexType() && FLen && ArgFPRsLeft >= 2) { QualType EltTy = Ty->castAs()->getElementType(); if (getContext().getTypeSize(EltTy) <= FLen) { ArgFPRsLeft -= 2; return ABIArgInfo::getDirect(); } } if (IsFixed && FLen && Ty->isStructureOrClassType()) { llvm::Type *Field1Ty = nullptr; llvm::Type *Field2Ty = nullptr; CharUnits Field1Off = CharUnits::Zero(); CharUnits Field2Off = CharUnits::Zero(); int NeededArgGPRs; int NeededArgFPRs; bool IsCandidate = detectFPCCEligibleStruct(Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, NeededArgGPRs, NeededArgFPRs); if (IsCandidate && NeededArgGPRs <= ArgGPRsLeft && NeededArgFPRs <= ArgFPRsLeft) { ArgGPRsLeft -= NeededArgGPRs; ArgFPRsLeft -= NeededArgFPRs; return coerceAndExpandFPCCEligibleStruct(Field1Ty, Field1Off, Field2Ty, Field2Off); } } uint64_t NeededAlign = getContext().getTypeAlign(Ty); bool MustUseStack = false; // Determine the number of GPRs needed to pass the current argument // according to the ABI. 2*XLen-aligned varargs are passed in "aligned" // register pairs, so may consume 3 registers. int NeededArgGPRs = 1; if (!IsFixed && NeededAlign == 2 * XLen) NeededArgGPRs = 2 + (ArgGPRsLeft % 2); else if (Size > XLen && Size <= 2 * XLen) NeededArgGPRs = 2; if (NeededArgGPRs > ArgGPRsLeft) { MustUseStack = true; NeededArgGPRs = ArgGPRsLeft; } ArgGPRsLeft -= NeededArgGPRs; if (!isAggregateTypeForABI(Ty) && !Ty->isVectorType()) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); // All integral types are promoted to XLen width, unless passed on the // stack. if (Size < XLen && Ty->isIntegralOrEnumerationType() && !MustUseStack) { return extendType(Ty); } return ABIArgInfo::getDirect(); } // Aggregates which are <= 2*XLen will be passed in registers if possible, // so coerce to integers. if (Size <= 2 * XLen) { unsigned Alignment = getContext().getTypeAlign(Ty); // Use a single XLen int if possible, 2*XLen if 2*XLen alignment is // required, and a 2-element XLen array if only XLen alignment is required. if (Size <= XLen) { return ABIArgInfo::getDirect( llvm::IntegerType::get(getVMContext(), XLen)); } else if (Alignment == 2 * XLen) { return ABIArgInfo::getDirect( llvm::IntegerType::get(getVMContext(), 2 * XLen)); } else { return ABIArgInfo::getDirect(llvm::ArrayType::get( llvm::IntegerType::get(getVMContext(), XLen), 2)); } } return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } ABIArgInfo RISCVABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); int ArgGPRsLeft = 2; int ArgFPRsLeft = FLen ? 2 : 0; // The rules for return and argument types are the same, so defer to // classifyArgumentType. return classifyArgumentType(RetTy, /*IsFixed=*/true, ArgGPRsLeft, ArgFPRsLeft); } Address RISCVABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8); // Empty records are ignored for parameter passing purposes. if (isEmptyRecord(getContext(), Ty, true)) { Address Addr(CGF.Builder.CreateLoad(VAListAddr), SlotSize); Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty)); return Addr; } std::pair SizeAndAlign = getContext().getTypeInfoInChars(Ty); // Arguments bigger than 2*Xlen bytes are passed indirectly. bool IsIndirect = SizeAndAlign.first > 2 * SlotSize; return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, SizeAndAlign, SlotSize, /*AllowHigherAlign=*/true); } ABIArgInfo RISCVABIInfo::extendType(QualType Ty) const { int TySize = getContext().getTypeSize(Ty); // RV64 ABI requires unsigned 32 bit integers to be sign extended. if (XLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32) return ABIArgInfo::getSignExtend(Ty); return ABIArgInfo::getExtend(Ty); } namespace { class RISCVTargetCodeGenInfo : public TargetCodeGenInfo { public: RISCVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen) : TargetCodeGenInfo(new RISCVABIInfo(CGT, XLen, FLen)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override { const auto *FD = dyn_cast_or_null(D); if (!FD) return; const auto *Attr = FD->getAttr(); if (!Attr) return; const char *Kind; switch (Attr->getInterrupt()) { case RISCVInterruptAttr::user: Kind = "user"; break; case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break; case RISCVInterruptAttr::machine: Kind = "machine"; break; } auto *Fn = cast(GV); Fn->addFnAttr("interrupt", Kind); } }; } // namespace //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// bool CodeGenModule::supportsCOMDAT() const { return getTriple().supportsCOMDAT(); } const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { if (TheTargetCodeGenInfo) return *TheTargetCodeGenInfo; // Helper to set the unique_ptr while still keeping the return value. auto SetCGInfo = [&](TargetCodeGenInfo *P) -> const TargetCodeGenInfo & { this->TheTargetCodeGenInfo.reset(P); return *P; }; const llvm::Triple &Triple = getTarget().getTriple(); switch (Triple.getArch()) { default: return SetCGInfo(new DefaultTargetCodeGenInfo(Types)); case llvm::Triple::le32: return SetCGInfo(new PNaClTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: if (Triple.getOS() == llvm::Triple::NaCl) return SetCGInfo(new PNaClTargetCodeGenInfo(Types)); return SetCGInfo(new MIPSTargetCodeGenInfo(Types, true)); case llvm::Triple::mips64: case llvm::Triple::mips64el: return SetCGInfo(new MIPSTargetCodeGenInfo(Types, false)); case llvm::Triple::avr: return SetCGInfo(new AVRTargetCodeGenInfo(Types)); case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: { AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS; if (getTarget().getABI() == "darwinpcs") Kind = AArch64ABIInfo::DarwinPCS; else if (Triple.isOSWindows()) return SetCGInfo( new WindowsAArch64TargetCodeGenInfo(Types, AArch64ABIInfo::Win64)); return SetCGInfo(new AArch64TargetCodeGenInfo(Types, Kind)); } case llvm::Triple::wasm32: case llvm::Triple::wasm64: return SetCGInfo(new WebAssemblyTargetCodeGenInfo(Types)); case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: { if (Triple.getOS() == llvm::Triple::Win32) { return SetCGInfo( new WindowsARMTargetCodeGenInfo(Types, ARMABIInfo::AAPCS_VFP)); } ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS; StringRef ABIStr = getTarget().getABI(); if (ABIStr == "apcs-gnu") Kind = ARMABIInfo::APCS; else if (ABIStr == "aapcs16") Kind = ARMABIInfo::AAPCS16_VFP; else if (CodeGenOpts.FloatABI == "hard" || (CodeGenOpts.FloatABI != "soft" && (Triple.getEnvironment() == llvm::Triple::GNUEABIHF || Triple.getEnvironment() == llvm::Triple::MuslEABIHF || Triple.getEnvironment() == llvm::Triple::EABIHF))) Kind = ARMABIInfo::AAPCS_VFP; return SetCGInfo(new ARMTargetCodeGenInfo(Types, Kind)); } case llvm::Triple::ppc: { bool IsSoftFloat = CodeGenOpts.FloatABI == "soft" || getTarget().hasFeature("spe"); bool RetSmallStructInRegABI = PPC32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts); return SetCGInfo( new PPC32TargetCodeGenInfo(Types, IsSoftFloat, RetSmallStructInRegABI)); } case llvm::Triple::ppc64: if (Triple.isOSBinFormatELF()) { PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1; if (getTarget().getABI() == "elfv2") Kind = PPC64_SVR4_ABIInfo::ELFv2; bool HasQPX = getTarget().getABI() == "elfv1-qpx"; bool IsSoftFloat = CodeGenOpts.FloatABI == "soft"; return SetCGInfo(new PPC64_SVR4_TargetCodeGenInfo(Types, Kind, HasQPX, IsSoftFloat)); } else return SetCGInfo(new PPC64TargetCodeGenInfo(Types)); case llvm::Triple::ppc64le: { assert(Triple.isOSBinFormatELF() && "PPC64 LE non-ELF not supported!"); PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv2; if (getTarget().getABI() == "elfv1" || getTarget().getABI() == "elfv1-qpx") Kind = PPC64_SVR4_ABIInfo::ELFv1; bool HasQPX = getTarget().getABI() == "elfv1-qpx"; bool IsSoftFloat = CodeGenOpts.FloatABI == "soft"; return SetCGInfo(new PPC64_SVR4_TargetCodeGenInfo(Types, Kind, HasQPX, IsSoftFloat)); } case llvm::Triple::nvptx: case llvm::Triple::nvptx64: return SetCGInfo(new NVPTXTargetCodeGenInfo(Types)); case llvm::Triple::msp430: return SetCGInfo(new MSP430TargetCodeGenInfo(Types)); case llvm::Triple::riscv32: case llvm::Triple::riscv64: { StringRef ABIStr = getTarget().getABI(); unsigned XLen = getTarget().getPointerWidth(0); unsigned ABIFLen = 0; if (ABIStr.endswith("f")) ABIFLen = 32; else if (ABIStr.endswith("d")) ABIFLen = 64; return SetCGInfo(new RISCVTargetCodeGenInfo(Types, XLen, ABIFLen)); } case llvm::Triple::systemz: { bool HasVector = getTarget().getABI() == "vector"; return SetCGInfo(new SystemZTargetCodeGenInfo(Types, HasVector)); } case llvm::Triple::tce: case llvm::Triple::tcele: return SetCGInfo(new TCETargetCodeGenInfo(Types)); case llvm::Triple::x86: { bool IsDarwinVectorABI = Triple.isOSDarwin(); bool RetSmallStructInRegABI = X86_32TargetCodeGenInfo::isStructReturnInRegABI(Triple, CodeGenOpts); bool IsWin32FloatStructABI = Triple.isOSWindows() && !Triple.isOSCygMing(); if (Triple.getOS() == llvm::Triple::Win32) { return SetCGInfo(new WinX86_32TargetCodeGenInfo( Types, IsDarwinVectorABI, RetSmallStructInRegABI, IsWin32FloatStructABI, CodeGenOpts.NumRegisterParameters)); } else { return SetCGInfo(new X86_32TargetCodeGenInfo( Types, IsDarwinVectorABI, RetSmallStructInRegABI, IsWin32FloatStructABI, CodeGenOpts.NumRegisterParameters, CodeGenOpts.FloatABI == "soft")); } } case llvm::Triple::x86_64: { StringRef ABI = getTarget().getABI(); X86AVXABILevel AVXLevel = (ABI == "avx512" ? X86AVXABILevel::AVX512 : ABI == "avx" ? X86AVXABILevel::AVX : X86AVXABILevel::None); switch (Triple.getOS()) { case llvm::Triple::Win32: return SetCGInfo(new WinX86_64TargetCodeGenInfo(Types, AVXLevel)); default: return SetCGInfo(new X86_64TargetCodeGenInfo(Types, AVXLevel)); } } case llvm::Triple::hexagon: return SetCGInfo(new HexagonTargetCodeGenInfo(Types)); case llvm::Triple::lanai: return SetCGInfo(new LanaiTargetCodeGenInfo(Types)); case llvm::Triple::r600: return SetCGInfo(new AMDGPUTargetCodeGenInfo(Types)); case llvm::Triple::amdgcn: return SetCGInfo(new AMDGPUTargetCodeGenInfo(Types)); case llvm::Triple::sparc: return SetCGInfo(new SparcV8TargetCodeGenInfo(Types)); case llvm::Triple::sparcv9: return SetCGInfo(new SparcV9TargetCodeGenInfo(Types)); case llvm::Triple::xcore: return SetCGInfo(new XCoreTargetCodeGenInfo(Types)); case llvm::Triple::arc: return SetCGInfo(new ARCTargetCodeGenInfo(Types)); case llvm::Triple::spir: case llvm::Triple::spir64: return SetCGInfo(new SPIRTargetCodeGenInfo(Types)); } } /// Create an OpenCL kernel for an enqueued block. /// /// The kernel has the same function type as the block invoke function. Its /// name is the name of the block invoke function postfixed with "_kernel". /// It simply calls the block invoke function then returns. llvm::Function * TargetCodeGenInfo::createEnqueuedBlockKernel(CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Value *BlockLiteral) const { auto *InvokeFT = Invoke->getFunctionType(); llvm::SmallVector ArgTys; for (auto &P : InvokeFT->params()) ArgTys.push_back(P); auto &C = CGF.getLLVMContext(); std::string Name = Invoke->getName().str() + "_kernel"; auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false); auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name, &CGF.CGM.getModule()); auto IP = CGF.Builder.saveIP(); auto *BB = llvm::BasicBlock::Create(C, "entry", F); auto &Builder = CGF.Builder; Builder.SetInsertPoint(BB); llvm::SmallVector Args; for (auto &A : F->args()) Args.push_back(&A); Builder.CreateCall(Invoke, Args); Builder.CreateRetVoid(); Builder.restoreIP(IP); return F; } /// Create an OpenCL kernel for an enqueued block. /// /// The type of the first argument (the block literal) is the struct type /// of the block literal instead of a pointer type. The first argument /// (block literal) is passed directly by value to the kernel. The kernel /// allocates the same type of struct on stack and stores the block literal /// to it and passes its pointer to the block invoke function. The kernel /// has "enqueued-block" function attribute and kernel argument metadata. llvm::Function *AMDGPUTargetCodeGenInfo::createEnqueuedBlockKernel( CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Value *BlockLiteral) const { auto &Builder = CGF.Builder; auto &C = CGF.getLLVMContext(); auto *BlockTy = BlockLiteral->getType()->getPointerElementType(); auto *InvokeFT = Invoke->getFunctionType(); llvm::SmallVector ArgTys; llvm::SmallVector AddressQuals; llvm::SmallVector AccessQuals; llvm::SmallVector ArgTypeNames; llvm::SmallVector ArgBaseTypeNames; llvm::SmallVector ArgTypeQuals; llvm::SmallVector ArgNames; ArgTys.push_back(BlockTy); ArgTypeNames.push_back(llvm::MDString::get(C, "__block_literal")); AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(0))); ArgBaseTypeNames.push_back(llvm::MDString::get(C, "__block_literal")); ArgTypeQuals.push_back(llvm::MDString::get(C, "")); AccessQuals.push_back(llvm::MDString::get(C, "none")); ArgNames.push_back(llvm::MDString::get(C, "block_literal")); for (unsigned I = 1, E = InvokeFT->getNumParams(); I < E; ++I) { ArgTys.push_back(InvokeFT->getParamType(I)); ArgTypeNames.push_back(llvm::MDString::get(C, "void*")); AddressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(3))); AccessQuals.push_back(llvm::MDString::get(C, "none")); ArgBaseTypeNames.push_back(llvm::MDString::get(C, "void*")); ArgTypeQuals.push_back(llvm::MDString::get(C, "")); ArgNames.push_back( llvm::MDString::get(C, (Twine("local_arg") + Twine(I)).str())); } std::string Name = Invoke->getName().str() + "_kernel"; auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), ArgTys, false); auto *F = llvm::Function::Create(FT, llvm::GlobalValue::InternalLinkage, Name, &CGF.CGM.getModule()); F->addFnAttr("enqueued-block"); auto IP = CGF.Builder.saveIP(); auto *BB = llvm::BasicBlock::Create(C, "entry", F); Builder.SetInsertPoint(BB); unsigned BlockAlign = CGF.CGM.getDataLayout().getPrefTypeAlignment(BlockTy); auto *BlockPtr = Builder.CreateAlloca(BlockTy, nullptr); BlockPtr->setAlignment(llvm::MaybeAlign(BlockAlign)); Builder.CreateAlignedStore(F->arg_begin(), BlockPtr, BlockAlign); auto *Cast = Builder.CreatePointerCast(BlockPtr, InvokeFT->getParamType(0)); llvm::SmallVector Args; Args.push_back(Cast); for (auto I = F->arg_begin() + 1, E = F->arg_end(); I != E; ++I) Args.push_back(I); Builder.CreateCall(Invoke, Args); Builder.CreateRetVoid(); Builder.restoreIP(IP); F->setMetadata("kernel_arg_addr_space", llvm::MDNode::get(C, AddressQuals)); F->setMetadata("kernel_arg_access_qual", llvm::MDNode::get(C, AccessQuals)); F->setMetadata("kernel_arg_type", llvm::MDNode::get(C, ArgTypeNames)); F->setMetadata("kernel_arg_base_type", llvm::MDNode::get(C, ArgBaseTypeNames)); F->setMetadata("kernel_arg_type_qual", llvm::MDNode::get(C, ArgTypeQuals)); if (CGF.CGM.getCodeGenOpts().EmitOpenCLArgMetadata) F->setMetadata("kernel_arg_name", llvm::MDNode::get(C, ArgNames)); return F; } Index: head/contrib/llvm-project/clang =================================================================== --- head/contrib/llvm-project/clang (revision 362718) +++ head/contrib/llvm-project/clang (revision 362719) Property changes on: head/contrib/llvm-project/clang ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/llvm-project/release-10.x/clang:r362595-362704 Index: head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/int_mul_impl.inc =================================================================== --- head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/int_mul_impl.inc (nonexistent) +++ head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/int_mul_impl.inc (revision 362719) @@ -0,0 +1,31 @@ +//===-- int_mul_impl.inc - Integer multiplication -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Helpers used by __mulsi3, __muldi3. +// +//===----------------------------------------------------------------------===// + +#if !defined(__riscv_mul) + .text + .align 2 + + .globl __mulxi3 + .type __mulxi3, @function +__mulxi3: + mv a2, a0 + mv a0, zero +.L1: + andi a3, a1, 1 + beqz a3, .L2 + add a0, a0, a2 +.L2: + srli a1, a1, 1 + slli a2, a2, 1 + bnez a1, .L1 + ret +#endif Property changes on: head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/int_mul_impl.inc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/muldi3.S =================================================================== --- head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/muldi3.S (nonexistent) +++ head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/muldi3.S (revision 362719) @@ -0,0 +1,11 @@ +//===--- muldi3.S - Integer multiplication routines -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#if __riscv_xlen == 64 +#define __mulxi3 __muldi3 +#include "int_mul_impl.inc" +#endif Property changes on: head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/muldi3.S ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/mulsi3.S =================================================================== --- head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/mulsi3.S (revision 362718) +++ head/contrib/llvm-project/compiler-rt/lib/builtins/riscv/mulsi3.S (revision 362719) @@ -1,27 +1,12 @@ -//===--- mulsi3.S - Integer multiplication routines routines ---===// +//===--- mulsi3.S - Integer multiplication routines -----------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -#if !defined(__riscv_mul) && __riscv_xlen == 32 - .text - .align 2 - - .globl __mulsi3 - .type __mulsi3, @function -__mulsi3: - mv a2, a0 - mv a0, zero -.L1: - andi a3, a1, 1 - beqz a3, .L2 - add a0, a0, a2 -.L2: - srli a1, a1, 1 - slli a2, a2, 1 - bnez a1, .L1 - ret +#if __riscv_xlen == 32 +#define __mulxi3 __mulsi3 +#include "int_mul_impl.inc" #endif Index: head/contrib/llvm-project/compiler-rt =================================================================== --- head/contrib/llvm-project/compiler-rt (revision 362718) +++ head/contrib/llvm-project/compiler-rt (revision 362719) Property changes on: head/contrib/llvm-project/compiler-rt ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/llvm-project/release-10.x/compiler-rt:r361404-362704 Index: head/contrib/llvm-project/libcxx/include/array =================================================================== --- head/contrib/llvm-project/libcxx/include/array (revision 362718) +++ head/contrib/llvm-project/libcxx/include/array (revision 362719) @@ -1,484 +1,484 @@ // -*- C++ -*- //===---------------------------- array -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef _LIBCPP_ARRAY #define _LIBCPP_ARRAY /* array synopsis namespace std { template struct array { // types: typedef T & reference; typedef const T & const_reference; typedef implementation defined iterator; typedef implementation defined const_iterator; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T value_type; typedef T* pointer; typedef const T* const_pointer; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; // No explicit construct/copy/destroy for aggregate type void fill(const T& u); void swap(array& a) noexcept(is_nothrow_swappable_v); // iterators: iterator begin() noexcept; const_iterator begin() const noexcept; iterator end() noexcept; const_iterator end() const noexcept; reverse_iterator rbegin() noexcept; const_reverse_iterator rbegin() const noexcept; reverse_iterator rend() noexcept; const_reverse_iterator rend() const noexcept; const_iterator cbegin() const noexcept; const_iterator cend() const noexcept; const_reverse_iterator crbegin() const noexcept; const_reverse_iterator crend() const noexcept; // capacity: constexpr size_type size() const noexcept; constexpr size_type max_size() const noexcept; constexpr bool empty() const noexcept; // element access: reference operator[](size_type n); const_reference operator[](size_type n) const; // constexpr in C++14 const_reference at(size_type n) const; // constexpr in C++14 reference at(size_type n); reference front(); const_reference front() const; // constexpr in C++14 reference back(); const_reference back() const; // constexpr in C++14 T* data() noexcept; const T* data() const noexcept; }; template array(T, U...) -> array; template bool operator==(const array& x, const array& y); template bool operator!=(const array& x, const array& y); template bool operator<(const array& x, const array& y); template bool operator>(const array& x, const array& y); template bool operator<=(const array& x, const array& y); template bool operator>=(const array& x, const array& y); template void swap(array& x, array& y) noexcept(noexcept(x.swap(y))); // C++17 template struct tuple_size; template struct tuple_element; template struct tuple_size>; template struct tuple_element>; template T& get(array&) noexcept; // constexpr in C++14 template const T& get(const array&) noexcept; // constexpr in C++14 template T&& get(array&&) noexcept; // constexpr in C++14 template const T&& get(const array&&) noexcept; // constexpr in C++14 } // std */ #include <__config> #include <__tuple> #include #include #include #include #include #include // for _LIBCPP_UNREACHABLE #include #include <__debug> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif _LIBCPP_BEGIN_NAMESPACE_STD template struct _LIBCPP_TEMPLATE_VIS array { // types: typedef array __self; typedef _Tp value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* iterator; typedef const value_type* const_iterator; typedef value_type* pointer; typedef const value_type* const_pointer; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; _Tp __elems_[_Size]; // No explicit construct/copy/destroy for aggregate type _LIBCPP_INLINE_VISIBILITY void fill(const value_type& __u) { _VSTD::fill_n(__elems_, _Size, __u); } _LIBCPP_INLINE_VISIBILITY void swap(array& __a) _NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) { std::swap_ranges(__elems_, __elems_ + _Size, __a.__elems_); } // iterators: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 iterator begin() _NOEXCEPT {return iterator(data());} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const_iterator begin() const _NOEXCEPT {return const_iterator(data());} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 iterator end() _NOEXCEPT {return iterator(data() + _Size);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const_iterator end() const _NOEXCEPT {return const_iterator(data() + _Size);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reverse_iterator rbegin() _NOEXCEPT {return reverse_iterator(end());} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const_reverse_iterator rbegin() const _NOEXCEPT {return const_reverse_iterator(end());} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reverse_iterator rend() _NOEXCEPT {return reverse_iterator(begin());} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const_reverse_iterator rend() const _NOEXCEPT {return const_reverse_iterator(begin());} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const_iterator cbegin() const _NOEXCEPT {return begin();} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const_iterator cend() const _NOEXCEPT {return end();} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const_reverse_iterator crbegin() const _NOEXCEPT {return rbegin();} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const_reverse_iterator crend() const _NOEXCEPT {return rend();} // capacity: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT {return _Size;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT {return _Size;} _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return false; } // element access: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference operator[](size_type __n) _NOEXCEPT {return __elems_[__n];} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference operator[](size_type __n) const _NOEXCEPT {return __elems_[__n];} _LIBCPP_CONSTEXPR_AFTER_CXX14 reference at(size_type __n); _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference at(size_type __n) const; _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference front() _NOEXCEPT {return __elems_[0];} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference front() const _NOEXCEPT {return __elems_[0];} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 reference back() _NOEXCEPT {return __elems_[_Size - 1];} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference back() const _NOEXCEPT {return __elems_[_Size - 1];} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 value_type* data() _NOEXCEPT {return __elems_;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14 const value_type* data() const _NOEXCEPT {return __elems_;} }; template _LIBCPP_CONSTEXPR_AFTER_CXX14 typename array<_Tp, _Size>::reference array<_Tp, _Size>::at(size_type __n) { if (__n >= _Size) __throw_out_of_range("array::at"); return __elems_[__n]; } template _LIBCPP_CONSTEXPR_AFTER_CXX11 typename array<_Tp, _Size>::const_reference array<_Tp, _Size>::at(size_type __n) const { if (__n >= _Size) __throw_out_of_range("array::at"); return __elems_[__n]; } template struct _LIBCPP_TEMPLATE_VIS array<_Tp, 0> { // types: typedef array __self; typedef _Tp value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* iterator; typedef const value_type* const_iterator; typedef value_type* pointer; typedef const value_type* const_pointer; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef typename conditional::value, const char, char>::type _CharType; struct _ArrayInStructT { _Tp __data_[1]; }; _ALIGNAS_TYPE(_ArrayInStructT) _CharType __elems_[sizeof(_ArrayInStructT)]; // No explicit construct/copy/destroy for aggregate type _LIBCPP_INLINE_VISIBILITY void fill(const value_type&) { static_assert(!is_const<_Tp>::value, "cannot fill zero-sized array of type 'const T'"); } _LIBCPP_INLINE_VISIBILITY void swap(array&) _NOEXCEPT { static_assert(!is_const<_Tp>::value, "cannot swap zero-sized array of type 'const T'"); } // iterators: _LIBCPP_INLINE_VISIBILITY iterator begin() _NOEXCEPT {return iterator(data());} _LIBCPP_INLINE_VISIBILITY const_iterator begin() const _NOEXCEPT {return const_iterator(data());} _LIBCPP_INLINE_VISIBILITY iterator end() _NOEXCEPT {return iterator(data());} _LIBCPP_INLINE_VISIBILITY const_iterator end() const _NOEXCEPT {return const_iterator(data());} _LIBCPP_INLINE_VISIBILITY reverse_iterator rbegin() _NOEXCEPT {return reverse_iterator(end());} _LIBCPP_INLINE_VISIBILITY const_reverse_iterator rbegin() const _NOEXCEPT {return const_reverse_iterator(end());} _LIBCPP_INLINE_VISIBILITY reverse_iterator rend() _NOEXCEPT {return reverse_iterator(begin());} _LIBCPP_INLINE_VISIBILITY const_reverse_iterator rend() const _NOEXCEPT {return const_reverse_iterator(begin());} _LIBCPP_INLINE_VISIBILITY const_iterator cbegin() const _NOEXCEPT {return begin();} _LIBCPP_INLINE_VISIBILITY const_iterator cend() const _NOEXCEPT {return end();} _LIBCPP_INLINE_VISIBILITY const_reverse_iterator crbegin() const _NOEXCEPT {return rbegin();} _LIBCPP_INLINE_VISIBILITY const_reverse_iterator crend() const _NOEXCEPT {return rend();} // capacity: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR size_type size() const _NOEXCEPT {return 0; } _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR size_type max_size() const _NOEXCEPT {return 0;} _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT {return true;} // element access: _LIBCPP_INLINE_VISIBILITY reference operator[](size_type) _NOEXCEPT { _LIBCPP_ASSERT(false, "cannot call array::operator[] on a zero-sized array"); _LIBCPP_UNREACHABLE(); } _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const_reference operator[](size_type) const _NOEXCEPT { _LIBCPP_ASSERT(false, "cannot call array::operator[] on a zero-sized array"); _LIBCPP_UNREACHABLE(); } _LIBCPP_INLINE_VISIBILITY reference at(size_type) { __throw_out_of_range("array::at"); _LIBCPP_UNREACHABLE(); } _LIBCPP_INLINE_VISIBILITY const_reference at(size_type) const { __throw_out_of_range("array::at"); _LIBCPP_UNREACHABLE(); } _LIBCPP_INLINE_VISIBILITY reference front() _NOEXCEPT { _LIBCPP_ASSERT(false, "cannot call array::front() on a zero-sized array"); _LIBCPP_UNREACHABLE(); } _LIBCPP_INLINE_VISIBILITY const_reference front() const _NOEXCEPT { _LIBCPP_ASSERT(false, "cannot call array::front() on a zero-sized array"); _LIBCPP_UNREACHABLE(); } _LIBCPP_INLINE_VISIBILITY reference back() _NOEXCEPT { _LIBCPP_ASSERT(false, "cannot call array::back() on a zero-sized array"); _LIBCPP_UNREACHABLE(); } _LIBCPP_INLINE_VISIBILITY const_reference back() const _NOEXCEPT { _LIBCPP_ASSERT(false, "cannot call array::back() on a zero-sized array"); _LIBCPP_UNREACHABLE(); } _LIBCPP_INLINE_VISIBILITY value_type* data() _NOEXCEPT {return reinterpret_cast(__elems_);} _LIBCPP_INLINE_VISIBILITY const value_type* data() const _NOEXCEPT {return reinterpret_cast(__elems_);} }; #ifndef _LIBCPP_HAS_NO_DEDUCTION_GUIDES template && ...), void>::type + class = _EnableIf<__all<_IsSame<_Tp, _Args>::value...>::value> > array(_Tp, _Args...) -> array<_Tp, 1 + sizeof...(_Args)>; #endif template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator==(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) { return _VSTD::equal(__x.begin(), __x.end(), __y.begin()); } template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator!=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) { return !(__x == __y); } template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator<(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) { return _VSTD::lexicographical_compare(__x.begin(), __x.end(), __y.begin(), __y.end()); } template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator>(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) { return __y < __x; } template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator<=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) { return !(__y < __x); } template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool operator>=(const array<_Tp, _Size>& __x, const array<_Tp, _Size>& __y) { return !(__x < __y); } template inline _LIBCPP_INLINE_VISIBILITY typename enable_if < _Size == 0 || __is_swappable<_Tp>::value, void >::type swap(array<_Tp, _Size>& __x, array<_Tp, _Size>& __y) _NOEXCEPT_(noexcept(__x.swap(__y))) { __x.swap(__y); } template struct _LIBCPP_TEMPLATE_VIS tuple_size > : public integral_constant {}; template struct _LIBCPP_TEMPLATE_VIS tuple_element<_Ip, array<_Tp, _Size> > { static_assert(_Ip < _Size, "Index out of bounds in std::tuple_element<> (std::array)"); typedef _Tp type; }; template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Tp& get(array<_Tp, _Size>& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array)"); return __a.__elems_[_Ip]; } template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp& get(const array<_Tp, _Size>& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array)"); return __a.__elems_[_Ip]; } #ifndef _LIBCPP_CXX03_LANG template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Tp&& get(array<_Tp, _Size>&& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (std::array &&)"); return _VSTD::move(__a.__elems_[_Ip]); } template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Tp&& get(const array<_Tp, _Size>&& __a) _NOEXCEPT { static_assert(_Ip < _Size, "Index out of bounds in std::get<> (const std::array &&)"); return _VSTD::move(__a.__elems_[_Ip]); } #endif // !_LIBCPP_CXX03_LANG _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_ARRAY Index: head/contrib/llvm-project/libcxx =================================================================== --- head/contrib/llvm-project/libcxx (revision 362718) +++ head/contrib/llvm-project/libcxx (revision 362719) Property changes on: head/contrib/llvm-project/libcxx ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/llvm-project/release-10.x/libcxx:r358399-362704 Index: head/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- head/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp (revision 362718) +++ head/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp (revision 362719) @@ -1,4447 +1,4459 @@ //===----- LegalizeIntegerTypes.cpp - Legalization of integer types -------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements integer type expansion and promotion for LegalizeTypes. // Promotion is the act of changing a computation in an illegal type into a // computation in a larger type. For example, implementing i8 arithmetic in an // i32 register (often needed on powerpc). // Expansion is the act of changing a computation in an illegal type into a // computation in two identical registers of a smaller type. For example, // implementing i64 arithmetic in two i32 registers (often needed on 32-bit // targets). // //===----------------------------------------------------------------------===// #include "LegalizeTypes.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "legalize-types" //===----------------------------------------------------------------------===// // Integer Result Promotion //===----------------------------------------------------------------------===// /// PromoteIntegerResult - This method is called when a result of a node is /// found to be in need of promotion to a larger type. At this point, the node /// may also have invalid operands or may have other results that need /// expansion, we just know that (at least) one result needs promotion. void DAGTypeLegalizer::PromoteIntegerResult(SDNode *N, unsigned ResNo) { LLVM_DEBUG(dbgs() << "Promote integer result: "; N->dump(&DAG); dbgs() << "\n"); SDValue Res = SDValue(); // See if the target wants to custom expand this node. if (CustomLowerNode(N, N->getValueType(ResNo), true)) { LLVM_DEBUG(dbgs() << "Node has been custom expanded, done\n"); return; } switch (N->getOpcode()) { default: #ifndef NDEBUG dbgs() << "PromoteIntegerResult #" << ResNo << ": "; N->dump(&DAG); dbgs() << "\n"; #endif llvm_unreachable("Do not know how to promote this operator!"); case ISD::MERGE_VALUES:Res = PromoteIntRes_MERGE_VALUES(N, ResNo); break; case ISD::AssertSext: Res = PromoteIntRes_AssertSext(N); break; case ISD::AssertZext: Res = PromoteIntRes_AssertZext(N); break; case ISD::BITCAST: Res = PromoteIntRes_BITCAST(N); break; case ISD::BITREVERSE: Res = PromoteIntRes_BITREVERSE(N); break; case ISD::BSWAP: Res = PromoteIntRes_BSWAP(N); break; case ISD::BUILD_PAIR: Res = PromoteIntRes_BUILD_PAIR(N); break; case ISD::Constant: Res = PromoteIntRes_Constant(N); break; case ISD::CTLZ_ZERO_UNDEF: case ISD::CTLZ: Res = PromoteIntRes_CTLZ(N); break; case ISD::CTPOP: Res = PromoteIntRes_CTPOP(N); break; case ISD::CTTZ_ZERO_UNDEF: case ISD::CTTZ: Res = PromoteIntRes_CTTZ(N); break; case ISD::EXTRACT_VECTOR_ELT: Res = PromoteIntRes_EXTRACT_VECTOR_ELT(N); break; case ISD::LOAD: Res = PromoteIntRes_LOAD(cast(N)); break; case ISD::MLOAD: Res = PromoteIntRes_MLOAD(cast(N)); break; case ISD::MGATHER: Res = PromoteIntRes_MGATHER(cast(N)); break; case ISD::SELECT: Res = PromoteIntRes_SELECT(N); break; case ISD::VSELECT: Res = PromoteIntRes_VSELECT(N); break; case ISD::SELECT_CC: Res = PromoteIntRes_SELECT_CC(N); break; case ISD::STRICT_FSETCC: case ISD::STRICT_FSETCCS: case ISD::SETCC: Res = PromoteIntRes_SETCC(N); break; case ISD::SMIN: case ISD::SMAX: Res = PromoteIntRes_SExtIntBinOp(N); break; case ISD::UMIN: case ISD::UMAX: Res = PromoteIntRes_ZExtIntBinOp(N); break; case ISD::SHL: Res = PromoteIntRes_SHL(N); break; case ISD::SIGN_EXTEND_INREG: Res = PromoteIntRes_SIGN_EXTEND_INREG(N); break; case ISD::SRA: Res = PromoteIntRes_SRA(N); break; case ISD::SRL: Res = PromoteIntRes_SRL(N); break; case ISD::TRUNCATE: Res = PromoteIntRes_TRUNCATE(N); break; case ISD::UNDEF: Res = PromoteIntRes_UNDEF(N); break; case ISD::VAARG: Res = PromoteIntRes_VAARG(N); break; case ISD::EXTRACT_SUBVECTOR: Res = PromoteIntRes_EXTRACT_SUBVECTOR(N); break; case ISD::VECTOR_SHUFFLE: Res = PromoteIntRes_VECTOR_SHUFFLE(N); break; case ISD::INSERT_VECTOR_ELT: Res = PromoteIntRes_INSERT_VECTOR_ELT(N); break; case ISD::BUILD_VECTOR: Res = PromoteIntRes_BUILD_VECTOR(N); break; case ISD::SCALAR_TO_VECTOR: Res = PromoteIntRes_SCALAR_TO_VECTOR(N); break; case ISD::SPLAT_VECTOR: Res = PromoteIntRes_SPLAT_VECTOR(N); break; case ISD::CONCAT_VECTORS: Res = PromoteIntRes_CONCAT_VECTORS(N); break; case ISD::ANY_EXTEND_VECTOR_INREG: case ISD::SIGN_EXTEND_VECTOR_INREG: case ISD::ZERO_EXTEND_VECTOR_INREG: Res = PromoteIntRes_EXTEND_VECTOR_INREG(N); break; case ISD::SIGN_EXTEND: case ISD::ZERO_EXTEND: case ISD::ANY_EXTEND: Res = PromoteIntRes_INT_EXTEND(N); break; case ISD::STRICT_FP_TO_SINT: case ISD::STRICT_FP_TO_UINT: case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: Res = PromoteIntRes_FP_TO_XINT(N); break; case ISD::FP_TO_FP16: Res = PromoteIntRes_FP_TO_FP16(N); break; case ISD::FLT_ROUNDS_: Res = PromoteIntRes_FLT_ROUNDS(N); break; case ISD::AND: case ISD::OR: case ISD::XOR: case ISD::ADD: case ISD::SUB: case ISD::MUL: Res = PromoteIntRes_SimpleIntBinOp(N); break; case ISD::SDIV: case ISD::SREM: Res = PromoteIntRes_SExtIntBinOp(N); break; case ISD::UDIV: case ISD::UREM: Res = PromoteIntRes_ZExtIntBinOp(N); break; case ISD::SADDO: case ISD::SSUBO: Res = PromoteIntRes_SADDSUBO(N, ResNo); break; case ISD::UADDO: case ISD::USUBO: Res = PromoteIntRes_UADDSUBO(N, ResNo); break; case ISD::SMULO: case ISD::UMULO: Res = PromoteIntRes_XMULO(N, ResNo); break; case ISD::ADDE: case ISD::SUBE: case ISD::ADDCARRY: case ISD::SUBCARRY: Res = PromoteIntRes_ADDSUBCARRY(N, ResNo); break; case ISD::SADDSAT: case ISD::UADDSAT: case ISD::SSUBSAT: case ISD::USUBSAT: Res = PromoteIntRes_ADDSUBSAT(N); break; case ISD::SMULFIX: case ISD::SMULFIXSAT: case ISD::UMULFIX: case ISD::UMULFIXSAT: Res = PromoteIntRes_MULFIX(N); break; case ISD::SDIVFIX: case ISD::UDIVFIX: Res = PromoteIntRes_DIVFIX(N); break; case ISD::ABS: Res = PromoteIntRes_ABS(N); break; case ISD::ATOMIC_LOAD: Res = PromoteIntRes_Atomic0(cast(N)); break; case ISD::ATOMIC_LOAD_ADD: case ISD::ATOMIC_LOAD_SUB: case ISD::ATOMIC_LOAD_AND: case ISD::ATOMIC_LOAD_CLR: case ISD::ATOMIC_LOAD_OR: case ISD::ATOMIC_LOAD_XOR: case ISD::ATOMIC_LOAD_NAND: case ISD::ATOMIC_LOAD_MIN: case ISD::ATOMIC_LOAD_MAX: case ISD::ATOMIC_LOAD_UMIN: case ISD::ATOMIC_LOAD_UMAX: case ISD::ATOMIC_SWAP: Res = PromoteIntRes_Atomic1(cast(N)); break; case ISD::ATOMIC_CMP_SWAP: case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: Res = PromoteIntRes_AtomicCmpSwap(cast(N), ResNo); break; case ISD::VECREDUCE_ADD: case ISD::VECREDUCE_MUL: case ISD::VECREDUCE_AND: case ISD::VECREDUCE_OR: case ISD::VECREDUCE_XOR: case ISD::VECREDUCE_SMAX: case ISD::VECREDUCE_SMIN: case ISD::VECREDUCE_UMAX: case ISD::VECREDUCE_UMIN: Res = PromoteIntRes_VECREDUCE(N); break; } // If the result is null then the sub-method took care of registering it. if (Res.getNode()) SetPromotedInteger(SDValue(N, ResNo), Res); } SDValue DAGTypeLegalizer::PromoteIntRes_MERGE_VALUES(SDNode *N, unsigned ResNo) { SDValue Op = DisintegrateMERGE_VALUES(N, ResNo); return GetPromotedInteger(Op); } SDValue DAGTypeLegalizer::PromoteIntRes_AssertSext(SDNode *N) { // Sign-extend the new bits, and continue the assertion. SDValue Op = SExtPromotedInteger(N->getOperand(0)); return DAG.getNode(ISD::AssertSext, SDLoc(N), Op.getValueType(), Op, N->getOperand(1)); } SDValue DAGTypeLegalizer::PromoteIntRes_AssertZext(SDNode *N) { // Zero the new bits, and continue the assertion. SDValue Op = ZExtPromotedInteger(N->getOperand(0)); return DAG.getNode(ISD::AssertZext, SDLoc(N), Op.getValueType(), Op, N->getOperand(1)); } SDValue DAGTypeLegalizer::PromoteIntRes_Atomic0(AtomicSDNode *N) { EVT ResVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Res = DAG.getAtomic(N->getOpcode(), SDLoc(N), N->getMemoryVT(), ResVT, N->getChain(), N->getBasePtr(), N->getMemOperand()); // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); return Res; } SDValue DAGTypeLegalizer::PromoteIntRes_Atomic1(AtomicSDNode *N) { SDValue Op2 = GetPromotedInteger(N->getOperand(2)); SDValue Res = DAG.getAtomic(N->getOpcode(), SDLoc(N), N->getMemoryVT(), N->getChain(), N->getBasePtr(), Op2, N->getMemOperand()); // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); return Res; } SDValue DAGTypeLegalizer::PromoteIntRes_AtomicCmpSwap(AtomicSDNode *N, unsigned ResNo) { if (ResNo == 1) { assert(N->getOpcode() == ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS); EVT SVT = getSetCCResultType(N->getOperand(2).getValueType()); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(1)); // Only use the result of getSetCCResultType if it is legal, // otherwise just use the promoted result type (NVT). if (!TLI.isTypeLegal(SVT)) SVT = NVT; SDVTList VTs = DAG.getVTList(N->getValueType(0), SVT, MVT::Other); SDValue Res = DAG.getAtomicCmpSwap( ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, SDLoc(N), N->getMemoryVT(), VTs, N->getChain(), N->getBasePtr(), N->getOperand(2), N->getOperand(3), N->getMemOperand()); ReplaceValueWith(SDValue(N, 0), Res.getValue(0)); ReplaceValueWith(SDValue(N, 2), Res.getValue(2)); return Res.getValue(1); } - SDValue Op2 = GetPromotedInteger(N->getOperand(2)); + // Op2 is used for the comparison and thus must be extended according to the + // target's atomic operations. Op3 is merely stored and so can be left alone. + SDValue Op2 = N->getOperand(2); SDValue Op3 = GetPromotedInteger(N->getOperand(3)); + if (TLI.getTargetMachine().getTargetTriple().isRISCV()) { + // The comparison argument must be sign-extended for RISC-V. This is + // abstracted using a new TargetLowering hook in the main LLVM development + // branch, but handled here directly in order to fix the codegen bug for + // 10.x without breaking the libLLVM.so ABI. + Op2 = SExtPromotedInteger(Op2); + } else { + Op2 = GetPromotedInteger(Op2); + } + SDVTList VTs = DAG.getVTList(Op2.getValueType(), N->getValueType(1), MVT::Other); SDValue Res = DAG.getAtomicCmpSwap( N->getOpcode(), SDLoc(N), N->getMemoryVT(), VTs, N->getChain(), N->getBasePtr(), Op2, Op3, N->getMemOperand()); // Update the use to N with the newly created Res. for (unsigned i = 1, NumResults = N->getNumValues(); i < NumResults; ++i) ReplaceValueWith(SDValue(N, i), Res.getValue(i)); return Res; } SDValue DAGTypeLegalizer::PromoteIntRes_BITCAST(SDNode *N) { SDValue InOp = N->getOperand(0); EVT InVT = InOp.getValueType(); EVT NInVT = TLI.getTypeToTransformTo(*DAG.getContext(), InVT); EVT OutVT = N->getValueType(0); EVT NOutVT = TLI.getTypeToTransformTo(*DAG.getContext(), OutVT); SDLoc dl(N); switch (getTypeAction(InVT)) { case TargetLowering::TypeLegal: break; case TargetLowering::TypePromoteInteger: if (NOutVT.bitsEq(NInVT) && !NOutVT.isVector() && !NInVT.isVector()) // The input promotes to the same size. Convert the promoted value. return DAG.getNode(ISD::BITCAST, dl, NOutVT, GetPromotedInteger(InOp)); break; case TargetLowering::TypeSoftenFloat: // Promote the integer operand by hand. return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, GetSoftenedFloat(InOp)); case TargetLowering::TypePromoteFloat: { // Convert the promoted float by hand. if (!NOutVT.isVector()) return DAG.getNode(ISD::FP_TO_FP16, dl, NOutVT, GetPromotedFloat(InOp)); break; } case TargetLowering::TypeExpandInteger: case TargetLowering::TypeExpandFloat: break; case TargetLowering::TypeScalarizeVector: // Convert the element to an integer and promote it by hand. if (!NOutVT.isVector()) return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, BitConvertToInteger(GetScalarizedVector(InOp))); break; case TargetLowering::TypeSplitVector: { if (!NOutVT.isVector()) { // For example, i32 = BITCAST v2i16 on alpha. Convert the split // pieces of the input into integers and reassemble in the final type. SDValue Lo, Hi; GetSplitVector(N->getOperand(0), Lo, Hi); Lo = BitConvertToInteger(Lo); Hi = BitConvertToInteger(Hi); if (DAG.getDataLayout().isBigEndian()) std::swap(Lo, Hi); InOp = DAG.getNode(ISD::ANY_EXTEND, dl, EVT::getIntegerVT(*DAG.getContext(), NOutVT.getSizeInBits()), JoinIntegers(Lo, Hi)); return DAG.getNode(ISD::BITCAST, dl, NOutVT, InOp); } break; } case TargetLowering::TypeWidenVector: // The input is widened to the same size. Convert to the widened value. // Make sure that the outgoing value is not a vector, because this would // make us bitcast between two vectors which are legalized in different ways. if (NOutVT.bitsEq(NInVT) && !NOutVT.isVector()) { SDValue Res = DAG.getNode(ISD::BITCAST, dl, NOutVT, GetWidenedVector(InOp)); // For big endian targets we need to shift the casted value or the // interesting bits will end up at the wrong place. if (DAG.getDataLayout().isBigEndian()) { unsigned ShiftAmt = NInVT.getSizeInBits() - InVT.getSizeInBits(); EVT ShiftAmtTy = TLI.getShiftAmountTy(NOutVT, DAG.getDataLayout()); assert(ShiftAmt < NOutVT.getSizeInBits() && "Too large shift amount!"); Res = DAG.getNode(ISD::SRL, dl, NOutVT, Res, DAG.getConstant(ShiftAmt, dl, ShiftAmtTy)); } return Res; } // If the output type is also a vector and widening it to the same size // as the widened input type would be a legal type, we can widen the bitcast // and handle the promotion after. if (NOutVT.isVector()) { unsigned WidenInSize = NInVT.getSizeInBits(); unsigned OutSize = OutVT.getSizeInBits(); if (WidenInSize % OutSize == 0) { unsigned Scale = WidenInSize / OutSize; EVT WideOutVT = EVT::getVectorVT(*DAG.getContext(), OutVT.getVectorElementType(), OutVT.getVectorNumElements() * Scale); if (isTypeLegal(WideOutVT)) { InOp = DAG.getBitcast(WideOutVT, GetWidenedVector(InOp)); MVT IdxTy = TLI.getVectorIdxTy(DAG.getDataLayout()); InOp = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, OutVT, InOp, DAG.getConstant(0, dl, IdxTy)); return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, InOp); } } } } return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, CreateStackStoreLoad(InOp, OutVT)); } // Helper for BSWAP/BITREVERSE promotion to ensure we can fit any shift amount // in the VT returned by getShiftAmountTy and to return a safe VT if we can't. static EVT getShiftAmountTyForConstant(EVT VT, const TargetLowering &TLI, SelectionDAG &DAG) { EVT ShiftVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); // If any possible shift value won't fit in the prefered type, just use // something safe. It will be legalized when the shift is expanded. if (!ShiftVT.isVector() && ShiftVT.getSizeInBits() < Log2_32_Ceil(VT.getSizeInBits())) ShiftVT = MVT::i32; return ShiftVT; } SDValue DAGTypeLegalizer::PromoteIntRes_BSWAP(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); EVT OVT = N->getValueType(0); EVT NVT = Op.getValueType(); SDLoc dl(N); unsigned DiffBits = NVT.getScalarSizeInBits() - OVT.getScalarSizeInBits(); EVT ShiftVT = getShiftAmountTyForConstant(NVT, TLI, DAG); return DAG.getNode(ISD::SRL, dl, NVT, DAG.getNode(ISD::BSWAP, dl, NVT, Op), DAG.getConstant(DiffBits, dl, ShiftVT)); } SDValue DAGTypeLegalizer::PromoteIntRes_BITREVERSE(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); EVT OVT = N->getValueType(0); EVT NVT = Op.getValueType(); SDLoc dl(N); unsigned DiffBits = NVT.getScalarSizeInBits() - OVT.getScalarSizeInBits(); EVT ShiftVT = getShiftAmountTyForConstant(NVT, TLI, DAG); return DAG.getNode(ISD::SRL, dl, NVT, DAG.getNode(ISD::BITREVERSE, dl, NVT, Op), DAG.getConstant(DiffBits, dl, ShiftVT)); } SDValue DAGTypeLegalizer::PromoteIntRes_BUILD_PAIR(SDNode *N) { // The pair element type may be legal, or may not promote to the same type as // the result, for example i14 = BUILD_PAIR (i7, i7). Handle all cases. return DAG.getNode(ISD::ANY_EXTEND, SDLoc(N), TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)), JoinIntegers(N->getOperand(0), N->getOperand(1))); } SDValue DAGTypeLegalizer::PromoteIntRes_Constant(SDNode *N) { EVT VT = N->getValueType(0); // FIXME there is no actual debug info here SDLoc dl(N); // Zero extend things like i1, sign extend everything else. It shouldn't // matter in theory which one we pick, but this tends to give better code? unsigned Opc = VT.isByteSized() ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; SDValue Result = DAG.getNode(Opc, dl, TLI.getTypeToTransformTo(*DAG.getContext(), VT), SDValue(N, 0)); assert(isa(Result) && "Didn't constant fold ext?"); return Result; } SDValue DAGTypeLegalizer::PromoteIntRes_CTLZ(SDNode *N) { // Zero extend to the promoted type and do the count there. SDValue Op = ZExtPromotedInteger(N->getOperand(0)); SDLoc dl(N); EVT OVT = N->getValueType(0); EVT NVT = Op.getValueType(); Op = DAG.getNode(N->getOpcode(), dl, NVT, Op); // Subtract off the extra leading bits in the bigger type. return DAG.getNode( ISD::SUB, dl, NVT, Op, DAG.getConstant(NVT.getScalarSizeInBits() - OVT.getScalarSizeInBits(), dl, NVT)); } SDValue DAGTypeLegalizer::PromoteIntRes_CTPOP(SDNode *N) { // Zero extend to the promoted type and do the count there. SDValue Op = ZExtPromotedInteger(N->getOperand(0)); return DAG.getNode(ISD::CTPOP, SDLoc(N), Op.getValueType(), Op); } SDValue DAGTypeLegalizer::PromoteIntRes_CTTZ(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); EVT OVT = N->getValueType(0); EVT NVT = Op.getValueType(); SDLoc dl(N); if (N->getOpcode() == ISD::CTTZ) { // The count is the same in the promoted type except if the original // value was zero. This can be handled by setting the bit just off // the top of the original type. auto TopBit = APInt::getOneBitSet(NVT.getScalarSizeInBits(), OVT.getScalarSizeInBits()); Op = DAG.getNode(ISD::OR, dl, NVT, Op, DAG.getConstant(TopBit, dl, NVT)); } return DAG.getNode(N->getOpcode(), dl, NVT, Op); } SDValue DAGTypeLegalizer::PromoteIntRes_EXTRACT_VECTOR_ELT(SDNode *N) { SDLoc dl(N); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Op0 = N->getOperand(0); SDValue Op1 = N->getOperand(1); // If the input also needs to be promoted, do that first so we can get a // get a good idea for the output type. if (TLI.getTypeAction(*DAG.getContext(), Op0.getValueType()) == TargetLowering::TypePromoteInteger) { SDValue In = GetPromotedInteger(Op0); // If the new type is larger than NVT, use it. We probably won't need to // promote it again. EVT SVT = In.getValueType().getScalarType(); if (SVT.bitsGE(NVT)) { SDValue Ext = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, SVT, In, Op1); return DAG.getAnyExtOrTrunc(Ext, dl, NVT); } } return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, NVT, Op0, Op1); } SDValue DAGTypeLegalizer::PromoteIntRes_FP_TO_XINT(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); unsigned NewOpc = N->getOpcode(); SDLoc dl(N); // If we're promoting a UINT to a larger size and the larger FP_TO_UINT is // not Legal, check to see if we can use FP_TO_SINT instead. (If both UINT // and SINT conversions are Custom, there is no way to tell which is // preferable. We choose SINT because that's the right thing on PPC.) if (N->getOpcode() == ISD::FP_TO_UINT && !TLI.isOperationLegal(ISD::FP_TO_UINT, NVT) && TLI.isOperationLegalOrCustom(ISD::FP_TO_SINT, NVT)) NewOpc = ISD::FP_TO_SINT; if (N->getOpcode() == ISD::STRICT_FP_TO_UINT && !TLI.isOperationLegal(ISD::STRICT_FP_TO_UINT, NVT) && TLI.isOperationLegalOrCustom(ISD::STRICT_FP_TO_SINT, NVT)) NewOpc = ISD::STRICT_FP_TO_SINT; SDValue Res; if (N->isStrictFPOpcode()) { Res = DAG.getNode(NewOpc, dl, { NVT, MVT::Other }, { N->getOperand(0), N->getOperand(1) }); // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); } else Res = DAG.getNode(NewOpc, dl, NVT, N->getOperand(0)); // Assert that the converted value fits in the original type. If it doesn't // (eg: because the value being converted is too big), then the result of the // original operation was undefined anyway, so the assert is still correct. // // NOTE: fp-to-uint to fp-to-sint promotion guarantees zero extend. For example: // before legalization: fp-to-uint16, 65534. -> 0xfffe // after legalization: fp-to-sint32, 65534. -> 0x0000fffe return DAG.getNode((N->getOpcode() == ISD::FP_TO_UINT || N->getOpcode() == ISD::STRICT_FP_TO_UINT) ? ISD::AssertZext : ISD::AssertSext, dl, NVT, Res, DAG.getValueType(N->getValueType(0).getScalarType())); } SDValue DAGTypeLegalizer::PromoteIntRes_FP_TO_FP16(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDLoc dl(N); return DAG.getNode(N->getOpcode(), dl, NVT, N->getOperand(0)); } SDValue DAGTypeLegalizer::PromoteIntRes_FLT_ROUNDS(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDLoc dl(N); return DAG.getNode(N->getOpcode(), dl, NVT); } SDValue DAGTypeLegalizer::PromoteIntRes_INT_EXTEND(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDLoc dl(N); if (getTypeAction(N->getOperand(0).getValueType()) == TargetLowering::TypePromoteInteger) { SDValue Res = GetPromotedInteger(N->getOperand(0)); assert(Res.getValueType().bitsLE(NVT) && "Extension doesn't make sense!"); // If the result and operand types are the same after promotion, simplify // to an in-register extension. if (NVT == Res.getValueType()) { // The high bits are not guaranteed to be anything. Insert an extend. if (N->getOpcode() == ISD::SIGN_EXTEND) return DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, NVT, Res, DAG.getValueType(N->getOperand(0).getValueType())); if (N->getOpcode() == ISD::ZERO_EXTEND) return DAG.getZeroExtendInReg(Res, dl, N->getOperand(0).getValueType().getScalarType()); assert(N->getOpcode() == ISD::ANY_EXTEND && "Unknown integer extension!"); return Res; } } // Otherwise, just extend the original operand all the way to the larger type. return DAG.getNode(N->getOpcode(), dl, NVT, N->getOperand(0)); } SDValue DAGTypeLegalizer::PromoteIntRes_LOAD(LoadSDNode *N) { assert(ISD::isUNINDEXEDLoad(N) && "Indexed load during type legalization!"); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); ISD::LoadExtType ExtType = ISD::isNON_EXTLoad(N) ? ISD::EXTLOAD : N->getExtensionType(); SDLoc dl(N); SDValue Res = DAG.getExtLoad(ExtType, dl, NVT, N->getChain(), N->getBasePtr(), N->getMemoryVT(), N->getMemOperand()); // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); return Res; } SDValue DAGTypeLegalizer::PromoteIntRes_MLOAD(MaskedLoadSDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue ExtPassThru = GetPromotedInteger(N->getPassThru()); SDLoc dl(N); SDValue Res = DAG.getMaskedLoad(NVT, dl, N->getChain(), N->getBasePtr(), N->getOffset(), N->getMask(), ExtPassThru, N->getMemoryVT(), N->getMemOperand(), N->getAddressingMode(), ISD::EXTLOAD); // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); return Res; } SDValue DAGTypeLegalizer::PromoteIntRes_MGATHER(MaskedGatherSDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue ExtPassThru = GetPromotedInteger(N->getPassThru()); assert(NVT == ExtPassThru.getValueType() && "Gather result type and the passThru argument type should be the same"); SDLoc dl(N); SDValue Ops[] = {N->getChain(), ExtPassThru, N->getMask(), N->getBasePtr(), N->getIndex(), N->getScale() }; SDValue Res = DAG.getMaskedGather(DAG.getVTList(NVT, MVT::Other), N->getMemoryVT(), dl, Ops, N->getMemOperand(), N->getIndexType()); // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); return Res; } /// Promote the overflow flag of an overflowing arithmetic node. SDValue DAGTypeLegalizer::PromoteIntRes_Overflow(SDNode *N) { // Change the return type of the boolean result while obeying // getSetCCResultType. EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(1)); EVT VT = N->getValueType(0); EVT SVT = getSetCCResultType(VT); SDValue Ops[3] = { N->getOperand(0), N->getOperand(1) }; unsigned NumOps = N->getNumOperands(); assert(NumOps <= 3 && "Too many operands"); if (NumOps == 3) Ops[2] = N->getOperand(2); SDLoc dl(N); SDValue Res = DAG.getNode(N->getOpcode(), dl, DAG.getVTList(VT, SVT), makeArrayRef(Ops, NumOps)); // Modified the sum result - switch anything that used the old sum to use // the new one. ReplaceValueWith(SDValue(N, 0), Res); // Convert to the expected type. return DAG.getBoolExtOrTrunc(Res.getValue(1), dl, NVT, VT); } SDValue DAGTypeLegalizer::PromoteIntRes_ADDSUBSAT(SDNode *N) { // If the promoted type is legal, we can convert this to: // 1. ANY_EXTEND iN to iM // 2. SHL by M-N // 3. [US][ADD|SUB]SAT // 4. L/ASHR by M-N // Else it is more efficient to convert this to a min and a max // operation in the higher precision arithmetic. SDLoc dl(N); SDValue Op1 = N->getOperand(0); SDValue Op2 = N->getOperand(1); unsigned OldBits = Op1.getScalarValueSizeInBits(); unsigned Opcode = N->getOpcode(); SDValue Op1Promoted, Op2Promoted; if (Opcode == ISD::UADDSAT || Opcode == ISD::USUBSAT) { Op1Promoted = ZExtPromotedInteger(Op1); Op2Promoted = ZExtPromotedInteger(Op2); } else { Op1Promoted = SExtPromotedInteger(Op1); Op2Promoted = SExtPromotedInteger(Op2); } EVT PromotedType = Op1Promoted.getValueType(); unsigned NewBits = PromotedType.getScalarSizeInBits(); if (TLI.isOperationLegalOrCustom(Opcode, PromotedType)) { unsigned ShiftOp; switch (Opcode) { case ISD::SADDSAT: case ISD::SSUBSAT: ShiftOp = ISD::SRA; break; case ISD::UADDSAT: case ISD::USUBSAT: ShiftOp = ISD::SRL; break; default: llvm_unreachable("Expected opcode to be signed or unsigned saturation " "addition or subtraction"); } unsigned SHLAmount = NewBits - OldBits; EVT SHVT = TLI.getShiftAmountTy(PromotedType, DAG.getDataLayout()); SDValue ShiftAmount = DAG.getConstant(SHLAmount, dl, SHVT); Op1Promoted = DAG.getNode(ISD::SHL, dl, PromotedType, Op1Promoted, ShiftAmount); Op2Promoted = DAG.getNode(ISD::SHL, dl, PromotedType, Op2Promoted, ShiftAmount); SDValue Result = DAG.getNode(Opcode, dl, PromotedType, Op1Promoted, Op2Promoted); return DAG.getNode(ShiftOp, dl, PromotedType, Result, ShiftAmount); } else { if (Opcode == ISD::USUBSAT) { SDValue Max = DAG.getNode(ISD::UMAX, dl, PromotedType, Op1Promoted, Op2Promoted); return DAG.getNode(ISD::SUB, dl, PromotedType, Max, Op2Promoted); } if (Opcode == ISD::UADDSAT) { APInt MaxVal = APInt::getAllOnesValue(OldBits).zext(NewBits); SDValue SatMax = DAG.getConstant(MaxVal, dl, PromotedType); SDValue Add = DAG.getNode(ISD::ADD, dl, PromotedType, Op1Promoted, Op2Promoted); return DAG.getNode(ISD::UMIN, dl, PromotedType, Add, SatMax); } unsigned AddOp = Opcode == ISD::SADDSAT ? ISD::ADD : ISD::SUB; APInt MinVal = APInt::getSignedMinValue(OldBits).sext(NewBits); APInt MaxVal = APInt::getSignedMaxValue(OldBits).sext(NewBits); SDValue SatMin = DAG.getConstant(MinVal, dl, PromotedType); SDValue SatMax = DAG.getConstant(MaxVal, dl, PromotedType); SDValue Result = DAG.getNode(AddOp, dl, PromotedType, Op1Promoted, Op2Promoted); Result = DAG.getNode(ISD::SMIN, dl, PromotedType, Result, SatMax); Result = DAG.getNode(ISD::SMAX, dl, PromotedType, Result, SatMin); return Result; } } SDValue DAGTypeLegalizer::PromoteIntRes_MULFIX(SDNode *N) { // Can just promote the operands then continue with operation. SDLoc dl(N); SDValue Op1Promoted, Op2Promoted; bool Signed = N->getOpcode() == ISD::SMULFIX || N->getOpcode() == ISD::SMULFIXSAT; bool Saturating = N->getOpcode() == ISD::SMULFIXSAT || N->getOpcode() == ISD::UMULFIXSAT; if (Signed) { Op1Promoted = SExtPromotedInteger(N->getOperand(0)); Op2Promoted = SExtPromotedInteger(N->getOperand(1)); } else { Op1Promoted = ZExtPromotedInteger(N->getOperand(0)); Op2Promoted = ZExtPromotedInteger(N->getOperand(1)); } EVT OldType = N->getOperand(0).getValueType(); EVT PromotedType = Op1Promoted.getValueType(); unsigned DiffSize = PromotedType.getScalarSizeInBits() - OldType.getScalarSizeInBits(); if (Saturating) { // Promoting the operand and result values changes the saturation width, // which is extends the values that we clamp to on saturation. This could be // resolved by shifting one of the operands the same amount, which would // also shift the result we compare against, then shifting back. EVT ShiftTy = TLI.getShiftAmountTy(PromotedType, DAG.getDataLayout()); Op1Promoted = DAG.getNode(ISD::SHL, dl, PromotedType, Op1Promoted, DAG.getConstant(DiffSize, dl, ShiftTy)); SDValue Result = DAG.getNode(N->getOpcode(), dl, PromotedType, Op1Promoted, Op2Promoted, N->getOperand(2)); unsigned ShiftOp = Signed ? ISD::SRA : ISD::SRL; return DAG.getNode(ShiftOp, dl, PromotedType, Result, DAG.getConstant(DiffSize, dl, ShiftTy)); } return DAG.getNode(N->getOpcode(), dl, PromotedType, Op1Promoted, Op2Promoted, N->getOperand(2)); } static SDValue earlyExpandDIVFIX(SDNode *N, SDValue LHS, SDValue RHS, unsigned Scale, const TargetLowering &TLI, SelectionDAG &DAG) { EVT VT = LHS.getValueType(); bool Signed = N->getOpcode() == ISD::SDIVFIX; SDLoc dl(N); // See if we can perform the division in this type without widening. if (SDValue V = TLI.expandFixedPointDiv(N->getOpcode(), dl, LHS, RHS, Scale, DAG)) return V; // If that didn't work, double the type width and try again. That must work, // or something is wrong. EVT WideVT = EVT::getIntegerVT(*DAG.getContext(), VT.getScalarSizeInBits() * 2); if (Signed) { LHS = DAG.getSExtOrTrunc(LHS, dl, WideVT); RHS = DAG.getSExtOrTrunc(RHS, dl, WideVT); } else { LHS = DAG.getZExtOrTrunc(LHS, dl, WideVT); RHS = DAG.getZExtOrTrunc(RHS, dl, WideVT); } // TODO: Saturation. SDValue Res = TLI.expandFixedPointDiv(N->getOpcode(), dl, LHS, RHS, Scale, DAG); assert(Res && "Expanding DIVFIX with wide type failed?"); return DAG.getZExtOrTrunc(Res, dl, VT); } SDValue DAGTypeLegalizer::PromoteIntRes_DIVFIX(SDNode *N) { SDLoc dl(N); SDValue Op1Promoted, Op2Promoted; bool Signed = N->getOpcode() == ISD::SDIVFIX; if (Signed) { Op1Promoted = SExtPromotedInteger(N->getOperand(0)); Op2Promoted = SExtPromotedInteger(N->getOperand(1)); } else { Op1Promoted = ZExtPromotedInteger(N->getOperand(0)); Op2Promoted = ZExtPromotedInteger(N->getOperand(1)); } EVT PromotedType = Op1Promoted.getValueType(); unsigned Scale = N->getConstantOperandVal(2); SDValue Res; // If the type is already legal and the operation is legal in that type, we // should not early expand. if (TLI.isTypeLegal(PromotedType)) { TargetLowering::LegalizeAction Action = TLI.getFixedPointOperationAction(N->getOpcode(), PromotedType, Scale); if (Action == TargetLowering::Legal || Action == TargetLowering::Custom) Res = DAG.getNode(N->getOpcode(), dl, PromotedType, Op1Promoted, Op2Promoted, N->getOperand(2)); } if (!Res) Res = earlyExpandDIVFIX(N, Op1Promoted, Op2Promoted, Scale, TLI, DAG); // TODO: Saturation. return Res; } SDValue DAGTypeLegalizer::PromoteIntRes_SADDSUBO(SDNode *N, unsigned ResNo) { if (ResNo == 1) return PromoteIntRes_Overflow(N); // The operation overflowed iff the result in the larger type is not the // sign extension of its truncation to the original type. SDValue LHS = SExtPromotedInteger(N->getOperand(0)); SDValue RHS = SExtPromotedInteger(N->getOperand(1)); EVT OVT = N->getOperand(0).getValueType(); EVT NVT = LHS.getValueType(); SDLoc dl(N); // Do the arithmetic in the larger type. unsigned Opcode = N->getOpcode() == ISD::SADDO ? ISD::ADD : ISD::SUB; SDValue Res = DAG.getNode(Opcode, dl, NVT, LHS, RHS); // Calculate the overflow flag: sign extend the arithmetic result from // the original type. SDValue Ofl = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, NVT, Res, DAG.getValueType(OVT)); // Overflowed if and only if this is not equal to Res. Ofl = DAG.getSetCC(dl, N->getValueType(1), Ofl, Res, ISD::SETNE); // Use the calculated overflow everywhere. ReplaceValueWith(SDValue(N, 1), Ofl); return Res; } SDValue DAGTypeLegalizer::PromoteIntRes_SELECT(SDNode *N) { SDValue LHS = GetPromotedInteger(N->getOperand(1)); SDValue RHS = GetPromotedInteger(N->getOperand(2)); return DAG.getSelect(SDLoc(N), LHS.getValueType(), N->getOperand(0), LHS, RHS); } SDValue DAGTypeLegalizer::PromoteIntRes_VSELECT(SDNode *N) { SDValue Mask = N->getOperand(0); SDValue LHS = GetPromotedInteger(N->getOperand(1)); SDValue RHS = GetPromotedInteger(N->getOperand(2)); return DAG.getNode(ISD::VSELECT, SDLoc(N), LHS.getValueType(), Mask, LHS, RHS); } SDValue DAGTypeLegalizer::PromoteIntRes_SELECT_CC(SDNode *N) { SDValue LHS = GetPromotedInteger(N->getOperand(2)); SDValue RHS = GetPromotedInteger(N->getOperand(3)); return DAG.getNode(ISD::SELECT_CC, SDLoc(N), LHS.getValueType(), N->getOperand(0), N->getOperand(1), LHS, RHS, N->getOperand(4)); } SDValue DAGTypeLegalizer::PromoteIntRes_SETCC(SDNode *N) { unsigned OpNo = N->isStrictFPOpcode() ? 1 : 0; EVT InVT = N->getOperand(OpNo).getValueType(); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); EVT SVT = getSetCCResultType(InVT); // If we got back a type that needs to be promoted, this likely means the // the input type also needs to be promoted. So get the promoted type for // the input and try the query again. if (getTypeAction(SVT) == TargetLowering::TypePromoteInteger) { if (getTypeAction(InVT) == TargetLowering::TypePromoteInteger) { InVT = TLI.getTypeToTransformTo(*DAG.getContext(), InVT); SVT = getSetCCResultType(InVT); } else { // Input type isn't promoted, just use the default promoted type. SVT = NVT; } } SDLoc dl(N); assert(SVT.isVector() == N->getOperand(OpNo).getValueType().isVector() && "Vector compare must return a vector result!"); // Get the SETCC result using the canonical SETCC type. SDValue SetCC; if (N->isStrictFPOpcode()) { EVT VTs[] = {SVT, MVT::Other}; SDValue Opers[] = {N->getOperand(0), N->getOperand(1), N->getOperand(2), N->getOperand(3)}; SetCC = DAG.getNode(N->getOpcode(), dl, VTs, Opers); // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), SetCC.getValue(1)); } else SetCC = DAG.getNode(N->getOpcode(), dl, SVT, N->getOperand(0), N->getOperand(1), N->getOperand(2)); // Convert to the expected type. return DAG.getSExtOrTrunc(SetCC, dl, NVT); } SDValue DAGTypeLegalizer::PromoteIntRes_SHL(SDNode *N) { SDValue LHS = GetPromotedInteger(N->getOperand(0)); SDValue RHS = N->getOperand(1); if (getTypeAction(RHS.getValueType()) == TargetLowering::TypePromoteInteger) RHS = ZExtPromotedInteger(RHS); return DAG.getNode(ISD::SHL, SDLoc(N), LHS.getValueType(), LHS, RHS); } SDValue DAGTypeLegalizer::PromoteIntRes_SIGN_EXTEND_INREG(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); return DAG.getNode(ISD::SIGN_EXTEND_INREG, SDLoc(N), Op.getValueType(), Op, N->getOperand(1)); } SDValue DAGTypeLegalizer::PromoteIntRes_SimpleIntBinOp(SDNode *N) { // The input may have strange things in the top bits of the registers, but // these operations don't care. They may have weird bits going out, but // that too is okay if they are integer operations. SDValue LHS = GetPromotedInteger(N->getOperand(0)); SDValue RHS = GetPromotedInteger(N->getOperand(1)); return DAG.getNode(N->getOpcode(), SDLoc(N), LHS.getValueType(), LHS, RHS); } SDValue DAGTypeLegalizer::PromoteIntRes_SExtIntBinOp(SDNode *N) { // Sign extend the input. SDValue LHS = SExtPromotedInteger(N->getOperand(0)); SDValue RHS = SExtPromotedInteger(N->getOperand(1)); return DAG.getNode(N->getOpcode(), SDLoc(N), LHS.getValueType(), LHS, RHS); } SDValue DAGTypeLegalizer::PromoteIntRes_ZExtIntBinOp(SDNode *N) { // Zero extend the input. SDValue LHS = ZExtPromotedInteger(N->getOperand(0)); SDValue RHS = ZExtPromotedInteger(N->getOperand(1)); return DAG.getNode(N->getOpcode(), SDLoc(N), LHS.getValueType(), LHS, RHS); } SDValue DAGTypeLegalizer::PromoteIntRes_SRA(SDNode *N) { // The input value must be properly sign extended. SDValue LHS = SExtPromotedInteger(N->getOperand(0)); SDValue RHS = N->getOperand(1); if (getTypeAction(RHS.getValueType()) == TargetLowering::TypePromoteInteger) RHS = ZExtPromotedInteger(RHS); return DAG.getNode(ISD::SRA, SDLoc(N), LHS.getValueType(), LHS, RHS); } SDValue DAGTypeLegalizer::PromoteIntRes_SRL(SDNode *N) { // The input value must be properly zero extended. SDValue LHS = ZExtPromotedInteger(N->getOperand(0)); SDValue RHS = N->getOperand(1); if (getTypeAction(RHS.getValueType()) == TargetLowering::TypePromoteInteger) RHS = ZExtPromotedInteger(RHS); return DAG.getNode(ISD::SRL, SDLoc(N), LHS.getValueType(), LHS, RHS); } SDValue DAGTypeLegalizer::PromoteIntRes_TRUNCATE(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Res; SDValue InOp = N->getOperand(0); SDLoc dl(N); switch (getTypeAction(InOp.getValueType())) { default: llvm_unreachable("Unknown type action!"); case TargetLowering::TypeLegal: case TargetLowering::TypeExpandInteger: Res = InOp; break; case TargetLowering::TypePromoteInteger: Res = GetPromotedInteger(InOp); break; case TargetLowering::TypeSplitVector: { EVT InVT = InOp.getValueType(); assert(InVT.isVector() && "Cannot split scalar types"); unsigned NumElts = InVT.getVectorNumElements(); assert(NumElts == NVT.getVectorNumElements() && "Dst and Src must have the same number of elements"); assert(isPowerOf2_32(NumElts) && "Promoted vector type must be a power of two"); SDValue EOp1, EOp2; GetSplitVector(InOp, EOp1, EOp2); EVT HalfNVT = EVT::getVectorVT(*DAG.getContext(), NVT.getScalarType(), NumElts/2); EOp1 = DAG.getNode(ISD::TRUNCATE, dl, HalfNVT, EOp1); EOp2 = DAG.getNode(ISD::TRUNCATE, dl, HalfNVT, EOp2); return DAG.getNode(ISD::CONCAT_VECTORS, dl, NVT, EOp1, EOp2); } case TargetLowering::TypeWidenVector: { SDValue WideInOp = GetWidenedVector(InOp); // Truncate widened InOp. unsigned NumElem = WideInOp.getValueType().getVectorNumElements(); EVT TruncVT = EVT::getVectorVT(*DAG.getContext(), N->getValueType(0).getScalarType(), NumElem); SDValue WideTrunc = DAG.getNode(ISD::TRUNCATE, dl, TruncVT, WideInOp); // Zero extend so that the elements are of same type as those of NVT EVT ExtVT = EVT::getVectorVT(*DAG.getContext(), NVT.getVectorElementType(), NumElem); SDValue WideExt = DAG.getNode(ISD::ZERO_EXTEND, dl, ExtVT, WideTrunc); // Extract the low NVT subvector. MVT IdxTy = TLI.getVectorIdxTy(DAG.getDataLayout()); SDValue ZeroIdx = DAG.getConstant(0, dl, IdxTy); return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, NVT, WideExt, ZeroIdx); } } // Truncate to NVT instead of VT return DAG.getNode(ISD::TRUNCATE, dl, NVT, Res); } SDValue DAGTypeLegalizer::PromoteIntRes_UADDSUBO(SDNode *N, unsigned ResNo) { if (ResNo == 1) return PromoteIntRes_Overflow(N); // The operation overflowed iff the result in the larger type is not the // zero extension of its truncation to the original type. SDValue LHS = ZExtPromotedInteger(N->getOperand(0)); SDValue RHS = ZExtPromotedInteger(N->getOperand(1)); EVT OVT = N->getOperand(0).getValueType(); EVT NVT = LHS.getValueType(); SDLoc dl(N); // Do the arithmetic in the larger type. unsigned Opcode = N->getOpcode() == ISD::UADDO ? ISD::ADD : ISD::SUB; SDValue Res = DAG.getNode(Opcode, dl, NVT, LHS, RHS); // Calculate the overflow flag: zero extend the arithmetic result from // the original type. SDValue Ofl = DAG.getZeroExtendInReg(Res, dl, OVT.getScalarType()); // Overflowed if and only if this is not equal to Res. Ofl = DAG.getSetCC(dl, N->getValueType(1), Ofl, Res, ISD::SETNE); // Use the calculated overflow everywhere. ReplaceValueWith(SDValue(N, 1), Ofl); return Res; } // Handle promotion for the ADDE/SUBE/ADDCARRY/SUBCARRY nodes. Notice that // the third operand of ADDE/SUBE nodes is carry flag, which differs from // the ADDCARRY/SUBCARRY nodes in that the third operand is carry Boolean. SDValue DAGTypeLegalizer::PromoteIntRes_ADDSUBCARRY(SDNode *N, unsigned ResNo) { if (ResNo == 1) return PromoteIntRes_Overflow(N); // We need to sign-extend the operands so the carry value computed by the // wide operation will be equivalent to the carry value computed by the // narrow operation. // An ADDCARRY can generate carry only if any of the operands has its // most significant bit set. Sign extension propagates the most significant // bit into the higher bits which means the extra bit that the narrow // addition would need (i.e. the carry) will be propagated through the higher // bits of the wide addition. // A SUBCARRY can generate borrow only if LHS < RHS and this property will be // preserved by sign extension. SDValue LHS = SExtPromotedInteger(N->getOperand(0)); SDValue RHS = SExtPromotedInteger(N->getOperand(1)); EVT ValueVTs[] = {LHS.getValueType(), N->getValueType(1)}; // Do the arithmetic in the wide type. SDValue Res = DAG.getNode(N->getOpcode(), SDLoc(N), DAG.getVTList(ValueVTs), LHS, RHS, N->getOperand(2)); // Update the users of the original carry/borrow value. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); return SDValue(Res.getNode(), 0); } SDValue DAGTypeLegalizer::PromoteIntRes_ABS(SDNode *N) { SDValue Op0 = SExtPromotedInteger(N->getOperand(0)); return DAG.getNode(ISD::ABS, SDLoc(N), Op0.getValueType(), Op0); } SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) { // Promote the overflow bit trivially. if (ResNo == 1) return PromoteIntRes_Overflow(N); SDValue LHS = N->getOperand(0), RHS = N->getOperand(1); SDLoc DL(N); EVT SmallVT = LHS.getValueType(); // To determine if the result overflowed in a larger type, we extend the // input to the larger type, do the multiply (checking if it overflows), // then also check the high bits of the result to see if overflow happened // there. if (N->getOpcode() == ISD::SMULO) { LHS = SExtPromotedInteger(LHS); RHS = SExtPromotedInteger(RHS); } else { LHS = ZExtPromotedInteger(LHS); RHS = ZExtPromotedInteger(RHS); } SDVTList VTs = DAG.getVTList(LHS.getValueType(), N->getValueType(1)); SDValue Mul = DAG.getNode(N->getOpcode(), DL, VTs, LHS, RHS); // Overflow occurred if it occurred in the larger type, or if the high part // of the result does not zero/sign-extend the low part. Check this second // possibility first. SDValue Overflow; if (N->getOpcode() == ISD::UMULO) { // Unsigned overflow occurred if the high part is non-zero. unsigned Shift = SmallVT.getScalarSizeInBits(); EVT ShiftTy = getShiftAmountTyForConstant(Mul.getValueType(), TLI, DAG); SDValue Hi = DAG.getNode(ISD::SRL, DL, Mul.getValueType(), Mul, DAG.getConstant(Shift, DL, ShiftTy)); Overflow = DAG.getSetCC(DL, N->getValueType(1), Hi, DAG.getConstant(0, DL, Hi.getValueType()), ISD::SETNE); } else { // Signed overflow occurred if the high part does not sign extend the low. SDValue SExt = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Mul.getValueType(), Mul, DAG.getValueType(SmallVT)); Overflow = DAG.getSetCC(DL, N->getValueType(1), SExt, Mul, ISD::SETNE); } // The only other way for overflow to occur is if the multiplication in the // larger type itself overflowed. Overflow = DAG.getNode(ISD::OR, DL, N->getValueType(1), Overflow, SDValue(Mul.getNode(), 1)); // Use the calculated overflow everywhere. ReplaceValueWith(SDValue(N, 1), Overflow); return Mul; } SDValue DAGTypeLegalizer::PromoteIntRes_UNDEF(SDNode *N) { return DAG.getUNDEF(TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0))); } SDValue DAGTypeLegalizer::PromoteIntRes_VAARG(SDNode *N) { SDValue Chain = N->getOperand(0); // Get the chain. SDValue Ptr = N->getOperand(1); // Get the pointer. EVT VT = N->getValueType(0); SDLoc dl(N); MVT RegVT = TLI.getRegisterType(*DAG.getContext(), VT); unsigned NumRegs = TLI.getNumRegisters(*DAG.getContext(), VT); // The argument is passed as NumRegs registers of type RegVT. SmallVector Parts(NumRegs); for (unsigned i = 0; i < NumRegs; ++i) { Parts[i] = DAG.getVAArg(RegVT, dl, Chain, Ptr, N->getOperand(2), N->getConstantOperandVal(3)); Chain = Parts[i].getValue(1); } // Handle endianness of the load. if (DAG.getDataLayout().isBigEndian()) std::reverse(Parts.begin(), Parts.end()); // Assemble the parts in the promoted type. EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Res = DAG.getNode(ISD::ZERO_EXTEND, dl, NVT, Parts[0]); for (unsigned i = 1; i < NumRegs; ++i) { SDValue Part = DAG.getNode(ISD::ZERO_EXTEND, dl, NVT, Parts[i]); // Shift it to the right position and "or" it in. Part = DAG.getNode(ISD::SHL, dl, NVT, Part, DAG.getConstant(i * RegVT.getSizeInBits(), dl, TLI.getPointerTy(DAG.getDataLayout()))); Res = DAG.getNode(ISD::OR, dl, NVT, Res, Part); } // Modified the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Chain); return Res; } //===----------------------------------------------------------------------===// // Integer Operand Promotion //===----------------------------------------------------------------------===// /// PromoteIntegerOperand - This method is called when the specified operand of /// the specified node is found to need promotion. At this point, all of the /// result types of the node are known to be legal, but other operands of the /// node may need promotion or expansion as well as the specified one. bool DAGTypeLegalizer::PromoteIntegerOperand(SDNode *N, unsigned OpNo) { LLVM_DEBUG(dbgs() << "Promote integer operand: "; N->dump(&DAG); dbgs() << "\n"); SDValue Res = SDValue(); if (CustomLowerNode(N, N->getOperand(OpNo).getValueType(), false)) { LLVM_DEBUG(dbgs() << "Node has been custom lowered, done\n"); return false; } switch (N->getOpcode()) { default: #ifndef NDEBUG dbgs() << "PromoteIntegerOperand Op #" << OpNo << ": "; N->dump(&DAG); dbgs() << "\n"; #endif llvm_unreachable("Do not know how to promote this operator's operand!"); case ISD::ANY_EXTEND: Res = PromoteIntOp_ANY_EXTEND(N); break; case ISD::ATOMIC_STORE: Res = PromoteIntOp_ATOMIC_STORE(cast(N)); break; case ISD::BITCAST: Res = PromoteIntOp_BITCAST(N); break; case ISD::BR_CC: Res = PromoteIntOp_BR_CC(N, OpNo); break; case ISD::BRCOND: Res = PromoteIntOp_BRCOND(N, OpNo); break; case ISD::BUILD_PAIR: Res = PromoteIntOp_BUILD_PAIR(N); break; case ISD::BUILD_VECTOR: Res = PromoteIntOp_BUILD_VECTOR(N); break; case ISD::CONCAT_VECTORS: Res = PromoteIntOp_CONCAT_VECTORS(N); break; case ISD::EXTRACT_VECTOR_ELT: Res = PromoteIntOp_EXTRACT_VECTOR_ELT(N); break; case ISD::INSERT_VECTOR_ELT: Res = PromoteIntOp_INSERT_VECTOR_ELT(N, OpNo);break; case ISD::SCALAR_TO_VECTOR: Res = PromoteIntOp_SCALAR_TO_VECTOR(N); break; case ISD::SPLAT_VECTOR: Res = PromoteIntOp_SPLAT_VECTOR(N); break; case ISD::VSELECT: case ISD::SELECT: Res = PromoteIntOp_SELECT(N, OpNo); break; case ISD::SELECT_CC: Res = PromoteIntOp_SELECT_CC(N, OpNo); break; case ISD::SETCC: Res = PromoteIntOp_SETCC(N, OpNo); break; case ISD::SIGN_EXTEND: Res = PromoteIntOp_SIGN_EXTEND(N); break; case ISD::SINT_TO_FP: Res = PromoteIntOp_SINT_TO_FP(N); break; case ISD::STRICT_SINT_TO_FP: Res = PromoteIntOp_STRICT_SINT_TO_FP(N); break; case ISD::STORE: Res = PromoteIntOp_STORE(cast(N), OpNo); break; case ISD::MSTORE: Res = PromoteIntOp_MSTORE(cast(N), OpNo); break; case ISD::MLOAD: Res = PromoteIntOp_MLOAD(cast(N), OpNo); break; case ISD::MGATHER: Res = PromoteIntOp_MGATHER(cast(N), OpNo); break; case ISD::MSCATTER: Res = PromoteIntOp_MSCATTER(cast(N), OpNo); break; case ISD::TRUNCATE: Res = PromoteIntOp_TRUNCATE(N); break; case ISD::FP16_TO_FP: case ISD::UINT_TO_FP: Res = PromoteIntOp_UINT_TO_FP(N); break; case ISD::STRICT_UINT_TO_FP: Res = PromoteIntOp_STRICT_UINT_TO_FP(N); break; case ISD::ZERO_EXTEND: Res = PromoteIntOp_ZERO_EXTEND(N); break; case ISD::EXTRACT_SUBVECTOR: Res = PromoteIntOp_EXTRACT_SUBVECTOR(N); break; case ISD::SHL: case ISD::SRA: case ISD::SRL: case ISD::ROTL: case ISD::ROTR: Res = PromoteIntOp_Shift(N); break; case ISD::ADDCARRY: case ISD::SUBCARRY: Res = PromoteIntOp_ADDSUBCARRY(N, OpNo); break; case ISD::FRAMEADDR: case ISD::RETURNADDR: Res = PromoteIntOp_FRAMERETURNADDR(N); break; case ISD::PREFETCH: Res = PromoteIntOp_PREFETCH(N, OpNo); break; case ISD::SMULFIX: case ISD::SMULFIXSAT: case ISD::UMULFIX: case ISD::UMULFIXSAT: case ISD::SDIVFIX: case ISD::UDIVFIX: Res = PromoteIntOp_FIX(N); break; case ISD::FPOWI: Res = PromoteIntOp_FPOWI(N); break; case ISD::VECREDUCE_ADD: case ISD::VECREDUCE_MUL: case ISD::VECREDUCE_AND: case ISD::VECREDUCE_OR: case ISD::VECREDUCE_XOR: case ISD::VECREDUCE_SMAX: case ISD::VECREDUCE_SMIN: case ISD::VECREDUCE_UMAX: case ISD::VECREDUCE_UMIN: Res = PromoteIntOp_VECREDUCE(N); break; } // If the result is null, the sub-method took care of registering results etc. if (!Res.getNode()) return false; // If the result is N, the sub-method updated N in place. Tell the legalizer // core about this. if (Res.getNode() == N) return true; const bool IsStrictFp = N->isStrictFPOpcode(); assert(Res.getValueType() == N->getValueType(0) && N->getNumValues() == (IsStrictFp ? 2 : 1) && "Invalid operand expansion"); LLVM_DEBUG(dbgs() << "Replacing: "; N->dump(&DAG); dbgs() << " with: "; Res.dump()); ReplaceValueWith(SDValue(N, 0), Res); if (IsStrictFp) ReplaceValueWith(SDValue(N, 1), SDValue(Res.getNode(), 1)); return false; } /// PromoteSetCCOperands - Promote the operands of a comparison. This code is /// shared among BR_CC, SELECT_CC, and SETCC handlers. void DAGTypeLegalizer::PromoteSetCCOperands(SDValue &NewLHS,SDValue &NewRHS, ISD::CondCode CCCode) { // We have to insert explicit sign or zero extends. Note that we could // insert sign extends for ALL conditions. For those operations where either // zero or sign extension would be valid, use SExtOrZExtPromotedInteger // which will choose the cheapest for the target. switch (CCCode) { default: llvm_unreachable("Unknown integer comparison!"); case ISD::SETEQ: case ISD::SETNE: { SDValue OpL = GetPromotedInteger(NewLHS); SDValue OpR = GetPromotedInteger(NewRHS); // We would prefer to promote the comparison operand with sign extension. // If the width of OpL/OpR excluding the duplicated sign bits is no greater // than the width of NewLHS/NewRH, we can avoid inserting real truncate // instruction, which is redundant eventually. unsigned OpLEffectiveBits = OpL.getScalarValueSizeInBits() - DAG.ComputeNumSignBits(OpL) + 1; unsigned OpREffectiveBits = OpR.getScalarValueSizeInBits() - DAG.ComputeNumSignBits(OpR) + 1; if (OpLEffectiveBits <= NewLHS.getScalarValueSizeInBits() && OpREffectiveBits <= NewRHS.getScalarValueSizeInBits()) { NewLHS = OpL; NewRHS = OpR; } else { NewLHS = SExtOrZExtPromotedInteger(NewLHS); NewRHS = SExtOrZExtPromotedInteger(NewRHS); } break; } case ISD::SETUGE: case ISD::SETUGT: case ISD::SETULE: case ISD::SETULT: NewLHS = SExtOrZExtPromotedInteger(NewLHS); NewRHS = SExtOrZExtPromotedInteger(NewRHS); break; case ISD::SETGE: case ISD::SETGT: case ISD::SETLT: case ISD::SETLE: NewLHS = SExtPromotedInteger(NewLHS); NewRHS = SExtPromotedInteger(NewRHS); break; } } SDValue DAGTypeLegalizer::PromoteIntOp_ANY_EXTEND(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); return DAG.getNode(ISD::ANY_EXTEND, SDLoc(N), N->getValueType(0), Op); } SDValue DAGTypeLegalizer::PromoteIntOp_ATOMIC_STORE(AtomicSDNode *N) { SDValue Op2 = GetPromotedInteger(N->getOperand(2)); return DAG.getAtomic(N->getOpcode(), SDLoc(N), N->getMemoryVT(), N->getChain(), N->getBasePtr(), Op2, N->getMemOperand()); } SDValue DAGTypeLegalizer::PromoteIntOp_BITCAST(SDNode *N) { // This should only occur in unusual situations like bitcasting to an // x86_fp80, so just turn it into a store+load return CreateStackStoreLoad(N->getOperand(0), N->getValueType(0)); } SDValue DAGTypeLegalizer::PromoteIntOp_BR_CC(SDNode *N, unsigned OpNo) { assert(OpNo == 2 && "Don't know how to promote this operand!"); SDValue LHS = N->getOperand(2); SDValue RHS = N->getOperand(3); PromoteSetCCOperands(LHS, RHS, cast(N->getOperand(1))->get()); // The chain (Op#0), CC (#1) and basic block destination (Op#4) are always // legal types. return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), N->getOperand(1), LHS, RHS, N->getOperand(4)), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_BRCOND(SDNode *N, unsigned OpNo) { assert(OpNo == 1 && "only know how to promote condition"); // Promote all the way up to the canonical SetCC type. SDValue Cond = PromoteTargetBoolean(N->getOperand(1), MVT::Other); // The chain (Op#0) and basic block destination (Op#2) are always legal types. return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), Cond, N->getOperand(2)), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_BUILD_PAIR(SDNode *N) { // Since the result type is legal, the operands must promote to it. EVT OVT = N->getOperand(0).getValueType(); SDValue Lo = ZExtPromotedInteger(N->getOperand(0)); SDValue Hi = GetPromotedInteger(N->getOperand(1)); assert(Lo.getValueType() == N->getValueType(0) && "Operand over promoted?"); SDLoc dl(N); Hi = DAG.getNode(ISD::SHL, dl, N->getValueType(0), Hi, DAG.getConstant(OVT.getSizeInBits(), dl, TLI.getPointerTy(DAG.getDataLayout()))); return DAG.getNode(ISD::OR, dl, N->getValueType(0), Lo, Hi); } SDValue DAGTypeLegalizer::PromoteIntOp_BUILD_VECTOR(SDNode *N) { // The vector type is legal but the element type is not. This implies // that the vector is a power-of-two in length and that the element // type does not have a strange size (eg: it is not i1). EVT VecVT = N->getValueType(0); unsigned NumElts = VecVT.getVectorNumElements(); assert(!((NumElts & 1) && (!TLI.isTypeLegal(VecVT))) && "Legal vector of one illegal element?"); // Promote the inserted value. The type does not need to match the // vector element type. Check that any extra bits introduced will be // truncated away. assert(N->getOperand(0).getValueSizeInBits() >= N->getValueType(0).getScalarSizeInBits() && "Type of inserted value narrower than vector element type!"); SmallVector NewOps; for (unsigned i = 0; i < NumElts; ++i) NewOps.push_back(GetPromotedInteger(N->getOperand(i))); return SDValue(DAG.UpdateNodeOperands(N, NewOps), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_INSERT_VECTOR_ELT(SDNode *N, unsigned OpNo) { if (OpNo == 1) { // Promote the inserted value. This is valid because the type does not // have to match the vector element type. // Check that any extra bits introduced will be truncated away. assert(N->getOperand(1).getValueSizeInBits() >= N->getValueType(0).getScalarSizeInBits() && "Type of inserted value narrower than vector element type!"); return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), GetPromotedInteger(N->getOperand(1)), N->getOperand(2)), 0); } assert(OpNo == 2 && "Different operand and result vector types?"); // Promote the index. SDValue Idx = DAG.getZExtOrTrunc(N->getOperand(2), SDLoc(N), TLI.getVectorIdxTy(DAG.getDataLayout())); return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), N->getOperand(1), Idx), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_SCALAR_TO_VECTOR(SDNode *N) { // Integer SCALAR_TO_VECTOR operands are implicitly truncated, so just promote // the operand in place. return SDValue(DAG.UpdateNodeOperands(N, GetPromotedInteger(N->getOperand(0))), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_SPLAT_VECTOR(SDNode *N) { // Integer SPLAT_VECTOR operands are implicitly truncated, so just promote the // operand in place. return SDValue( DAG.UpdateNodeOperands(N, GetPromotedInteger(N->getOperand(0))), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_SELECT(SDNode *N, unsigned OpNo) { assert(OpNo == 0 && "Only know how to promote the condition!"); SDValue Cond = N->getOperand(0); EVT OpTy = N->getOperand(1).getValueType(); if (N->getOpcode() == ISD::VSELECT) if (SDValue Res = WidenVSELECTAndMask(N)) return Res; // Promote all the way up to the canonical SetCC type. EVT OpVT = N->getOpcode() == ISD::SELECT ? OpTy.getScalarType() : OpTy; Cond = PromoteTargetBoolean(Cond, OpVT); return SDValue(DAG.UpdateNodeOperands(N, Cond, N->getOperand(1), N->getOperand(2)), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_SELECT_CC(SDNode *N, unsigned OpNo) { assert(OpNo == 0 && "Don't know how to promote this operand!"); SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); PromoteSetCCOperands(LHS, RHS, cast(N->getOperand(4))->get()); // The CC (#4) and the possible return values (#2 and #3) have legal types. return SDValue(DAG.UpdateNodeOperands(N, LHS, RHS, N->getOperand(2), N->getOperand(3), N->getOperand(4)), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_SETCC(SDNode *N, unsigned OpNo) { assert(OpNo == 0 && "Don't know how to promote this operand!"); SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); PromoteSetCCOperands(LHS, RHS, cast(N->getOperand(2))->get()); // The CC (#2) is always legal. return SDValue(DAG.UpdateNodeOperands(N, LHS, RHS, N->getOperand(2)), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_Shift(SDNode *N) { return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), ZExtPromotedInteger(N->getOperand(1))), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_SIGN_EXTEND(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); SDLoc dl(N); Op = DAG.getNode(ISD::ANY_EXTEND, dl, N->getValueType(0), Op); return DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Op.getValueType(), Op, DAG.getValueType(N->getOperand(0).getValueType())); } SDValue DAGTypeLegalizer::PromoteIntOp_SINT_TO_FP(SDNode *N) { return SDValue(DAG.UpdateNodeOperands(N, SExtPromotedInteger(N->getOperand(0))), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_STRICT_SINT_TO_FP(SDNode *N) { return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), SExtPromotedInteger(N->getOperand(1))), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_STORE(StoreSDNode *N, unsigned OpNo){ assert(ISD::isUNINDEXEDStore(N) && "Indexed store during type legalization!"); SDValue Ch = N->getChain(), Ptr = N->getBasePtr(); SDLoc dl(N); SDValue Val = GetPromotedInteger(N->getValue()); // Get promoted value. // Truncate the value and store the result. return DAG.getTruncStore(Ch, dl, Val, Ptr, N->getMemoryVT(), N->getMemOperand()); } SDValue DAGTypeLegalizer::PromoteIntOp_MSTORE(MaskedStoreSDNode *N, unsigned OpNo) { SDValue DataOp = N->getValue(); EVT DataVT = DataOp.getValueType(); SDValue Mask = N->getMask(); SDLoc dl(N); bool TruncateStore = false; if (OpNo == 4) { Mask = PromoteTargetBoolean(Mask, DataVT); // Update in place. SmallVector NewOps(N->op_begin(), N->op_end()); NewOps[4] = Mask; return SDValue(DAG.UpdateNodeOperands(N, NewOps), 0); } else { // Data operand assert(OpNo == 1 && "Unexpected operand for promotion"); DataOp = GetPromotedInteger(DataOp); TruncateStore = true; } return DAG.getMaskedStore(N->getChain(), dl, DataOp, N->getBasePtr(), N->getOffset(), Mask, N->getMemoryVT(), N->getMemOperand(), N->getAddressingMode(), TruncateStore, N->isCompressingStore()); } SDValue DAGTypeLegalizer::PromoteIntOp_MLOAD(MaskedLoadSDNode *N, unsigned OpNo) { assert(OpNo == 3 && "Only know how to promote the mask!"); EVT DataVT = N->getValueType(0); SDValue Mask = PromoteTargetBoolean(N->getOperand(OpNo), DataVT); SmallVector NewOps(N->op_begin(), N->op_end()); NewOps[OpNo] = Mask; return SDValue(DAG.UpdateNodeOperands(N, NewOps), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_MGATHER(MaskedGatherSDNode *N, unsigned OpNo) { SmallVector NewOps(N->op_begin(), N->op_end()); if (OpNo == 2) { // The Mask EVT DataVT = N->getValueType(0); NewOps[OpNo] = PromoteTargetBoolean(N->getOperand(OpNo), DataVT); } else if (OpNo == 4) { // The Index if (N->isIndexSigned()) // Need to sign extend the index since the bits will likely be used. NewOps[OpNo] = SExtPromotedInteger(N->getOperand(OpNo)); else NewOps[OpNo] = ZExtPromotedInteger(N->getOperand(OpNo)); } else NewOps[OpNo] = GetPromotedInteger(N->getOperand(OpNo)); return SDValue(DAG.UpdateNodeOperands(N, NewOps), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_MSCATTER(MaskedScatterSDNode *N, unsigned OpNo) { SmallVector NewOps(N->op_begin(), N->op_end()); if (OpNo == 2) { // The Mask EVT DataVT = N->getValue().getValueType(); NewOps[OpNo] = PromoteTargetBoolean(N->getOperand(OpNo), DataVT); } else if (OpNo == 4) { // The Index if (N->isIndexSigned()) // Need to sign extend the index since the bits will likely be used. NewOps[OpNo] = SExtPromotedInteger(N->getOperand(OpNo)); else NewOps[OpNo] = ZExtPromotedInteger(N->getOperand(OpNo)); } else NewOps[OpNo] = GetPromotedInteger(N->getOperand(OpNo)); return SDValue(DAG.UpdateNodeOperands(N, NewOps), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_TRUNCATE(SDNode *N) { SDValue Op = GetPromotedInteger(N->getOperand(0)); return DAG.getNode(ISD::TRUNCATE, SDLoc(N), N->getValueType(0), Op); } SDValue DAGTypeLegalizer::PromoteIntOp_UINT_TO_FP(SDNode *N) { return SDValue(DAG.UpdateNodeOperands(N, ZExtPromotedInteger(N->getOperand(0))), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_STRICT_UINT_TO_FP(SDNode *N) { return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), ZExtPromotedInteger(N->getOperand(1))), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_ZERO_EXTEND(SDNode *N) { SDLoc dl(N); SDValue Op = GetPromotedInteger(N->getOperand(0)); Op = DAG.getNode(ISD::ANY_EXTEND, dl, N->getValueType(0), Op); return DAG.getZeroExtendInReg(Op, dl, N->getOperand(0).getValueType().getScalarType()); } SDValue DAGTypeLegalizer::PromoteIntOp_ADDSUBCARRY(SDNode *N, unsigned OpNo) { assert(OpNo == 2 && "Don't know how to promote this operand!"); SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); SDValue Carry = N->getOperand(2); SDLoc DL(N); Carry = PromoteTargetBoolean(Carry, LHS.getValueType()); return SDValue(DAG.UpdateNodeOperands(N, LHS, RHS, Carry), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_FIX(SDNode *N) { SDValue Op2 = ZExtPromotedInteger(N->getOperand(2)); return SDValue( DAG.UpdateNodeOperands(N, N->getOperand(0), N->getOperand(1), Op2), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_FRAMERETURNADDR(SDNode *N) { // Promote the RETURNADDR/FRAMEADDR argument to a supported integer width. SDValue Op = ZExtPromotedInteger(N->getOperand(0)); return SDValue(DAG.UpdateNodeOperands(N, Op), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_PREFETCH(SDNode *N, unsigned OpNo) { assert(OpNo > 1 && "Don't know how to promote this operand!"); // Promote the rw, locality, and cache type arguments to a supported integer // width. SDValue Op2 = ZExtPromotedInteger(N->getOperand(2)); SDValue Op3 = ZExtPromotedInteger(N->getOperand(3)); SDValue Op4 = ZExtPromotedInteger(N->getOperand(4)); return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), N->getOperand(1), Op2, Op3, Op4), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_FPOWI(SDNode *N) { SDValue Op = SExtPromotedInteger(N->getOperand(1)); return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), Op), 0); } SDValue DAGTypeLegalizer::PromoteIntOp_VECREDUCE(SDNode *N) { SDLoc dl(N); SDValue Op; switch (N->getOpcode()) { default: llvm_unreachable("Expected integer vector reduction"); case ISD::VECREDUCE_ADD: case ISD::VECREDUCE_MUL: case ISD::VECREDUCE_AND: case ISD::VECREDUCE_OR: case ISD::VECREDUCE_XOR: Op = GetPromotedInteger(N->getOperand(0)); break; case ISD::VECREDUCE_SMAX: case ISD::VECREDUCE_SMIN: Op = SExtPromotedInteger(N->getOperand(0)); break; case ISD::VECREDUCE_UMAX: case ISD::VECREDUCE_UMIN: Op = ZExtPromotedInteger(N->getOperand(0)); break; } EVT EltVT = Op.getValueType().getVectorElementType(); EVT VT = N->getValueType(0); if (VT.bitsGE(EltVT)) return DAG.getNode(N->getOpcode(), SDLoc(N), VT, Op); // Result size must be >= element size. If this is not the case after // promotion, also promote the result type and then truncate. SDValue Reduce = DAG.getNode(N->getOpcode(), dl, EltVT, Op); return DAG.getNode(ISD::TRUNCATE, dl, VT, Reduce); } //===----------------------------------------------------------------------===// // Integer Result Expansion //===----------------------------------------------------------------------===// /// ExpandIntegerResult - This method is called when the specified result of the /// specified node is found to need expansion. At this point, the node may also /// have invalid operands or may have other results that need promotion, we just /// know that (at least) one result needs expansion. void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) { LLVM_DEBUG(dbgs() << "Expand integer result: "; N->dump(&DAG); dbgs() << "\n"); SDValue Lo, Hi; Lo = Hi = SDValue(); // See if the target wants to custom expand this node. if (CustomLowerNode(N, N->getValueType(ResNo), true)) return; switch (N->getOpcode()) { default: #ifndef NDEBUG dbgs() << "ExpandIntegerResult #" << ResNo << ": "; N->dump(&DAG); dbgs() << "\n"; #endif report_fatal_error("Do not know how to expand the result of this " "operator!"); case ISD::MERGE_VALUES: SplitRes_MERGE_VALUES(N, ResNo, Lo, Hi); break; case ISD::SELECT: SplitRes_SELECT(N, Lo, Hi); break; case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break; case ISD::UNDEF: SplitRes_UNDEF(N, Lo, Hi); break; case ISD::BITCAST: ExpandRes_BITCAST(N, Lo, Hi); break; case ISD::BUILD_PAIR: ExpandRes_BUILD_PAIR(N, Lo, Hi); break; case ISD::EXTRACT_ELEMENT: ExpandRes_EXTRACT_ELEMENT(N, Lo, Hi); break; case ISD::EXTRACT_VECTOR_ELT: ExpandRes_EXTRACT_VECTOR_ELT(N, Lo, Hi); break; case ISD::VAARG: ExpandRes_VAARG(N, Lo, Hi); break; case ISD::ANY_EXTEND: ExpandIntRes_ANY_EXTEND(N, Lo, Hi); break; case ISD::AssertSext: ExpandIntRes_AssertSext(N, Lo, Hi); break; case ISD::AssertZext: ExpandIntRes_AssertZext(N, Lo, Hi); break; case ISD::BITREVERSE: ExpandIntRes_BITREVERSE(N, Lo, Hi); break; case ISD::BSWAP: ExpandIntRes_BSWAP(N, Lo, Hi); break; case ISD::Constant: ExpandIntRes_Constant(N, Lo, Hi); break; case ISD::ABS: ExpandIntRes_ABS(N, Lo, Hi); break; case ISD::CTLZ_ZERO_UNDEF: case ISD::CTLZ: ExpandIntRes_CTLZ(N, Lo, Hi); break; case ISD::CTPOP: ExpandIntRes_CTPOP(N, Lo, Hi); break; case ISD::CTTZ_ZERO_UNDEF: case ISD::CTTZ: ExpandIntRes_CTTZ(N, Lo, Hi); break; case ISD::FLT_ROUNDS_: ExpandIntRes_FLT_ROUNDS(N, Lo, Hi); break; case ISD::STRICT_FP_TO_SINT: case ISD::FP_TO_SINT: ExpandIntRes_FP_TO_SINT(N, Lo, Hi); break; case ISD::STRICT_FP_TO_UINT: case ISD::FP_TO_UINT: ExpandIntRes_FP_TO_UINT(N, Lo, Hi); break; case ISD::STRICT_LLROUND: case ISD::STRICT_LLRINT: case ISD::LLROUND: case ISD::LLRINT: ExpandIntRes_LLROUND_LLRINT(N, Lo, Hi); break; case ISD::LOAD: ExpandIntRes_LOAD(cast(N), Lo, Hi); break; case ISD::MUL: ExpandIntRes_MUL(N, Lo, Hi); break; case ISD::READCYCLECOUNTER: ExpandIntRes_READCYCLECOUNTER(N, Lo, Hi); break; case ISD::SDIV: ExpandIntRes_SDIV(N, Lo, Hi); break; case ISD::SIGN_EXTEND: ExpandIntRes_SIGN_EXTEND(N, Lo, Hi); break; case ISD::SIGN_EXTEND_INREG: ExpandIntRes_SIGN_EXTEND_INREG(N, Lo, Hi); break; case ISD::SREM: ExpandIntRes_SREM(N, Lo, Hi); break; case ISD::TRUNCATE: ExpandIntRes_TRUNCATE(N, Lo, Hi); break; case ISD::UDIV: ExpandIntRes_UDIV(N, Lo, Hi); break; case ISD::UREM: ExpandIntRes_UREM(N, Lo, Hi); break; case ISD::ZERO_EXTEND: ExpandIntRes_ZERO_EXTEND(N, Lo, Hi); break; case ISD::ATOMIC_LOAD: ExpandIntRes_ATOMIC_LOAD(N, Lo, Hi); break; case ISD::ATOMIC_LOAD_ADD: case ISD::ATOMIC_LOAD_SUB: case ISD::ATOMIC_LOAD_AND: case ISD::ATOMIC_LOAD_CLR: case ISD::ATOMIC_LOAD_OR: case ISD::ATOMIC_LOAD_XOR: case ISD::ATOMIC_LOAD_NAND: case ISD::ATOMIC_LOAD_MIN: case ISD::ATOMIC_LOAD_MAX: case ISD::ATOMIC_LOAD_UMIN: case ISD::ATOMIC_LOAD_UMAX: case ISD::ATOMIC_SWAP: case ISD::ATOMIC_CMP_SWAP: { std::pair Tmp = ExpandAtomic(N); SplitInteger(Tmp.first, Lo, Hi); ReplaceValueWith(SDValue(N, 1), Tmp.second); break; } case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: { AtomicSDNode *AN = cast(N); SDVTList VTs = DAG.getVTList(N->getValueType(0), MVT::Other); SDValue Tmp = DAG.getAtomicCmpSwap( ISD::ATOMIC_CMP_SWAP, SDLoc(N), AN->getMemoryVT(), VTs, N->getOperand(0), N->getOperand(1), N->getOperand(2), N->getOperand(3), AN->getMemOperand()); // Expanding to the strong ATOMIC_CMP_SWAP node means we can determine // success simply by comparing the loaded value against the ingoing // comparison. SDValue Success = DAG.getSetCC(SDLoc(N), N->getValueType(1), Tmp, N->getOperand(2), ISD::SETEQ); SplitInteger(Tmp, Lo, Hi); ReplaceValueWith(SDValue(N, 1), Success); ReplaceValueWith(SDValue(N, 2), Tmp.getValue(1)); break; } case ISD::AND: case ISD::OR: case ISD::XOR: ExpandIntRes_Logical(N, Lo, Hi); break; case ISD::UMAX: case ISD::SMAX: case ISD::UMIN: case ISD::SMIN: ExpandIntRes_MINMAX(N, Lo, Hi); break; case ISD::ADD: case ISD::SUB: ExpandIntRes_ADDSUB(N, Lo, Hi); break; case ISD::ADDC: case ISD::SUBC: ExpandIntRes_ADDSUBC(N, Lo, Hi); break; case ISD::ADDE: case ISD::SUBE: ExpandIntRes_ADDSUBE(N, Lo, Hi); break; case ISD::ADDCARRY: case ISD::SUBCARRY: ExpandIntRes_ADDSUBCARRY(N, Lo, Hi); break; case ISD::SHL: case ISD::SRA: case ISD::SRL: ExpandIntRes_Shift(N, Lo, Hi); break; case ISD::SADDO: case ISD::SSUBO: ExpandIntRes_SADDSUBO(N, Lo, Hi); break; case ISD::UADDO: case ISD::USUBO: ExpandIntRes_UADDSUBO(N, Lo, Hi); break; case ISD::UMULO: case ISD::SMULO: ExpandIntRes_XMULO(N, Lo, Hi); break; case ISD::SADDSAT: case ISD::UADDSAT: case ISD::SSUBSAT: case ISD::USUBSAT: ExpandIntRes_ADDSUBSAT(N, Lo, Hi); break; case ISD::SMULFIX: case ISD::SMULFIXSAT: case ISD::UMULFIX: case ISD::UMULFIXSAT: ExpandIntRes_MULFIX(N, Lo, Hi); break; case ISD::SDIVFIX: case ISD::UDIVFIX: ExpandIntRes_DIVFIX(N, Lo, Hi); break; case ISD::VECREDUCE_ADD: case ISD::VECREDUCE_MUL: case ISD::VECREDUCE_AND: case ISD::VECREDUCE_OR: case ISD::VECREDUCE_XOR: case ISD::VECREDUCE_SMAX: case ISD::VECREDUCE_SMIN: case ISD::VECREDUCE_UMAX: case ISD::VECREDUCE_UMIN: ExpandIntRes_VECREDUCE(N, Lo, Hi); break; } // If Lo/Hi is null, the sub-method took care of registering results etc. if (Lo.getNode()) SetExpandedInteger(SDValue(N, ResNo), Lo, Hi); } /// Lower an atomic node to the appropriate builtin call. std::pair DAGTypeLegalizer::ExpandAtomic(SDNode *Node) { unsigned Opc = Node->getOpcode(); MVT VT = cast(Node)->getMemoryVT().getSimpleVT(); RTLIB::Libcall LC = RTLIB::getSYNC(Opc, VT); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected atomic op or value type!"); EVT RetVT = Node->getValueType(0); SmallVector Ops(Node->op_begin() + 1, Node->op_end()); TargetLowering::MakeLibCallOptions CallOptions; return TLI.makeLibCall(DAG, LC, RetVT, Ops, CallOptions, SDLoc(Node), Node->getOperand(0)); } /// N is a shift by a value that needs to be expanded, /// and the shift amount is a constant 'Amt'. Expand the operation. void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, const APInt &Amt, SDValue &Lo, SDValue &Hi) { SDLoc DL(N); // Expand the incoming operand to be shifted, so that we have its parts SDValue InL, InH; GetExpandedInteger(N->getOperand(0), InL, InH); // Though Amt shouldn't usually be 0, it's possible. E.g. when legalization // splitted a vector shift, like this: SHL <0, 2>. if (!Amt) { Lo = InL; Hi = InH; return; } EVT NVT = InL.getValueType(); unsigned VTBits = N->getValueType(0).getSizeInBits(); unsigned NVTBits = NVT.getSizeInBits(); EVT ShTy = N->getOperand(1).getValueType(); if (N->getOpcode() == ISD::SHL) { if (Amt.ugt(VTBits)) { Lo = Hi = DAG.getConstant(0, DL, NVT); } else if (Amt.ugt(NVTBits)) { Lo = DAG.getConstant(0, DL, NVT); Hi = DAG.getNode(ISD::SHL, DL, NVT, InL, DAG.getConstant(Amt - NVTBits, DL, ShTy)); } else if (Amt == NVTBits) { Lo = DAG.getConstant(0, DL, NVT); Hi = InL; } else { Lo = DAG.getNode(ISD::SHL, DL, NVT, InL, DAG.getConstant(Amt, DL, ShTy)); Hi = DAG.getNode(ISD::OR, DL, NVT, DAG.getNode(ISD::SHL, DL, NVT, InH, DAG.getConstant(Amt, DL, ShTy)), DAG.getNode(ISD::SRL, DL, NVT, InL, DAG.getConstant(-Amt + NVTBits, DL, ShTy))); } return; } if (N->getOpcode() == ISD::SRL) { if (Amt.ugt(VTBits)) { Lo = Hi = DAG.getConstant(0, DL, NVT); } else if (Amt.ugt(NVTBits)) { Lo = DAG.getNode(ISD::SRL, DL, NVT, InH, DAG.getConstant(Amt - NVTBits, DL, ShTy)); Hi = DAG.getConstant(0, DL, NVT); } else if (Amt == NVTBits) { Lo = InH; Hi = DAG.getConstant(0, DL, NVT); } else { Lo = DAG.getNode(ISD::OR, DL, NVT, DAG.getNode(ISD::SRL, DL, NVT, InL, DAG.getConstant(Amt, DL, ShTy)), DAG.getNode(ISD::SHL, DL, NVT, InH, DAG.getConstant(-Amt + NVTBits, DL, ShTy))); Hi = DAG.getNode(ISD::SRL, DL, NVT, InH, DAG.getConstant(Amt, DL, ShTy)); } return; } assert(N->getOpcode() == ISD::SRA && "Unknown shift!"); if (Amt.ugt(VTBits)) { Hi = Lo = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(NVTBits - 1, DL, ShTy)); } else if (Amt.ugt(NVTBits)) { Lo = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(Amt - NVTBits, DL, ShTy)); Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(NVTBits - 1, DL, ShTy)); } else if (Amt == NVTBits) { Lo = InH; Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(NVTBits - 1, DL, ShTy)); } else { Lo = DAG.getNode(ISD::OR, DL, NVT, DAG.getNode(ISD::SRL, DL, NVT, InL, DAG.getConstant(Amt, DL, ShTy)), DAG.getNode(ISD::SHL, DL, NVT, InH, DAG.getConstant(-Amt + NVTBits, DL, ShTy))); Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(Amt, DL, ShTy)); } } /// ExpandShiftWithKnownAmountBit - Try to determine whether we can simplify /// this shift based on knowledge of the high bit of the shift amount. If we /// can tell this, we know that it is >= 32 or < 32, without knowing the actual /// shift amount. bool DAGTypeLegalizer:: ExpandShiftWithKnownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue Amt = N->getOperand(1); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); EVT ShTy = Amt.getValueType(); unsigned ShBits = ShTy.getScalarSizeInBits(); unsigned NVTBits = NVT.getScalarSizeInBits(); assert(isPowerOf2_32(NVTBits) && "Expanded integer type size not a power of two!"); SDLoc dl(N); APInt HighBitMask = APInt::getHighBitsSet(ShBits, ShBits - Log2_32(NVTBits)); KnownBits Known = DAG.computeKnownBits(N->getOperand(1)); // If we don't know anything about the high bits, exit. if (((Known.Zero|Known.One) & HighBitMask) == 0) return false; // Get the incoming operand to be shifted. SDValue InL, InH; GetExpandedInteger(N->getOperand(0), InL, InH); // If we know that any of the high bits of the shift amount are one, then we // can do this as a couple of simple shifts. if (Known.One.intersects(HighBitMask)) { // Mask out the high bit, which we know is set. Amt = DAG.getNode(ISD::AND, dl, ShTy, Amt, DAG.getConstant(~HighBitMask, dl, ShTy)); switch (N->getOpcode()) { default: llvm_unreachable("Unknown shift"); case ISD::SHL: Lo = DAG.getConstant(0, dl, NVT); // Low part is zero. Hi = DAG.getNode(ISD::SHL, dl, NVT, InL, Amt); // High part from Lo part. return true; case ISD::SRL: Hi = DAG.getConstant(0, dl, NVT); // Hi part is zero. Lo = DAG.getNode(ISD::SRL, dl, NVT, InH, Amt); // Lo part from Hi part. return true; case ISD::SRA: Hi = DAG.getNode(ISD::SRA, dl, NVT, InH, // Sign extend high part. DAG.getConstant(NVTBits - 1, dl, ShTy)); Lo = DAG.getNode(ISD::SRA, dl, NVT, InH, Amt); // Lo part from Hi part. return true; } } // If we know that all of the high bits of the shift amount are zero, then we // can do this as a couple of simple shifts. if (HighBitMask.isSubsetOf(Known.Zero)) { // Calculate 31-x. 31 is used instead of 32 to avoid creating an undefined // shift if x is zero. We can use XOR here because x is known to be smaller // than 32. SDValue Amt2 = DAG.getNode(ISD::XOR, dl, ShTy, Amt, DAG.getConstant(NVTBits - 1, dl, ShTy)); unsigned Op1, Op2; switch (N->getOpcode()) { default: llvm_unreachable("Unknown shift"); case ISD::SHL: Op1 = ISD::SHL; Op2 = ISD::SRL; break; case ISD::SRL: case ISD::SRA: Op1 = ISD::SRL; Op2 = ISD::SHL; break; } // When shifting right the arithmetic for Lo and Hi is swapped. if (N->getOpcode() != ISD::SHL) std::swap(InL, InH); // Use a little trick to get the bits that move from Lo to Hi. First // shift by one bit. SDValue Sh1 = DAG.getNode(Op2, dl, NVT, InL, DAG.getConstant(1, dl, ShTy)); // Then compute the remaining shift with amount-1. SDValue Sh2 = DAG.getNode(Op2, dl, NVT, Sh1, Amt2); Lo = DAG.getNode(N->getOpcode(), dl, NVT, InL, Amt); Hi = DAG.getNode(ISD::OR, dl, NVT, DAG.getNode(Op1, dl, NVT, InH, Amt),Sh2); if (N->getOpcode() != ISD::SHL) std::swap(Hi, Lo); return true; } return false; } /// ExpandShiftWithUnknownAmountBit - Fully general expansion of integer shift /// of any size. bool DAGTypeLegalizer:: ExpandShiftWithUnknownAmountBit(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue Amt = N->getOperand(1); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); EVT ShTy = Amt.getValueType(); unsigned NVTBits = NVT.getSizeInBits(); assert(isPowerOf2_32(NVTBits) && "Expanded integer type size not a power of two!"); SDLoc dl(N); // Get the incoming operand to be shifted. SDValue InL, InH; GetExpandedInteger(N->getOperand(0), InL, InH); SDValue NVBitsNode = DAG.getConstant(NVTBits, dl, ShTy); SDValue AmtExcess = DAG.getNode(ISD::SUB, dl, ShTy, Amt, NVBitsNode); SDValue AmtLack = DAG.getNode(ISD::SUB, dl, ShTy, NVBitsNode, Amt); SDValue isShort = DAG.getSetCC(dl, getSetCCResultType(ShTy), Amt, NVBitsNode, ISD::SETULT); SDValue isZero = DAG.getSetCC(dl, getSetCCResultType(ShTy), Amt, DAG.getConstant(0, dl, ShTy), ISD::SETEQ); SDValue LoS, HiS, LoL, HiL; switch (N->getOpcode()) { default: llvm_unreachable("Unknown shift"); case ISD::SHL: // Short: ShAmt < NVTBits LoS = DAG.getNode(ISD::SHL, dl, NVT, InL, Amt); HiS = DAG.getNode(ISD::OR, dl, NVT, DAG.getNode(ISD::SHL, dl, NVT, InH, Amt), DAG.getNode(ISD::SRL, dl, NVT, InL, AmtLack)); // Long: ShAmt >= NVTBits LoL = DAG.getConstant(0, dl, NVT); // Lo part is zero. HiL = DAG.getNode(ISD::SHL, dl, NVT, InL, AmtExcess); // Hi from Lo part. Lo = DAG.getSelect(dl, NVT, isShort, LoS, LoL); Hi = DAG.getSelect(dl, NVT, isZero, InH, DAG.getSelect(dl, NVT, isShort, HiS, HiL)); return true; case ISD::SRL: // Short: ShAmt < NVTBits HiS = DAG.getNode(ISD::SRL, dl, NVT, InH, Amt); LoS = DAG.getNode(ISD::OR, dl, NVT, DAG.getNode(ISD::SRL, dl, NVT, InL, Amt), // FIXME: If Amt is zero, the following shift generates an undefined result // on some architectures. DAG.getNode(ISD::SHL, dl, NVT, InH, AmtLack)); // Long: ShAmt >= NVTBits HiL = DAG.getConstant(0, dl, NVT); // Hi part is zero. LoL = DAG.getNode(ISD::SRL, dl, NVT, InH, AmtExcess); // Lo from Hi part. Lo = DAG.getSelect(dl, NVT, isZero, InL, DAG.getSelect(dl, NVT, isShort, LoS, LoL)); Hi = DAG.getSelect(dl, NVT, isShort, HiS, HiL); return true; case ISD::SRA: // Short: ShAmt < NVTBits HiS = DAG.getNode(ISD::SRA, dl, NVT, InH, Amt); LoS = DAG.getNode(ISD::OR, dl, NVT, DAG.getNode(ISD::SRL, dl, NVT, InL, Amt), DAG.getNode(ISD::SHL, dl, NVT, InH, AmtLack)); // Long: ShAmt >= NVTBits HiL = DAG.getNode(ISD::SRA, dl, NVT, InH, // Sign of Hi part. DAG.getConstant(NVTBits - 1, dl, ShTy)); LoL = DAG.getNode(ISD::SRA, dl, NVT, InH, AmtExcess); // Lo from Hi part. Lo = DAG.getSelect(dl, NVT, isZero, InL, DAG.getSelect(dl, NVT, isShort, LoS, LoL)); Hi = DAG.getSelect(dl, NVT, isShort, HiS, HiL); return true; } } static std::pair getExpandedMinMaxOps(int Op) { switch (Op) { default: llvm_unreachable("invalid min/max opcode"); case ISD::SMAX: return std::make_pair(ISD::SETGT, ISD::UMAX); case ISD::UMAX: return std::make_pair(ISD::SETUGT, ISD::UMAX); case ISD::SMIN: return std::make_pair(ISD::SETLT, ISD::UMIN); case ISD::UMIN: return std::make_pair(ISD::SETULT, ISD::UMIN); } } void DAGTypeLegalizer::ExpandIntRes_MINMAX(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc DL(N); ISD::NodeType LoOpc; ISD::CondCode CondC; std::tie(CondC, LoOpc) = getExpandedMinMaxOps(N->getOpcode()); // Expand the subcomponents. SDValue LHSL, LHSH, RHSL, RHSH; GetExpandedInteger(N->getOperand(0), LHSL, LHSH); GetExpandedInteger(N->getOperand(1), RHSL, RHSH); // Value types EVT NVT = LHSL.getValueType(); EVT CCT = getSetCCResultType(NVT); // Hi part is always the same op Hi = DAG.getNode(N->getOpcode(), DL, NVT, {LHSH, RHSH}); // We need to know whether to select Lo part that corresponds to 'winning' // Hi part or if Hi parts are equal. SDValue IsHiLeft = DAG.getSetCC(DL, CCT, LHSH, RHSH, CondC); SDValue IsHiEq = DAG.getSetCC(DL, CCT, LHSH, RHSH, ISD::SETEQ); // Lo part corresponding to the 'winning' Hi part SDValue LoCmp = DAG.getSelect(DL, NVT, IsHiLeft, LHSL, RHSL); // Recursed Lo part if Hi parts are equal, this uses unsigned version SDValue LoMinMax = DAG.getNode(LoOpc, DL, NVT, {LHSL, RHSL}); Lo = DAG.getSelect(DL, NVT, IsHiEq, LoMinMax, LoCmp); } void DAGTypeLegalizer::ExpandIntRes_ADDSUB(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); // Expand the subcomponents. SDValue LHSL, LHSH, RHSL, RHSH; GetExpandedInteger(N->getOperand(0), LHSL, LHSH); GetExpandedInteger(N->getOperand(1), RHSL, RHSH); EVT NVT = LHSL.getValueType(); SDValue LoOps[2] = { LHSL, RHSL }; SDValue HiOps[3] = { LHSH, RHSH }; bool HasOpCarry = TLI.isOperationLegalOrCustom( N->getOpcode() == ISD::ADD ? ISD::ADDCARRY : ISD::SUBCARRY, TLI.getTypeToExpandTo(*DAG.getContext(), NVT)); if (HasOpCarry) { SDVTList VTList = DAG.getVTList(NVT, getSetCCResultType(NVT)); if (N->getOpcode() == ISD::ADD) { Lo = DAG.getNode(ISD::UADDO, dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(ISD::ADDCARRY, dl, VTList, HiOps); } else { Lo = DAG.getNode(ISD::USUBO, dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(ISD::SUBCARRY, dl, VTList, HiOps); } return; } // Do not generate ADDC/ADDE or SUBC/SUBE if the target does not support // them. TODO: Teach operation legalization how to expand unsupported // ADDC/ADDE/SUBC/SUBE. The problem is that these operations generate // a carry of type MVT::Glue, but there doesn't seem to be any way to // generate a value of this type in the expanded code sequence. bool hasCarry = TLI.isOperationLegalOrCustom(N->getOpcode() == ISD::ADD ? ISD::ADDC : ISD::SUBC, TLI.getTypeToExpandTo(*DAG.getContext(), NVT)); if (hasCarry) { SDVTList VTList = DAG.getVTList(NVT, MVT::Glue); if (N->getOpcode() == ISD::ADD) { Lo = DAG.getNode(ISD::ADDC, dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(ISD::ADDE, dl, VTList, HiOps); } else { Lo = DAG.getNode(ISD::SUBC, dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(ISD::SUBE, dl, VTList, HiOps); } return; } bool hasOVF = TLI.isOperationLegalOrCustom(N->getOpcode() == ISD::ADD ? ISD::UADDO : ISD::USUBO, TLI.getTypeToExpandTo(*DAG.getContext(), NVT)); TargetLoweringBase::BooleanContent BoolType = TLI.getBooleanContents(NVT); if (hasOVF) { EVT OvfVT = getSetCCResultType(NVT); SDVTList VTList = DAG.getVTList(NVT, OvfVT); int RevOpc; if (N->getOpcode() == ISD::ADD) { RevOpc = ISD::SUB; Lo = DAG.getNode(ISD::UADDO, dl, VTList, LoOps); Hi = DAG.getNode(ISD::ADD, dl, NVT, makeArrayRef(HiOps, 2)); } else { RevOpc = ISD::ADD; Lo = DAG.getNode(ISD::USUBO, dl, VTList, LoOps); Hi = DAG.getNode(ISD::SUB, dl, NVT, makeArrayRef(HiOps, 2)); } SDValue OVF = Lo.getValue(1); switch (BoolType) { case TargetLoweringBase::UndefinedBooleanContent: OVF = DAG.getNode(ISD::AND, dl, OvfVT, DAG.getConstant(1, dl, OvfVT), OVF); LLVM_FALLTHROUGH; case TargetLoweringBase::ZeroOrOneBooleanContent: OVF = DAG.getZExtOrTrunc(OVF, dl, NVT); Hi = DAG.getNode(N->getOpcode(), dl, NVT, Hi, OVF); break; case TargetLoweringBase::ZeroOrNegativeOneBooleanContent: OVF = DAG.getSExtOrTrunc(OVF, dl, NVT); Hi = DAG.getNode(RevOpc, dl, NVT, Hi, OVF); } return; } if (N->getOpcode() == ISD::ADD) { Lo = DAG.getNode(ISD::ADD, dl, NVT, LoOps); Hi = DAG.getNode(ISD::ADD, dl, NVT, makeArrayRef(HiOps, 2)); SDValue Cmp1 = DAG.getSetCC(dl, getSetCCResultType(NVT), Lo, LoOps[0], ISD::SETULT); if (BoolType == TargetLoweringBase::ZeroOrOneBooleanContent) { SDValue Carry = DAG.getZExtOrTrunc(Cmp1, dl, NVT); Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, Carry); return; } SDValue Carry1 = DAG.getSelect(dl, NVT, Cmp1, DAG.getConstant(1, dl, NVT), DAG.getConstant(0, dl, NVT)); SDValue Cmp2 = DAG.getSetCC(dl, getSetCCResultType(NVT), Lo, LoOps[1], ISD::SETULT); SDValue Carry2 = DAG.getSelect(dl, NVT, Cmp2, DAG.getConstant(1, dl, NVT), Carry1); Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, Carry2); } else { Lo = DAG.getNode(ISD::SUB, dl, NVT, LoOps); Hi = DAG.getNode(ISD::SUB, dl, NVT, makeArrayRef(HiOps, 2)); SDValue Cmp = DAG.getSetCC(dl, getSetCCResultType(LoOps[0].getValueType()), LoOps[0], LoOps[1], ISD::SETULT); SDValue Borrow; if (BoolType == TargetLoweringBase::ZeroOrOneBooleanContent) Borrow = DAG.getZExtOrTrunc(Cmp, dl, NVT); else Borrow = DAG.getSelect(dl, NVT, Cmp, DAG.getConstant(1, dl, NVT), DAG.getConstant(0, dl, NVT)); Hi = DAG.getNode(ISD::SUB, dl, NVT, Hi, Borrow); } } void DAGTypeLegalizer::ExpandIntRes_ADDSUBC(SDNode *N, SDValue &Lo, SDValue &Hi) { // Expand the subcomponents. SDValue LHSL, LHSH, RHSL, RHSH; SDLoc dl(N); GetExpandedInteger(N->getOperand(0), LHSL, LHSH); GetExpandedInteger(N->getOperand(1), RHSL, RHSH); SDVTList VTList = DAG.getVTList(LHSL.getValueType(), MVT::Glue); SDValue LoOps[2] = { LHSL, RHSL }; SDValue HiOps[3] = { LHSH, RHSH }; if (N->getOpcode() == ISD::ADDC) { Lo = DAG.getNode(ISD::ADDC, dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(ISD::ADDE, dl, VTList, HiOps); } else { Lo = DAG.getNode(ISD::SUBC, dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(ISD::SUBE, dl, VTList, HiOps); } // Legalized the flag result - switch anything that used the old flag to // use the new one. ReplaceValueWith(SDValue(N, 1), Hi.getValue(1)); } void DAGTypeLegalizer::ExpandIntRes_ADDSUBE(SDNode *N, SDValue &Lo, SDValue &Hi) { // Expand the subcomponents. SDValue LHSL, LHSH, RHSL, RHSH; SDLoc dl(N); GetExpandedInteger(N->getOperand(0), LHSL, LHSH); GetExpandedInteger(N->getOperand(1), RHSL, RHSH); SDVTList VTList = DAG.getVTList(LHSL.getValueType(), MVT::Glue); SDValue LoOps[3] = { LHSL, RHSL, N->getOperand(2) }; SDValue HiOps[3] = { LHSH, RHSH }; Lo = DAG.getNode(N->getOpcode(), dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(N->getOpcode(), dl, VTList, HiOps); // Legalized the flag result - switch anything that used the old flag to // use the new one. ReplaceValueWith(SDValue(N, 1), Hi.getValue(1)); } void DAGTypeLegalizer::ExpandIntRes_UADDSUBO(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); SDLoc dl(N); SDValue Ovf; unsigned CarryOp, NoCarryOp; ISD::CondCode Cond; switch(N->getOpcode()) { case ISD::UADDO: CarryOp = ISD::ADDCARRY; NoCarryOp = ISD::ADD; Cond = ISD::SETULT; break; case ISD::USUBO: CarryOp = ISD::SUBCARRY; NoCarryOp = ISD::SUB; Cond = ISD::SETUGT; break; default: llvm_unreachable("Node has unexpected Opcode"); } bool HasCarryOp = TLI.isOperationLegalOrCustom( CarryOp, TLI.getTypeToExpandTo(*DAG.getContext(), LHS.getValueType())); if (HasCarryOp) { // Expand the subcomponents. SDValue LHSL, LHSH, RHSL, RHSH; GetExpandedInteger(LHS, LHSL, LHSH); GetExpandedInteger(RHS, RHSL, RHSH); SDVTList VTList = DAG.getVTList(LHSL.getValueType(), N->getValueType(1)); SDValue LoOps[2] = { LHSL, RHSL }; SDValue HiOps[3] = { LHSH, RHSH }; Lo = DAG.getNode(N->getOpcode(), dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(CarryOp, dl, VTList, HiOps); Ovf = Hi.getValue(1); } else { // Expand the result by simply replacing it with the equivalent // non-overflow-checking operation. SDValue Sum = DAG.getNode(NoCarryOp, dl, LHS.getValueType(), LHS, RHS); SplitInteger(Sum, Lo, Hi); // Calculate the overflow: addition overflows iff a + b < a, and subtraction // overflows iff a - b > a. Ovf = DAG.getSetCC(dl, N->getValueType(1), Sum, LHS, Cond); } // Legalized the flag result - switch anything that used the old flag to // use the new one. ReplaceValueWith(SDValue(N, 1), Ovf); } void DAGTypeLegalizer::ExpandIntRes_ADDSUBCARRY(SDNode *N, SDValue &Lo, SDValue &Hi) { // Expand the subcomponents. SDValue LHSL, LHSH, RHSL, RHSH; SDLoc dl(N); GetExpandedInteger(N->getOperand(0), LHSL, LHSH); GetExpandedInteger(N->getOperand(1), RHSL, RHSH); SDVTList VTList = DAG.getVTList(LHSL.getValueType(), N->getValueType(1)); SDValue LoOps[3] = { LHSL, RHSL, N->getOperand(2) }; SDValue HiOps[3] = { LHSH, RHSH, SDValue() }; Lo = DAG.getNode(N->getOpcode(), dl, VTList, LoOps); HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(N->getOpcode(), dl, VTList, HiOps); // Legalized the flag result - switch anything that used the old flag to // use the new one. ReplaceValueWith(SDValue(N, 1), Hi.getValue(1)); } void DAGTypeLegalizer::ExpandIntRes_ANY_EXTEND(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDLoc dl(N); SDValue Op = N->getOperand(0); if (Op.getValueType().bitsLE(NVT)) { // The low part is any extension of the input (which degenerates to a copy). Lo = DAG.getNode(ISD::ANY_EXTEND, dl, NVT, Op); Hi = DAG.getUNDEF(NVT); // The high part is undefined. } else { // For example, extension of an i48 to an i64. The operand type necessarily // promotes to the result type, so will end up being expanded too. assert(getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteInteger && "Only know how to promote this result!"); SDValue Res = GetPromotedInteger(Op); assert(Res.getValueType() == N->getValueType(0) && "Operand over promoted?"); // Split the promoted operand. This will simplify when it is expanded. SplitInteger(Res, Lo, Hi); } } void DAGTypeLegalizer::ExpandIntRes_AssertSext(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); GetExpandedInteger(N->getOperand(0), Lo, Hi); EVT NVT = Lo.getValueType(); EVT EVT = cast(N->getOperand(1))->getVT(); unsigned NVTBits = NVT.getSizeInBits(); unsigned EVTBits = EVT.getSizeInBits(); if (NVTBits < EVTBits) { Hi = DAG.getNode(ISD::AssertSext, dl, NVT, Hi, DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), EVTBits - NVTBits))); } else { Lo = DAG.getNode(ISD::AssertSext, dl, NVT, Lo, DAG.getValueType(EVT)); // The high part replicates the sign bit of Lo, make it explicit. Hi = DAG.getNode(ISD::SRA, dl, NVT, Lo, DAG.getConstant(NVTBits - 1, dl, TLI.getPointerTy(DAG.getDataLayout()))); } } void DAGTypeLegalizer::ExpandIntRes_AssertZext(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); GetExpandedInteger(N->getOperand(0), Lo, Hi); EVT NVT = Lo.getValueType(); EVT EVT = cast(N->getOperand(1))->getVT(); unsigned NVTBits = NVT.getSizeInBits(); unsigned EVTBits = EVT.getSizeInBits(); if (NVTBits < EVTBits) { Hi = DAG.getNode(ISD::AssertZext, dl, NVT, Hi, DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), EVTBits - NVTBits))); } else { Lo = DAG.getNode(ISD::AssertZext, dl, NVT, Lo, DAG.getValueType(EVT)); // The high part must be zero, make it explicit. Hi = DAG.getConstant(0, dl, NVT); } } void DAGTypeLegalizer::ExpandIntRes_BITREVERSE(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); GetExpandedInteger(N->getOperand(0), Hi, Lo); // Note swapped operands. Lo = DAG.getNode(ISD::BITREVERSE, dl, Lo.getValueType(), Lo); Hi = DAG.getNode(ISD::BITREVERSE, dl, Hi.getValueType(), Hi); } void DAGTypeLegalizer::ExpandIntRes_BSWAP(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); GetExpandedInteger(N->getOperand(0), Hi, Lo); // Note swapped operands. Lo = DAG.getNode(ISD::BSWAP, dl, Lo.getValueType(), Lo); Hi = DAG.getNode(ISD::BSWAP, dl, Hi.getValueType(), Hi); } void DAGTypeLegalizer::ExpandIntRes_Constant(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); unsigned NBitWidth = NVT.getSizeInBits(); auto Constant = cast(N); const APInt &Cst = Constant->getAPIntValue(); bool IsTarget = Constant->isTargetOpcode(); bool IsOpaque = Constant->isOpaque(); SDLoc dl(N); Lo = DAG.getConstant(Cst.trunc(NBitWidth), dl, NVT, IsTarget, IsOpaque); Hi = DAG.getConstant(Cst.lshr(NBitWidth).trunc(NBitWidth), dl, NVT, IsTarget, IsOpaque); } void DAGTypeLegalizer::ExpandIntRes_ABS(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); // abs(HiLo) -> (Hi < 0 ? -HiLo : HiLo) EVT VT = N->getValueType(0); SDValue N0 = N->getOperand(0); SDValue Neg = DAG.getNode(ISD::SUB, dl, VT, DAG.getConstant(0, dl, VT), N0); SDValue NegLo, NegHi; SplitInteger(Neg, NegLo, NegHi); GetExpandedInteger(N0, Lo, Hi); EVT NVT = Lo.getValueType(); SDValue HiIsNeg = DAG.getSetCC(dl, getSetCCResultType(NVT), DAG.getConstant(0, dl, NVT), Hi, ISD::SETGT); Lo = DAG.getSelect(dl, NVT, HiIsNeg, NegLo, Lo); Hi = DAG.getSelect(dl, NVT, HiIsNeg, NegHi, Hi); } void DAGTypeLegalizer::ExpandIntRes_CTLZ(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); // ctlz (HiLo) -> Hi != 0 ? ctlz(Hi) : (ctlz(Lo)+32) GetExpandedInteger(N->getOperand(0), Lo, Hi); EVT NVT = Lo.getValueType(); SDValue HiNotZero = DAG.getSetCC(dl, getSetCCResultType(NVT), Hi, DAG.getConstant(0, dl, NVT), ISD::SETNE); SDValue LoLZ = DAG.getNode(N->getOpcode(), dl, NVT, Lo); SDValue HiLZ = DAG.getNode(ISD::CTLZ_ZERO_UNDEF, dl, NVT, Hi); Lo = DAG.getSelect(dl, NVT, HiNotZero, HiLZ, DAG.getNode(ISD::ADD, dl, NVT, LoLZ, DAG.getConstant(NVT.getSizeInBits(), dl, NVT))); Hi = DAG.getConstant(0, dl, NVT); } void DAGTypeLegalizer::ExpandIntRes_CTPOP(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); // ctpop(HiLo) -> ctpop(Hi)+ctpop(Lo) GetExpandedInteger(N->getOperand(0), Lo, Hi); EVT NVT = Lo.getValueType(); Lo = DAG.getNode(ISD::ADD, dl, NVT, DAG.getNode(ISD::CTPOP, dl, NVT, Lo), DAG.getNode(ISD::CTPOP, dl, NVT, Hi)); Hi = DAG.getConstant(0, dl, NVT); } void DAGTypeLegalizer::ExpandIntRes_CTTZ(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); // cttz (HiLo) -> Lo != 0 ? cttz(Lo) : (cttz(Hi)+32) GetExpandedInteger(N->getOperand(0), Lo, Hi); EVT NVT = Lo.getValueType(); SDValue LoNotZero = DAG.getSetCC(dl, getSetCCResultType(NVT), Lo, DAG.getConstant(0, dl, NVT), ISD::SETNE); SDValue LoLZ = DAG.getNode(ISD::CTTZ_ZERO_UNDEF, dl, NVT, Lo); SDValue HiLZ = DAG.getNode(N->getOpcode(), dl, NVT, Hi); Lo = DAG.getSelect(dl, NVT, LoNotZero, LoLZ, DAG.getNode(ISD::ADD, dl, NVT, HiLZ, DAG.getConstant(NVT.getSizeInBits(), dl, NVT))); Hi = DAG.getConstant(0, dl, NVT); } void DAGTypeLegalizer::ExpandIntRes_FLT_ROUNDS(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); unsigned NBitWidth = NVT.getSizeInBits(); EVT ShiftAmtTy = TLI.getShiftAmountTy(NVT, DAG.getDataLayout()); Lo = DAG.getNode(ISD::FLT_ROUNDS_, dl, NVT); // The high part is the sign of Lo, as -1 is a valid value for FLT_ROUNDS Hi = DAG.getNode(ISD::SRA, dl, NVT, Lo, DAG.getConstant(NBitWidth - 1, dl, ShiftAmtTy)); } void DAGTypeLegalizer::ExpandIntRes_FP_TO_SINT(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); EVT VT = N->getValueType(0); bool IsStrict = N->isStrictFPOpcode(); SDValue Chain = IsStrict ? N->getOperand(0) : SDValue(); SDValue Op = N->getOperand(IsStrict ? 1 : 0); if (getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteFloat) Op = GetPromotedFloat(Op); RTLIB::Libcall LC = RTLIB::getFPTOSINT(Op.getValueType(), VT); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected fp-to-sint conversion!"); TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(true); std::pair Tmp = TLI.makeLibCall(DAG, LC, VT, Op, CallOptions, dl, Chain); SplitInteger(Tmp.first, Lo, Hi); if (IsStrict) ReplaceValueWith(SDValue(N, 1), Tmp.second); } void DAGTypeLegalizer::ExpandIntRes_FP_TO_UINT(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); EVT VT = N->getValueType(0); bool IsStrict = N->isStrictFPOpcode(); SDValue Chain = IsStrict ? N->getOperand(0) : SDValue(); SDValue Op = N->getOperand(IsStrict ? 1 : 0); if (getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteFloat) Op = GetPromotedFloat(Op); RTLIB::Libcall LC = RTLIB::getFPTOUINT(Op.getValueType(), VT); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected fp-to-uint conversion!"); TargetLowering::MakeLibCallOptions CallOptions; std::pair Tmp = TLI.makeLibCall(DAG, LC, VT, Op, CallOptions, dl, Chain); SplitInteger(Tmp.first, Lo, Hi); if (IsStrict) ReplaceValueWith(SDValue(N, 1), Tmp.second); } void DAGTypeLegalizer::ExpandIntRes_LLROUND_LLRINT(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue Op = N->getOperand(N->isStrictFPOpcode() ? 1 : 0); assert(getTypeAction(Op.getValueType()) != TargetLowering::TypePromoteFloat && "Input type needs to be promoted!"); EVT VT = Op.getValueType(); RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (N->getOpcode() == ISD::LLROUND || N->getOpcode() == ISD::STRICT_LLROUND) { if (VT == MVT::f32) LC = RTLIB::LLROUND_F32; else if (VT == MVT::f64) LC = RTLIB::LLROUND_F64; else if (VT == MVT::f80) LC = RTLIB::LLROUND_F80; else if (VT == MVT::f128) LC = RTLIB::LLROUND_F128; else if (VT == MVT::ppcf128) LC = RTLIB::LLROUND_PPCF128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected llround input type!"); } else if (N->getOpcode() == ISD::LLRINT || N->getOpcode() == ISD::STRICT_LLRINT) { if (VT == MVT::f32) LC = RTLIB::LLRINT_F32; else if (VT == MVT::f64) LC = RTLIB::LLRINT_F64; else if (VT == MVT::f80) LC = RTLIB::LLRINT_F80; else if (VT == MVT::f128) LC = RTLIB::LLRINT_F128; else if (VT == MVT::ppcf128) LC = RTLIB::LLRINT_PPCF128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unexpected llrint input type!"); } else llvm_unreachable("Unexpected opcode!"); SDLoc dl(N); EVT RetVT = N->getValueType(0); SDValue Chain = N->isStrictFPOpcode() ? N->getOperand(0) : SDValue(); TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(true); std::pair Tmp = TLI.makeLibCall(DAG, LC, RetVT, Op, CallOptions, dl, Chain); SplitInteger(Tmp.first, Lo, Hi); if (N->isStrictFPOpcode()) ReplaceValueWith(SDValue(N, 1), Tmp.second); } void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, SDValue &Lo, SDValue &Hi) { if (N->isAtomic()) { // It's typical to have larger CAS than atomic load instructions. SDLoc dl(N); EVT VT = N->getMemoryVT(); SDVTList VTs = DAG.getVTList(VT, MVT::i1, MVT::Other); SDValue Zero = DAG.getConstant(0, dl, VT); SDValue Swap = DAG.getAtomicCmpSwap( ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, dl, VT, VTs, N->getOperand(0), N->getOperand(1), Zero, Zero, N->getMemOperand()); ReplaceValueWith(SDValue(N, 0), Swap.getValue(0)); ReplaceValueWith(SDValue(N, 1), Swap.getValue(2)); return; } if (ISD::isNormalLoad(N)) { ExpandRes_NormalLoad(N, Lo, Hi); return; } assert(ISD::isUNINDEXEDLoad(N) && "Indexed load during type legalization!"); EVT VT = N->getValueType(0); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); SDValue Ch = N->getChain(); SDValue Ptr = N->getBasePtr(); ISD::LoadExtType ExtType = N->getExtensionType(); unsigned Alignment = N->getAlignment(); MachineMemOperand::Flags MMOFlags = N->getMemOperand()->getFlags(); AAMDNodes AAInfo = N->getAAInfo(); SDLoc dl(N); assert(NVT.isByteSized() && "Expanded type not byte sized!"); if (N->getMemoryVT().bitsLE(NVT)) { EVT MemVT = N->getMemoryVT(); Lo = DAG.getExtLoad(ExtType, dl, NVT, Ch, Ptr, N->getPointerInfo(), MemVT, Alignment, MMOFlags, AAInfo); // Remember the chain. Ch = Lo.getValue(1); if (ExtType == ISD::SEXTLOAD) { // The high part is obtained by SRA'ing all but one of the bits of the // lo part. unsigned LoSize = Lo.getValueSizeInBits(); Hi = DAG.getNode(ISD::SRA, dl, NVT, Lo, DAG.getConstant(LoSize - 1, dl, TLI.getPointerTy(DAG.getDataLayout()))); } else if (ExtType == ISD::ZEXTLOAD) { // The high part is just a zero. Hi = DAG.getConstant(0, dl, NVT); } else { assert(ExtType == ISD::EXTLOAD && "Unknown extload!"); // The high part is undefined. Hi = DAG.getUNDEF(NVT); } } else if (DAG.getDataLayout().isLittleEndian()) { // Little-endian - low bits are at low addresses. Lo = DAG.getLoad(NVT, dl, Ch, Ptr, N->getPointerInfo(), Alignment, MMOFlags, AAInfo); unsigned ExcessBits = N->getMemoryVT().getSizeInBits() - NVT.getSizeInBits(); EVT NEVT = EVT::getIntegerVT(*DAG.getContext(), ExcessBits); // Increment the pointer to the other half. unsigned IncrementSize = NVT.getSizeInBits()/8; Ptr = DAG.getMemBasePlusOffset(Ptr, IncrementSize, dl); Hi = DAG.getExtLoad(ExtType, dl, NVT, Ch, Ptr, N->getPointerInfo().getWithOffset(IncrementSize), NEVT, MinAlign(Alignment, IncrementSize), MMOFlags, AAInfo); // Build a factor node to remember that this load is independent of the // other one. Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), Hi.getValue(1)); } else { // Big-endian - high bits are at low addresses. Favor aligned loads at // the cost of some bit-fiddling. EVT MemVT = N->getMemoryVT(); unsigned EBytes = MemVT.getStoreSize(); unsigned IncrementSize = NVT.getSizeInBits()/8; unsigned ExcessBits = (EBytes - IncrementSize)*8; // Load both the high bits and maybe some of the low bits. Hi = DAG.getExtLoad(ExtType, dl, NVT, Ch, Ptr, N->getPointerInfo(), EVT::getIntegerVT(*DAG.getContext(), MemVT.getSizeInBits() - ExcessBits), Alignment, MMOFlags, AAInfo); // Increment the pointer to the other half. Ptr = DAG.getMemBasePlusOffset(Ptr, IncrementSize, dl); // Load the rest of the low bits. Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, NVT, Ch, Ptr, N->getPointerInfo().getWithOffset(IncrementSize), EVT::getIntegerVT(*DAG.getContext(), ExcessBits), MinAlign(Alignment, IncrementSize), MMOFlags, AAInfo); // Build a factor node to remember that this load is independent of the // other one. Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), Hi.getValue(1)); if (ExcessBits < NVT.getSizeInBits()) { // Transfer low bits from the bottom of Hi to the top of Lo. Lo = DAG.getNode( ISD::OR, dl, NVT, Lo, DAG.getNode(ISD::SHL, dl, NVT, Hi, DAG.getConstant(ExcessBits, dl, TLI.getPointerTy(DAG.getDataLayout())))); // Move high bits to the right position in Hi. Hi = DAG.getNode(ExtType == ISD::SEXTLOAD ? ISD::SRA : ISD::SRL, dl, NVT, Hi, DAG.getConstant(NVT.getSizeInBits() - ExcessBits, dl, TLI.getPointerTy(DAG.getDataLayout()))); } } // Legalize the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Ch); } void DAGTypeLegalizer::ExpandIntRes_Logical(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); SDValue LL, LH, RL, RH; GetExpandedInteger(N->getOperand(0), LL, LH); GetExpandedInteger(N->getOperand(1), RL, RH); Lo = DAG.getNode(N->getOpcode(), dl, LL.getValueType(), LL, RL); Hi = DAG.getNode(N->getOpcode(), dl, LL.getValueType(), LH, RH); } void DAGTypeLegalizer::ExpandIntRes_MUL(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT VT = N->getValueType(0); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); SDLoc dl(N); SDValue LL, LH, RL, RH; GetExpandedInteger(N->getOperand(0), LL, LH); GetExpandedInteger(N->getOperand(1), RL, RH); if (TLI.expandMUL(N, Lo, Hi, NVT, DAG, TargetLowering::MulExpansionKind::OnlyLegalOrCustom, LL, LH, RL, RH)) return; // If nothing else, we can make a libcall. RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i16) LC = RTLIB::MUL_I16; else if (VT == MVT::i32) LC = RTLIB::MUL_I32; else if (VT == MVT::i64) LC = RTLIB::MUL_I64; else if (VT == MVT::i128) LC = RTLIB::MUL_I128; if (LC == RTLIB::UNKNOWN_LIBCALL || !TLI.getLibcallName(LC)) { // We'll expand the multiplication by brute force because we have no other // options. This is a trivially-generalized version of the code from // Hacker's Delight (itself derived from Knuth's Algorithm M from section // 4.3.1). unsigned Bits = NVT.getSizeInBits(); unsigned HalfBits = Bits >> 1; SDValue Mask = DAG.getConstant(APInt::getLowBitsSet(Bits, HalfBits), dl, NVT); SDValue LLL = DAG.getNode(ISD::AND, dl, NVT, LL, Mask); SDValue RLL = DAG.getNode(ISD::AND, dl, NVT, RL, Mask); SDValue T = DAG.getNode(ISD::MUL, dl, NVT, LLL, RLL); SDValue TL = DAG.getNode(ISD::AND, dl, NVT, T, Mask); EVT ShiftAmtTy = TLI.getShiftAmountTy(NVT, DAG.getDataLayout()); if (APInt::getMaxValue(ShiftAmtTy.getSizeInBits()).ult(HalfBits)) { // The type from TLI is too small to fit the shift amount we want. // Override it with i32. The shift will have to be legalized. ShiftAmtTy = MVT::i32; } SDValue Shift = DAG.getConstant(HalfBits, dl, ShiftAmtTy); SDValue TH = DAG.getNode(ISD::SRL, dl, NVT, T, Shift); SDValue LLH = DAG.getNode(ISD::SRL, dl, NVT, LL, Shift); SDValue RLH = DAG.getNode(ISD::SRL, dl, NVT, RL, Shift); SDValue U = DAG.getNode(ISD::ADD, dl, NVT, DAG.getNode(ISD::MUL, dl, NVT, LLH, RLL), TH); SDValue UL = DAG.getNode(ISD::AND, dl, NVT, U, Mask); SDValue UH = DAG.getNode(ISD::SRL, dl, NVT, U, Shift); SDValue V = DAG.getNode(ISD::ADD, dl, NVT, DAG.getNode(ISD::MUL, dl, NVT, LLL, RLH), UL); SDValue VH = DAG.getNode(ISD::SRL, dl, NVT, V, Shift); SDValue W = DAG.getNode(ISD::ADD, dl, NVT, DAG.getNode(ISD::MUL, dl, NVT, LLH, RLH), DAG.getNode(ISD::ADD, dl, NVT, UH, VH)); Lo = DAG.getNode(ISD::ADD, dl, NVT, TL, DAG.getNode(ISD::SHL, dl, NVT, V, Shift)); Hi = DAG.getNode(ISD::ADD, dl, NVT, W, DAG.getNode(ISD::ADD, dl, NVT, DAG.getNode(ISD::MUL, dl, NVT, RH, LL), DAG.getNode(ISD::MUL, dl, NVT, RL, LH))); return; } SDValue Ops[2] = { N->getOperand(0), N->getOperand(1) }; TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(true); SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, CallOptions, dl).first, Lo, Hi); } void DAGTypeLegalizer::ExpandIntRes_READCYCLECOUNTER(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc DL(N); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDVTList VTs = DAG.getVTList(NVT, NVT, MVT::Other); SDValue R = DAG.getNode(N->getOpcode(), DL, VTs, N->getOperand(0)); Lo = R.getValue(0); Hi = R.getValue(1); ReplaceValueWith(SDValue(N, 1), R.getValue(2)); } void DAGTypeLegalizer::ExpandIntRes_ADDSUBSAT(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue Result = TLI.expandAddSubSat(N, DAG); SplitInteger(Result, Lo, Hi); } /// This performs an expansion of the integer result for a fixed point /// multiplication. The default expansion performs rounding down towards /// negative infinity, though targets that do care about rounding should specify /// a target hook for rounding and provide their own expansion or lowering of /// fixed point multiplication to be consistent with rounding. void DAGTypeLegalizer::ExpandIntRes_MULFIX(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); EVT VT = N->getValueType(0); unsigned VTSize = VT.getScalarSizeInBits(); SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); uint64_t Scale = N->getConstantOperandVal(2); bool Saturating = (N->getOpcode() == ISD::SMULFIXSAT || N->getOpcode() == ISD::UMULFIXSAT); bool Signed = (N->getOpcode() == ISD::SMULFIX || N->getOpcode() == ISD::SMULFIXSAT); // Handle special case when scale is equal to zero. if (!Scale) { SDValue Result; if (!Saturating) { Result = DAG.getNode(ISD::MUL, dl, VT, LHS, RHS); } else { EVT BoolVT = getSetCCResultType(VT); unsigned MulOp = Signed ? ISD::SMULO : ISD::UMULO; Result = DAG.getNode(MulOp, dl, DAG.getVTList(VT, BoolVT), LHS, RHS); SDValue Product = Result.getValue(0); SDValue Overflow = Result.getValue(1); if (Signed) { APInt MinVal = APInt::getSignedMinValue(VTSize); APInt MaxVal = APInt::getSignedMaxValue(VTSize); SDValue SatMin = DAG.getConstant(MinVal, dl, VT); SDValue SatMax = DAG.getConstant(MaxVal, dl, VT); SDValue Zero = DAG.getConstant(0, dl, VT); SDValue ProdNeg = DAG.getSetCC(dl, BoolVT, Product, Zero, ISD::SETLT); Result = DAG.getSelect(dl, VT, ProdNeg, SatMax, SatMin); Result = DAG.getSelect(dl, VT, Overflow, Result, Product); } else { // For unsigned multiplication, we only need to check the max since we // can't really overflow towards zero. APInt MaxVal = APInt::getMaxValue(VTSize); SDValue SatMax = DAG.getConstant(MaxVal, dl, VT); Result = DAG.getSelect(dl, VT, Overflow, SatMax, Product); } } SplitInteger(Result, Lo, Hi); return; } // For SMULFIX[SAT] we only expect to find Scale Result; unsigned LoHiOp = Signed ? ISD::SMUL_LOHI : ISD::UMUL_LOHI; if (!TLI.expandMUL_LOHI(LoHiOp, VT, dl, LHS, RHS, Result, NVT, DAG, TargetLowering::MulExpansionKind::OnlyLegalOrCustom, LL, LH, RL, RH)) { report_fatal_error("Unable to expand MUL_FIX using MUL_LOHI."); return; } unsigned NVTSize = NVT.getScalarSizeInBits(); assert((VTSize == NVTSize * 2) && "Expected the new value type to be half " "the size of the current value type"); EVT ShiftTy = TLI.getShiftAmountTy(NVT, DAG.getDataLayout()); // After getting the multiplication result in 4 parts, we need to perform a // shift right by the amount of the scale to get the result in that scale. // // Let's say we multiply 2 64 bit numbers. The resulting value can be held in // 128 bits that are cut into 4 32-bit parts: // // HH HL LH LL // |---32---|---32---|---32---|---32---| // 128 96 64 32 0 // // |------VTSize-----| // // |NVTSize-| // // The resulting Lo and Hi would normally be in LL and LH after the shift. But // to avoid unneccessary shifting of all 4 parts, we can adjust the shift // amount and get Lo and Hi using two funnel shifts. Or for the special case // when Scale is a multiple of NVTSize we can just pick the result without // shifting. uint64_t Part0 = Scale / NVTSize; // Part holding lowest bit needed. if (Scale % NVTSize) { SDValue ShiftAmount = DAG.getConstant(Scale % NVTSize, dl, ShiftTy); Lo = DAG.getNode(ISD::FSHR, dl, NVT, Result[Part0 + 1], Result[Part0], ShiftAmount); Hi = DAG.getNode(ISD::FSHR, dl, NVT, Result[Part0 + 2], Result[Part0 + 1], ShiftAmount); } else { Lo = Result[Part0]; Hi = Result[Part0 + 1]; } // Unless saturation is requested we are done. The result is in . if (!Saturating) return; // Can not overflow when there is no integer part. if (Scale == VTSize) return; // To handle saturation we must check for overflow in the multiplication. // // Unsigned overflow happened if the upper (VTSize - Scale) bits (of Result) // aren't all zeroes. // // Signed overflow happened if the upper (VTSize - Scale + 1) bits (of Result) // aren't all ones or all zeroes. // // We cannot overflow past HH when multiplying 2 ints of size VTSize, so the // highest bit of HH determines saturation direction in the event of signed // saturation. SDValue ResultHL = Result[2]; SDValue ResultHH = Result[3]; SDValue SatMax, SatMin; SDValue NVTZero = DAG.getConstant(0, dl, NVT); SDValue NVTNeg1 = DAG.getConstant(-1, dl, NVT); EVT BoolNVT = getSetCCResultType(NVT); if (!Signed) { if (Scale < NVTSize) { // Overflow happened if ((HH | (HL >> Scale)) != 0). SDValue HLAdjusted = DAG.getNode(ISD::SRL, dl, NVT, ResultHL, DAG.getConstant(Scale, dl, ShiftTy)); SDValue Tmp = DAG.getNode(ISD::OR, dl, NVT, HLAdjusted, ResultHH); SatMax = DAG.getSetCC(dl, BoolNVT, Tmp, NVTZero, ISD::SETNE); } else if (Scale == NVTSize) { // Overflow happened if (HH != 0). SatMax = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTZero, ISD::SETNE); } else if (Scale < VTSize) { // Overflow happened if ((HH >> (Scale - NVTSize)) != 0). SDValue HLAdjusted = DAG.getNode(ISD::SRL, dl, NVT, ResultHL, DAG.getConstant(Scale - NVTSize, dl, ShiftTy)); SatMax = DAG.getSetCC(dl, BoolNVT, HLAdjusted, NVTZero, ISD::SETNE); } else llvm_unreachable("Scale must be less or equal to VTSize for UMULFIXSAT" "(and saturation can't happen with Scale==VTSize)."); Hi = DAG.getSelect(dl, NVT, SatMax, NVTNeg1, Hi); Lo = DAG.getSelect(dl, NVT, SatMax, NVTNeg1, Lo); return; } if (Scale < NVTSize) { // The number of overflow bits we can check are VTSize - Scale + 1 (we // include the sign bit). If these top bits are > 0, then we overflowed past // the max value. If these top bits are < -1, then we overflowed past the // min value. Otherwise, we did not overflow. unsigned OverflowBits = VTSize - Scale + 1; assert(OverflowBits <= VTSize && OverflowBits > NVTSize && "Extent of overflow bits must start within HL"); SDValue HLHiMask = DAG.getConstant( APInt::getHighBitsSet(NVTSize, OverflowBits - NVTSize), dl, NVT); SDValue HLLoMask = DAG.getConstant( APInt::getLowBitsSet(NVTSize, VTSize - OverflowBits), dl, NVT); // We overflow max if HH > 0 or (HH == 0 && HL > HLLoMask). SDValue HHGT0 = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTZero, ISD::SETGT); SDValue HHEQ0 = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTZero, ISD::SETEQ); SDValue HLUGT = DAG.getSetCC(dl, BoolNVT, ResultHL, HLLoMask, ISD::SETUGT); SatMax = DAG.getNode(ISD::OR, dl, BoolNVT, HHGT0, DAG.getNode(ISD::AND, dl, BoolNVT, HHEQ0, HLUGT)); // We overflow min if HH < -1 or (HH == -1 && HL < HLHiMask). SDValue HHLT = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTNeg1, ISD::SETLT); SDValue HHEQ = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTNeg1, ISD::SETEQ); SDValue HLULT = DAG.getSetCC(dl, BoolNVT, ResultHL, HLHiMask, ISD::SETULT); SatMin = DAG.getNode(ISD::OR, dl, BoolNVT, HHLT, DAG.getNode(ISD::AND, dl, BoolNVT, HHEQ, HLULT)); } else if (Scale == NVTSize) { // We overflow max if HH > 0 or (HH == 0 && HL sign bit is 1). SDValue HHGT0 = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTZero, ISD::SETGT); SDValue HHEQ0 = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTZero, ISD::SETEQ); SDValue HLNeg = DAG.getSetCC(dl, BoolNVT, ResultHL, NVTZero, ISD::SETLT); SatMax = DAG.getNode(ISD::OR, dl, BoolNVT, HHGT0, DAG.getNode(ISD::AND, dl, BoolNVT, HHEQ0, HLNeg)); // We overflow min if HH < -1 or (HH == -1 && HL sign bit is 0). SDValue HHLT = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTNeg1, ISD::SETLT); SDValue HHEQ = DAG.getSetCC(dl, BoolNVT, ResultHH, NVTNeg1, ISD::SETEQ); SDValue HLPos = DAG.getSetCC(dl, BoolNVT, ResultHL, NVTZero, ISD::SETGE); SatMin = DAG.getNode(ISD::OR, dl, BoolNVT, HHLT, DAG.getNode(ISD::AND, dl, BoolNVT, HHEQ, HLPos)); } else if (Scale < VTSize) { // This is similar to the case when we saturate if Scale < NVTSize, but we // only need to check HH. unsigned OverflowBits = VTSize - Scale + 1; SDValue HHHiMask = DAG.getConstant( APInt::getHighBitsSet(NVTSize, OverflowBits), dl, NVT); SDValue HHLoMask = DAG.getConstant( APInt::getLowBitsSet(NVTSize, NVTSize - OverflowBits), dl, NVT); SatMax = DAG.getSetCC(dl, BoolNVT, ResultHH, HHLoMask, ISD::SETGT); SatMin = DAG.getSetCC(dl, BoolNVT, ResultHH, HHHiMask, ISD::SETLT); } else llvm_unreachable("Illegal scale for signed fixed point mul."); // Saturate to signed maximum. APInt MaxHi = APInt::getSignedMaxValue(NVTSize); APInt MaxLo = APInt::getAllOnesValue(NVTSize); Hi = DAG.getSelect(dl, NVT, SatMax, DAG.getConstant(MaxHi, dl, NVT), Hi); Lo = DAG.getSelect(dl, NVT, SatMax, DAG.getConstant(MaxLo, dl, NVT), Lo); // Saturate to signed minimum. APInt MinHi = APInt::getSignedMinValue(NVTSize); Hi = DAG.getSelect(dl, NVT, SatMin, DAG.getConstant(MinHi, dl, NVT), Hi); Lo = DAG.getSelect(dl, NVT, SatMin, NVTZero, Lo); } void DAGTypeLegalizer::ExpandIntRes_DIVFIX(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue Res = earlyExpandDIVFIX(N, N->getOperand(0), N->getOperand(1), N->getConstantOperandVal(2), TLI, DAG); SplitInteger(Res, Lo, Hi); } void DAGTypeLegalizer::ExpandIntRes_SADDSUBO(SDNode *Node, SDValue &Lo, SDValue &Hi) { SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); SDLoc dl(Node); // Expand the result by simply replacing it with the equivalent // non-overflow-checking operation. SDValue Sum = DAG.getNode(Node->getOpcode() == ISD::SADDO ? ISD::ADD : ISD::SUB, dl, LHS.getValueType(), LHS, RHS); SplitInteger(Sum, Lo, Hi); // Compute the overflow. // // LHSSign -> LHS >= 0 // RHSSign -> RHS >= 0 // SumSign -> Sum >= 0 // // Add: // Overflow -> (LHSSign == RHSSign) && (LHSSign != SumSign) // Sub: // Overflow -> (LHSSign != RHSSign) && (LHSSign != SumSign) // EVT OType = Node->getValueType(1); SDValue Zero = DAG.getConstant(0, dl, LHS.getValueType()); SDValue LHSSign = DAG.getSetCC(dl, OType, LHS, Zero, ISD::SETGE); SDValue RHSSign = DAG.getSetCC(dl, OType, RHS, Zero, ISD::SETGE); SDValue SignsMatch = DAG.getSetCC(dl, OType, LHSSign, RHSSign, Node->getOpcode() == ISD::SADDO ? ISD::SETEQ : ISD::SETNE); SDValue SumSign = DAG.getSetCC(dl, OType, Sum, Zero, ISD::SETGE); SDValue SumSignNE = DAG.getSetCC(dl, OType, LHSSign, SumSign, ISD::SETNE); SDValue Cmp = DAG.getNode(ISD::AND, dl, OType, SignsMatch, SumSignNE); // Use the calculated overflow everywhere. ReplaceValueWith(SDValue(Node, 1), Cmp); } void DAGTypeLegalizer::ExpandIntRes_SDIV(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT VT = N->getValueType(0); SDLoc dl(N); SDValue Ops[2] = { N->getOperand(0), N->getOperand(1) }; if (TLI.getOperationAction(ISD::SDIVREM, VT) == TargetLowering::Custom) { SDValue Res = DAG.getNode(ISD::SDIVREM, dl, DAG.getVTList(VT, VT), Ops); SplitInteger(Res.getValue(0), Lo, Hi); return; } RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i16) LC = RTLIB::SDIV_I16; else if (VT == MVT::i32) LC = RTLIB::SDIV_I32; else if (VT == MVT::i64) LC = RTLIB::SDIV_I64; else if (VT == MVT::i128) LC = RTLIB::SDIV_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SDIV!"); TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(true); SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, CallOptions, dl).first, Lo, Hi); } void DAGTypeLegalizer::ExpandIntRes_Shift(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT VT = N->getValueType(0); SDLoc dl(N); // If we can emit an efficient shift operation, do so now. Check to see if // the RHS is a constant. if (ConstantSDNode *CN = dyn_cast(N->getOperand(1))) return ExpandShiftByConstant(N, CN->getAPIntValue(), Lo, Hi); // If we can determine that the high bit of the shift is zero or one, even if // the low bits are variable, emit this shift in an optimized form. if (ExpandShiftWithKnownAmountBit(N, Lo, Hi)) return; // If this target supports shift_PARTS, use it. First, map to the _PARTS opc. unsigned PartsOpc; if (N->getOpcode() == ISD::SHL) { PartsOpc = ISD::SHL_PARTS; } else if (N->getOpcode() == ISD::SRL) { PartsOpc = ISD::SRL_PARTS; } else { assert(N->getOpcode() == ISD::SRA && "Unknown shift!"); PartsOpc = ISD::SRA_PARTS; } // Next check to see if the target supports this SHL_PARTS operation or if it // will custom expand it. Don't lower this to SHL_PARTS when we optimise for // size, but create a libcall instead. EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); TargetLowering::LegalizeAction Action = TLI.getOperationAction(PartsOpc, NVT); const bool LegalOrCustom = (Action == TargetLowering::Legal && TLI.isTypeLegal(NVT)) || Action == TargetLowering::Custom; if (LegalOrCustom && TLI.shouldExpandShift(DAG, N)) { // Expand the subcomponents. SDValue LHSL, LHSH; GetExpandedInteger(N->getOperand(0), LHSL, LHSH); EVT VT = LHSL.getValueType(); // If the shift amount operand is coming from a vector legalization it may // have an illegal type. Fix that first by casting the operand, otherwise // the new SHL_PARTS operation would need further legalization. SDValue ShiftOp = N->getOperand(1); EVT ShiftTy = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); assert(ShiftTy.getScalarSizeInBits() >= Log2_32_Ceil(VT.getScalarSizeInBits()) && "ShiftAmountTy is too small to cover the range of this type!"); if (ShiftOp.getValueType() != ShiftTy) ShiftOp = DAG.getZExtOrTrunc(ShiftOp, dl, ShiftTy); SDValue Ops[] = { LHSL, LHSH, ShiftOp }; Lo = DAG.getNode(PartsOpc, dl, DAG.getVTList(VT, VT), Ops); Hi = Lo.getValue(1); return; } // Otherwise, emit a libcall. RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; bool isSigned; if (N->getOpcode() == ISD::SHL) { isSigned = false; /*sign irrelevant*/ if (VT == MVT::i16) LC = RTLIB::SHL_I16; else if (VT == MVT::i32) LC = RTLIB::SHL_I32; else if (VT == MVT::i64) LC = RTLIB::SHL_I64; else if (VT == MVT::i128) LC = RTLIB::SHL_I128; } else if (N->getOpcode() == ISD::SRL) { isSigned = false; if (VT == MVT::i16) LC = RTLIB::SRL_I16; else if (VT == MVT::i32) LC = RTLIB::SRL_I32; else if (VT == MVT::i64) LC = RTLIB::SRL_I64; else if (VT == MVT::i128) LC = RTLIB::SRL_I128; } else { assert(N->getOpcode() == ISD::SRA && "Unknown shift!"); isSigned = true; if (VT == MVT::i16) LC = RTLIB::SRA_I16; else if (VT == MVT::i32) LC = RTLIB::SRA_I32; else if (VT == MVT::i64) LC = RTLIB::SRA_I64; else if (VT == MVT::i128) LC = RTLIB::SRA_I128; } if (LC != RTLIB::UNKNOWN_LIBCALL && TLI.getLibcallName(LC)) { SDValue Ops[2] = { N->getOperand(0), N->getOperand(1) }; TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(isSigned); SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, CallOptions, dl).first, Lo, Hi); return; } if (!ExpandShiftWithUnknownAmountBit(N, Lo, Hi)) llvm_unreachable("Unsupported shift!"); } void DAGTypeLegalizer::ExpandIntRes_SIGN_EXTEND(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDLoc dl(N); SDValue Op = N->getOperand(0); if (Op.getValueType().bitsLE(NVT)) { // The low part is sign extension of the input (degenerates to a copy). Lo = DAG.getNode(ISD::SIGN_EXTEND, dl, NVT, N->getOperand(0)); // The high part is obtained by SRA'ing all but one of the bits of low part. unsigned LoSize = NVT.getSizeInBits(); Hi = DAG.getNode( ISD::SRA, dl, NVT, Lo, DAG.getConstant(LoSize - 1, dl, TLI.getPointerTy(DAG.getDataLayout()))); } else { // For example, extension of an i48 to an i64. The operand type necessarily // promotes to the result type, so will end up being expanded too. assert(getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteInteger && "Only know how to promote this result!"); SDValue Res = GetPromotedInteger(Op); assert(Res.getValueType() == N->getValueType(0) && "Operand over promoted?"); // Split the promoted operand. This will simplify when it is expanded. SplitInteger(Res, Lo, Hi); unsigned ExcessBits = Op.getValueSizeInBits() - NVT.getSizeInBits(); Hi = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Hi.getValueType(), Hi, DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), ExcessBits))); } } void DAGTypeLegalizer:: ExpandIntRes_SIGN_EXTEND_INREG(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); GetExpandedInteger(N->getOperand(0), Lo, Hi); EVT EVT = cast(N->getOperand(1))->getVT(); if (EVT.bitsLE(Lo.getValueType())) { // sext_inreg the low part if needed. Lo = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Lo.getValueType(), Lo, N->getOperand(1)); // The high part gets the sign extension from the lo-part. This handles // things like sextinreg V:i64 from i8. Hi = DAG.getNode(ISD::SRA, dl, Hi.getValueType(), Lo, DAG.getConstant(Hi.getValueSizeInBits() - 1, dl, TLI.getPointerTy(DAG.getDataLayout()))); } else { // For example, extension of an i48 to an i64. Leave the low part alone, // sext_inreg the high part. unsigned ExcessBits = EVT.getSizeInBits() - Lo.getValueSizeInBits(); Hi = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, Hi.getValueType(), Hi, DAG.getValueType(EVT::getIntegerVT(*DAG.getContext(), ExcessBits))); } } void DAGTypeLegalizer::ExpandIntRes_SREM(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT VT = N->getValueType(0); SDLoc dl(N); SDValue Ops[2] = { N->getOperand(0), N->getOperand(1) }; if (TLI.getOperationAction(ISD::SDIVREM, VT) == TargetLowering::Custom) { SDValue Res = DAG.getNode(ISD::SDIVREM, dl, DAG.getVTList(VT, VT), Ops); SplitInteger(Res.getValue(1), Lo, Hi); return; } RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i16) LC = RTLIB::SREM_I16; else if (VT == MVT::i32) LC = RTLIB::SREM_I32; else if (VT == MVT::i64) LC = RTLIB::SREM_I64; else if (VT == MVT::i128) LC = RTLIB::SREM_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SREM!"); TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(true); SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, CallOptions, dl).first, Lo, Hi); } void DAGTypeLegalizer::ExpandIntRes_TRUNCATE(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDLoc dl(N); Lo = DAG.getNode(ISD::TRUNCATE, dl, NVT, N->getOperand(0)); Hi = DAG.getNode(ISD::SRL, dl, N->getOperand(0).getValueType(), N->getOperand(0), DAG.getConstant(NVT.getSizeInBits(), dl, TLI.getPointerTy(DAG.getDataLayout()))); Hi = DAG.getNode(ISD::TRUNCATE, dl, NVT, Hi); } void DAGTypeLegalizer::ExpandIntRes_XMULO(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT VT = N->getValueType(0); SDLoc dl(N); if (N->getOpcode() == ISD::UMULO) { // This section expands the operation into the following sequence of // instructions. `iNh` here refers to a type which has half the bit width of // the type the original operation operated on. // // %0 = %LHS.HI != 0 && %RHS.HI != 0 // %1 = { iNh, i1 } @umul.with.overflow.iNh(iNh %LHS.HI, iNh %RHS.LO) // %2 = { iNh, i1 } @umul.with.overflow.iNh(iNh %RHS.HI, iNh %LHS.LO) // %3 = mul nuw iN (%LHS.LOW as iN), (%RHS.LOW as iN) // %4 = add iN (%1.0 as iN) << Nh, (%2.0 as iN) << Nh // %5 = { iN, i1 } @uadd.with.overflow.iN( %4, %3 ) // // %res = { %5.0, %0 || %1.1 || %2.1 || %5.1 } SDValue LHS = N->getOperand(0), RHS = N->getOperand(1); SDValue LHSHigh, LHSLow, RHSHigh, RHSLow; SplitInteger(LHS, LHSLow, LHSHigh); SplitInteger(RHS, RHSLow, RHSHigh); EVT HalfVT = LHSLow.getValueType() , BitVT = N->getValueType(1); SDVTList VTHalfMulO = DAG.getVTList(HalfVT, BitVT); SDVTList VTFullAddO = DAG.getVTList(VT, BitVT); SDValue HalfZero = DAG.getConstant(0, dl, HalfVT); SDValue Overflow = DAG.getNode(ISD::AND, dl, BitVT, DAG.getSetCC(dl, BitVT, LHSHigh, HalfZero, ISD::SETNE), DAG.getSetCC(dl, BitVT, RHSHigh, HalfZero, ISD::SETNE)); SDValue One = DAG.getNode(ISD::UMULO, dl, VTHalfMulO, LHSHigh, RHSLow); Overflow = DAG.getNode(ISD::OR, dl, BitVT, Overflow, One.getValue(1)); SDValue OneInHigh = DAG.getNode(ISD::BUILD_PAIR, dl, VT, HalfZero, One.getValue(0)); SDValue Two = DAG.getNode(ISD::UMULO, dl, VTHalfMulO, RHSHigh, LHSLow); Overflow = DAG.getNode(ISD::OR, dl, BitVT, Overflow, Two.getValue(1)); SDValue TwoInHigh = DAG.getNode(ISD::BUILD_PAIR, dl, VT, HalfZero, Two.getValue(0)); // Cannot use `UMUL_LOHI` directly, because some 32-bit targets (ARM) do not // know how to expand `i64,i64 = umul_lohi a, b` and abort (why isn’t this // operation recursively legalized?). // // Many backends understand this pattern and will convert into LOHI // themselves, if applicable. SDValue Three = DAG.getNode(ISD::MUL, dl, VT, DAG.getNode(ISD::ZERO_EXTEND, dl, VT, LHSLow), DAG.getNode(ISD::ZERO_EXTEND, dl, VT, RHSLow)); SDValue Four = DAG.getNode(ISD::ADD, dl, VT, OneInHigh, TwoInHigh); SDValue Five = DAG.getNode(ISD::UADDO, dl, VTFullAddO, Three, Four); Overflow = DAG.getNode(ISD::OR, dl, BitVT, Overflow, Five.getValue(1)); SplitInteger(Five, Lo, Hi); ReplaceValueWith(SDValue(N, 1), Overflow); return; } Type *RetTy = VT.getTypeForEVT(*DAG.getContext()); EVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); Type *PtrTy = PtrVT.getTypeForEVT(*DAG.getContext()); // Replace this with a libcall that will check overflow. RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i32) LC = RTLIB::MULO_I32; else if (VT == MVT::i64) LC = RTLIB::MULO_I64; else if (VT == MVT::i128) LC = RTLIB::MULO_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported XMULO!"); SDValue Temp = DAG.CreateStackTemporary(PtrVT); // Temporary for the overflow value, default it to zero. SDValue Chain = DAG.getStore(DAG.getEntryNode(), dl, DAG.getConstant(0, dl, PtrVT), Temp, MachinePointerInfo()); TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; for (const SDValue &Op : N->op_values()) { EVT ArgVT = Op.getValueType(); Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); Entry.Node = Op; Entry.Ty = ArgTy; Entry.IsSExt = true; Entry.IsZExt = false; Args.push_back(Entry); } // Also pass the address of the overflow check. Entry.Node = Temp; Entry.Ty = PtrTy->getPointerTo(); Entry.IsSExt = true; Entry.IsZExt = false; Args.push_back(Entry); SDValue Func = DAG.getExternalSymbol(TLI.getLibcallName(LC), PtrVT); TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl) .setChain(Chain) .setLibCallee(TLI.getLibcallCallingConv(LC), RetTy, Func, std::move(Args)) .setSExtResult(); std::pair CallInfo = TLI.LowerCallTo(CLI); SplitInteger(CallInfo.first, Lo, Hi); SDValue Temp2 = DAG.getLoad(PtrVT, dl, CallInfo.second, Temp, MachinePointerInfo()); SDValue Ofl = DAG.getSetCC(dl, N->getValueType(1), Temp2, DAG.getConstant(0, dl, PtrVT), ISD::SETNE); // Use the overflow from the libcall everywhere. ReplaceValueWith(SDValue(N, 1), Ofl); } void DAGTypeLegalizer::ExpandIntRes_UDIV(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT VT = N->getValueType(0); SDLoc dl(N); SDValue Ops[2] = { N->getOperand(0), N->getOperand(1) }; if (TLI.getOperationAction(ISD::UDIVREM, VT) == TargetLowering::Custom) { SDValue Res = DAG.getNode(ISD::UDIVREM, dl, DAG.getVTList(VT, VT), Ops); SplitInteger(Res.getValue(0), Lo, Hi); return; } RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i16) LC = RTLIB::UDIV_I16; else if (VT == MVT::i32) LC = RTLIB::UDIV_I32; else if (VT == MVT::i64) LC = RTLIB::UDIV_I64; else if (VT == MVT::i128) LC = RTLIB::UDIV_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported UDIV!"); TargetLowering::MakeLibCallOptions CallOptions; SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, CallOptions, dl).first, Lo, Hi); } void DAGTypeLegalizer::ExpandIntRes_UREM(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT VT = N->getValueType(0); SDLoc dl(N); SDValue Ops[2] = { N->getOperand(0), N->getOperand(1) }; if (TLI.getOperationAction(ISD::UDIVREM, VT) == TargetLowering::Custom) { SDValue Res = DAG.getNode(ISD::UDIVREM, dl, DAG.getVTList(VT, VT), Ops); SplitInteger(Res.getValue(1), Lo, Hi); return; } RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (VT == MVT::i16) LC = RTLIB::UREM_I16; else if (VT == MVT::i32) LC = RTLIB::UREM_I32; else if (VT == MVT::i64) LC = RTLIB::UREM_I64; else if (VT == MVT::i128) LC = RTLIB::UREM_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported UREM!"); TargetLowering::MakeLibCallOptions CallOptions; SplitInteger(TLI.makeLibCall(DAG, LC, VT, Ops, CallOptions, dl).first, Lo, Hi); } void DAGTypeLegalizer::ExpandIntRes_ZERO_EXTEND(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDLoc dl(N); SDValue Op = N->getOperand(0); if (Op.getValueType().bitsLE(NVT)) { // The low part is zero extension of the input (degenerates to a copy). Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, NVT, N->getOperand(0)); Hi = DAG.getConstant(0, dl, NVT); // The high part is just a zero. } else { // For example, extension of an i48 to an i64. The operand type necessarily // promotes to the result type, so will end up being expanded too. assert(getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteInteger && "Only know how to promote this result!"); SDValue Res = GetPromotedInteger(Op); assert(Res.getValueType() == N->getValueType(0) && "Operand over promoted?"); // Split the promoted operand. This will simplify when it is expanded. SplitInteger(Res, Lo, Hi); unsigned ExcessBits = Op.getValueSizeInBits() - NVT.getSizeInBits(); Hi = DAG.getZeroExtendInReg(Hi, dl, EVT::getIntegerVT(*DAG.getContext(), ExcessBits)); } } void DAGTypeLegalizer::ExpandIntRes_ATOMIC_LOAD(SDNode *N, SDValue &Lo, SDValue &Hi) { SDLoc dl(N); EVT VT = cast(N)->getMemoryVT(); SDVTList VTs = DAG.getVTList(VT, MVT::i1, MVT::Other); SDValue Zero = DAG.getConstant(0, dl, VT); SDValue Swap = DAG.getAtomicCmpSwap( ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS, dl, cast(N)->getMemoryVT(), VTs, N->getOperand(0), N->getOperand(1), Zero, Zero, cast(N)->getMemOperand()); ReplaceValueWith(SDValue(N, 0), Swap.getValue(0)); ReplaceValueWith(SDValue(N, 1), Swap.getValue(2)); } void DAGTypeLegalizer::ExpandIntRes_VECREDUCE(SDNode *N, SDValue &Lo, SDValue &Hi) { // TODO For VECREDUCE_(AND|OR|XOR) we could split the vector and calculate // both halves independently. SDValue Res = TLI.expandVecReduce(N, DAG); SplitInteger(Res, Lo, Hi); } //===----------------------------------------------------------------------===// // Integer Operand Expansion //===----------------------------------------------------------------------===// /// ExpandIntegerOperand - This method is called when the specified operand of /// the specified node is found to need expansion. At this point, all of the /// result types of the node are known to be legal, but other operands of the /// node may need promotion or expansion as well as the specified one. bool DAGTypeLegalizer::ExpandIntegerOperand(SDNode *N, unsigned OpNo) { LLVM_DEBUG(dbgs() << "Expand integer operand: "; N->dump(&DAG); dbgs() << "\n"); SDValue Res = SDValue(); if (CustomLowerNode(N, N->getOperand(OpNo).getValueType(), false)) return false; switch (N->getOpcode()) { default: #ifndef NDEBUG dbgs() << "ExpandIntegerOperand Op #" << OpNo << ": "; N->dump(&DAG); dbgs() << "\n"; #endif report_fatal_error("Do not know how to expand this operator's operand!"); case ISD::BITCAST: Res = ExpandOp_BITCAST(N); break; case ISD::BR_CC: Res = ExpandIntOp_BR_CC(N); break; case ISD::BUILD_VECTOR: Res = ExpandOp_BUILD_VECTOR(N); break; case ISD::EXTRACT_ELEMENT: Res = ExpandOp_EXTRACT_ELEMENT(N); break; case ISD::INSERT_VECTOR_ELT: Res = ExpandOp_INSERT_VECTOR_ELT(N); break; case ISD::SCALAR_TO_VECTOR: Res = ExpandOp_SCALAR_TO_VECTOR(N); break; case ISD::SELECT_CC: Res = ExpandIntOp_SELECT_CC(N); break; case ISD::SETCC: Res = ExpandIntOp_SETCC(N); break; case ISD::SETCCCARRY: Res = ExpandIntOp_SETCCCARRY(N); break; case ISD::STRICT_SINT_TO_FP: case ISD::SINT_TO_FP: Res = ExpandIntOp_SINT_TO_FP(N); break; case ISD::STORE: Res = ExpandIntOp_STORE(cast(N), OpNo); break; case ISD::TRUNCATE: Res = ExpandIntOp_TRUNCATE(N); break; case ISD::STRICT_UINT_TO_FP: case ISD::UINT_TO_FP: Res = ExpandIntOp_UINT_TO_FP(N); break; case ISD::SHL: case ISD::SRA: case ISD::SRL: case ISD::ROTL: case ISD::ROTR: Res = ExpandIntOp_Shift(N); break; case ISD::RETURNADDR: case ISD::FRAMEADDR: Res = ExpandIntOp_RETURNADDR(N); break; case ISD::ATOMIC_STORE: Res = ExpandIntOp_ATOMIC_STORE(N); break; } // If the result is null, the sub-method took care of registering results etc. if (!Res.getNode()) return false; // If the result is N, the sub-method updated N in place. Tell the legalizer // core about this. if (Res.getNode() == N) return true; assert(Res.getValueType() == N->getValueType(0) && N->getNumValues() == 1 && "Invalid operand expansion"); ReplaceValueWith(SDValue(N, 0), Res); return false; } /// IntegerExpandSetCCOperands - Expand the operands of a comparison. This code /// is shared among BR_CC, SELECT_CC, and SETCC handlers. void DAGTypeLegalizer::IntegerExpandSetCCOperands(SDValue &NewLHS, SDValue &NewRHS, ISD::CondCode &CCCode, const SDLoc &dl) { SDValue LHSLo, LHSHi, RHSLo, RHSHi; GetExpandedInteger(NewLHS, LHSLo, LHSHi); GetExpandedInteger(NewRHS, RHSLo, RHSHi); if (CCCode == ISD::SETEQ || CCCode == ISD::SETNE) { if (RHSLo == RHSHi) { if (ConstantSDNode *RHSCST = dyn_cast(RHSLo)) { if (RHSCST->isAllOnesValue()) { // Equality comparison to -1. NewLHS = DAG.getNode(ISD::AND, dl, LHSLo.getValueType(), LHSLo, LHSHi); NewRHS = RHSLo; return; } } } NewLHS = DAG.getNode(ISD::XOR, dl, LHSLo.getValueType(), LHSLo, RHSLo); NewRHS = DAG.getNode(ISD::XOR, dl, LHSLo.getValueType(), LHSHi, RHSHi); NewLHS = DAG.getNode(ISD::OR, dl, NewLHS.getValueType(), NewLHS, NewRHS); NewRHS = DAG.getConstant(0, dl, NewLHS.getValueType()); return; } // If this is a comparison of the sign bit, just look at the top part. // X > -1, x < 0 if (ConstantSDNode *CST = dyn_cast(NewRHS)) if ((CCCode == ISD::SETLT && CST->isNullValue()) || // X < 0 (CCCode == ISD::SETGT && CST->isAllOnesValue())) { // X > -1 NewLHS = LHSHi; NewRHS = RHSHi; return; } // FIXME: This generated code sucks. ISD::CondCode LowCC; switch (CCCode) { default: llvm_unreachable("Unknown integer setcc!"); case ISD::SETLT: case ISD::SETULT: LowCC = ISD::SETULT; break; case ISD::SETGT: case ISD::SETUGT: LowCC = ISD::SETUGT; break; case ISD::SETLE: case ISD::SETULE: LowCC = ISD::SETULE; break; case ISD::SETGE: case ISD::SETUGE: LowCC = ISD::SETUGE; break; } // LoCmp = lo(op1) < lo(op2) // Always unsigned comparison // HiCmp = hi(op1) < hi(op2) // Signedness depends on operands // dest = hi(op1) == hi(op2) ? LoCmp : HiCmp; // NOTE: on targets without efficient SELECT of bools, we can always use // this identity: (B1 ? B2 : B3) --> (B1 & B2)|(!B1&B3) TargetLowering::DAGCombinerInfo DagCombineInfo(DAG, AfterLegalizeTypes, true, nullptr); SDValue LoCmp, HiCmp; if (TLI.isTypeLegal(LHSLo.getValueType()) && TLI.isTypeLegal(RHSLo.getValueType())) LoCmp = TLI.SimplifySetCC(getSetCCResultType(LHSLo.getValueType()), LHSLo, RHSLo, LowCC, false, DagCombineInfo, dl); if (!LoCmp.getNode()) LoCmp = DAG.getSetCC(dl, getSetCCResultType(LHSLo.getValueType()), LHSLo, RHSLo, LowCC); if (TLI.isTypeLegal(LHSHi.getValueType()) && TLI.isTypeLegal(RHSHi.getValueType())) HiCmp = TLI.SimplifySetCC(getSetCCResultType(LHSHi.getValueType()), LHSHi, RHSHi, CCCode, false, DagCombineInfo, dl); if (!HiCmp.getNode()) HiCmp = DAG.getNode(ISD::SETCC, dl, getSetCCResultType(LHSHi.getValueType()), LHSHi, RHSHi, DAG.getCondCode(CCCode)); ConstantSDNode *LoCmpC = dyn_cast(LoCmp.getNode()); ConstantSDNode *HiCmpC = dyn_cast(HiCmp.getNode()); bool EqAllowed = (CCCode == ISD::SETLE || CCCode == ISD::SETGE || CCCode == ISD::SETUGE || CCCode == ISD::SETULE); if ((EqAllowed && (HiCmpC && HiCmpC->isNullValue())) || (!EqAllowed && ((HiCmpC && (HiCmpC->getAPIntValue() == 1)) || (LoCmpC && LoCmpC->isNullValue())))) { // For LE / GE, if high part is known false, ignore the low part. // For LT / GT: if low part is known false, return the high part. // if high part is known true, ignore the low part. NewLHS = HiCmp; NewRHS = SDValue(); return; } if (LHSHi == RHSHi) { // Comparing the low bits is enough. NewLHS = LoCmp; NewRHS = SDValue(); return; } // Lower with SETCCCARRY if the target supports it. EVT HiVT = LHSHi.getValueType(); EVT ExpandVT = TLI.getTypeToExpandTo(*DAG.getContext(), HiVT); bool HasSETCCCARRY = TLI.isOperationLegalOrCustom(ISD::SETCCCARRY, ExpandVT); // FIXME: Make all targets support this, then remove the other lowering. if (HasSETCCCARRY) { // SETCCCARRY can detect < and >= directly. For > and <=, flip // operands and condition code. bool FlipOperands = false; switch (CCCode) { case ISD::SETGT: CCCode = ISD::SETLT; FlipOperands = true; break; case ISD::SETUGT: CCCode = ISD::SETULT; FlipOperands = true; break; case ISD::SETLE: CCCode = ISD::SETGE; FlipOperands = true; break; case ISD::SETULE: CCCode = ISD::SETUGE; FlipOperands = true; break; default: break; } if (FlipOperands) { std::swap(LHSLo, RHSLo); std::swap(LHSHi, RHSHi); } // Perform a wide subtraction, feeding the carry from the low part into // SETCCCARRY. The SETCCCARRY operation is essentially looking at the high // part of the result of LHS - RHS. It is negative iff LHS < RHS. It is // zero or positive iff LHS >= RHS. EVT LoVT = LHSLo.getValueType(); SDVTList VTList = DAG.getVTList(LoVT, getSetCCResultType(LoVT)); SDValue LowCmp = DAG.getNode(ISD::USUBO, dl, VTList, LHSLo, RHSLo); SDValue Res = DAG.getNode(ISD::SETCCCARRY, dl, getSetCCResultType(HiVT), LHSHi, RHSHi, LowCmp.getValue(1), DAG.getCondCode(CCCode)); NewLHS = Res; NewRHS = SDValue(); return; } NewLHS = TLI.SimplifySetCC(getSetCCResultType(HiVT), LHSHi, RHSHi, ISD::SETEQ, false, DagCombineInfo, dl); if (!NewLHS.getNode()) NewLHS = DAG.getSetCC(dl, getSetCCResultType(HiVT), LHSHi, RHSHi, ISD::SETEQ); NewLHS = DAG.getSelect(dl, LoCmp.getValueType(), NewLHS, LoCmp, HiCmp); NewRHS = SDValue(); } SDValue DAGTypeLegalizer::ExpandIntOp_BR_CC(SDNode *N) { SDValue NewLHS = N->getOperand(2), NewRHS = N->getOperand(3); ISD::CondCode CCCode = cast(N->getOperand(1))->get(); IntegerExpandSetCCOperands(NewLHS, NewRHS, CCCode, SDLoc(N)); // If ExpandSetCCOperands returned a scalar, we need to compare the result // against zero to select between true and false values. if (!NewRHS.getNode()) { NewRHS = DAG.getConstant(0, SDLoc(N), NewLHS.getValueType()); CCCode = ISD::SETNE; } // Update N to have the operands specified. return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), DAG.getCondCode(CCCode), NewLHS, NewRHS, N->getOperand(4)), 0); } SDValue DAGTypeLegalizer::ExpandIntOp_SELECT_CC(SDNode *N) { SDValue NewLHS = N->getOperand(0), NewRHS = N->getOperand(1); ISD::CondCode CCCode = cast(N->getOperand(4))->get(); IntegerExpandSetCCOperands(NewLHS, NewRHS, CCCode, SDLoc(N)); // If ExpandSetCCOperands returned a scalar, we need to compare the result // against zero to select between true and false values. if (!NewRHS.getNode()) { NewRHS = DAG.getConstant(0, SDLoc(N), NewLHS.getValueType()); CCCode = ISD::SETNE; } // Update N to have the operands specified. return SDValue(DAG.UpdateNodeOperands(N, NewLHS, NewRHS, N->getOperand(2), N->getOperand(3), DAG.getCondCode(CCCode)), 0); } SDValue DAGTypeLegalizer::ExpandIntOp_SETCC(SDNode *N) { SDValue NewLHS = N->getOperand(0), NewRHS = N->getOperand(1); ISD::CondCode CCCode = cast(N->getOperand(2))->get(); IntegerExpandSetCCOperands(NewLHS, NewRHS, CCCode, SDLoc(N)); // If ExpandSetCCOperands returned a scalar, use it. if (!NewRHS.getNode()) { assert(NewLHS.getValueType() == N->getValueType(0) && "Unexpected setcc expansion!"); return NewLHS; } // Otherwise, update N to have the operands specified. return SDValue( DAG.UpdateNodeOperands(N, NewLHS, NewRHS, DAG.getCondCode(CCCode)), 0); } SDValue DAGTypeLegalizer::ExpandIntOp_SETCCCARRY(SDNode *N) { SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); SDValue Carry = N->getOperand(2); SDValue Cond = N->getOperand(3); SDLoc dl = SDLoc(N); SDValue LHSLo, LHSHi, RHSLo, RHSHi; GetExpandedInteger(LHS, LHSLo, LHSHi); GetExpandedInteger(RHS, RHSLo, RHSHi); // Expand to a SUBE for the low part and a smaller SETCCCARRY for the high. SDVTList VTList = DAG.getVTList(LHSLo.getValueType(), Carry.getValueType()); SDValue LowCmp = DAG.getNode(ISD::SUBCARRY, dl, VTList, LHSLo, RHSLo, Carry); return DAG.getNode(ISD::SETCCCARRY, dl, N->getValueType(0), LHSHi, RHSHi, LowCmp.getValue(1), Cond); } SDValue DAGTypeLegalizer::ExpandIntOp_Shift(SDNode *N) { // The value being shifted is legal, but the shift amount is too big. // It follows that either the result of the shift is undefined, or the // upper half of the shift amount is zero. Just use the lower half. SDValue Lo, Hi; GetExpandedInteger(N->getOperand(1), Lo, Hi); return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), Lo), 0); } SDValue DAGTypeLegalizer::ExpandIntOp_RETURNADDR(SDNode *N) { // The argument of RETURNADDR / FRAMEADDR builtin is 32 bit contant. This // surely makes pretty nice problems on 8/16 bit targets. Just truncate this // constant to valid type. SDValue Lo, Hi; GetExpandedInteger(N->getOperand(0), Lo, Hi); return SDValue(DAG.UpdateNodeOperands(N, Lo), 0); } SDValue DAGTypeLegalizer::ExpandIntOp_SINT_TO_FP(SDNode *N) { bool IsStrict = N->isStrictFPOpcode(); SDValue Chain = IsStrict ? N->getOperand(0) : SDValue(); SDValue Op = N->getOperand(IsStrict ? 1 : 0); EVT DstVT = N->getValueType(0); RTLIB::Libcall LC = RTLIB::getSINTTOFP(Op.getValueType(), DstVT); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Don't know how to expand this SINT_TO_FP!"); TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(true); std::pair Tmp = TLI.makeLibCall(DAG, LC, DstVT, Op, CallOptions, SDLoc(N), Chain); if (!IsStrict) return Tmp.first; ReplaceValueWith(SDValue(N, 1), Tmp.second); ReplaceValueWith(SDValue(N, 0), Tmp.first); return SDValue(); } SDValue DAGTypeLegalizer::ExpandIntOp_STORE(StoreSDNode *N, unsigned OpNo) { if (N->isAtomic()) { // It's typical to have larger CAS than atomic store instructions. SDLoc dl(N); SDValue Swap = DAG.getAtomic(ISD::ATOMIC_SWAP, dl, N->getMemoryVT(), N->getOperand(0), N->getOperand(2), N->getOperand(1), N->getMemOperand()); return Swap.getValue(1); } if (ISD::isNormalStore(N)) return ExpandOp_NormalStore(N, OpNo); assert(ISD::isUNINDEXEDStore(N) && "Indexed store during type legalization!"); assert(OpNo == 1 && "Can only expand the stored value so far"); EVT VT = N->getOperand(1).getValueType(); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); SDValue Ch = N->getChain(); SDValue Ptr = N->getBasePtr(); unsigned Alignment = N->getAlignment(); MachineMemOperand::Flags MMOFlags = N->getMemOperand()->getFlags(); AAMDNodes AAInfo = N->getAAInfo(); SDLoc dl(N); SDValue Lo, Hi; assert(NVT.isByteSized() && "Expanded type not byte sized!"); if (N->getMemoryVT().bitsLE(NVT)) { GetExpandedInteger(N->getValue(), Lo, Hi); return DAG.getTruncStore(Ch, dl, Lo, Ptr, N->getPointerInfo(), N->getMemoryVT(), Alignment, MMOFlags, AAInfo); } if (DAG.getDataLayout().isLittleEndian()) { // Little-endian - low bits are at low addresses. GetExpandedInteger(N->getValue(), Lo, Hi); Lo = DAG.getStore(Ch, dl, Lo, Ptr, N->getPointerInfo(), Alignment, MMOFlags, AAInfo); unsigned ExcessBits = N->getMemoryVT().getSizeInBits() - NVT.getSizeInBits(); EVT NEVT = EVT::getIntegerVT(*DAG.getContext(), ExcessBits); // Increment the pointer to the other half. unsigned IncrementSize = NVT.getSizeInBits()/8; Ptr = DAG.getObjectPtrOffset(dl, Ptr, IncrementSize); Hi = DAG.getTruncStore( Ch, dl, Hi, Ptr, N->getPointerInfo().getWithOffset(IncrementSize), NEVT, MinAlign(Alignment, IncrementSize), MMOFlags, AAInfo); return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); } // Big-endian - high bits are at low addresses. Favor aligned stores at // the cost of some bit-fiddling. GetExpandedInteger(N->getValue(), Lo, Hi); EVT ExtVT = N->getMemoryVT(); unsigned EBytes = ExtVT.getStoreSize(); unsigned IncrementSize = NVT.getSizeInBits()/8; unsigned ExcessBits = (EBytes - IncrementSize)*8; EVT HiVT = EVT::getIntegerVT(*DAG.getContext(), ExtVT.getSizeInBits() - ExcessBits); if (ExcessBits < NVT.getSizeInBits()) { // Transfer high bits from the top of Lo to the bottom of Hi. Hi = DAG.getNode(ISD::SHL, dl, NVT, Hi, DAG.getConstant(NVT.getSizeInBits() - ExcessBits, dl, TLI.getPointerTy(DAG.getDataLayout()))); Hi = DAG.getNode( ISD::OR, dl, NVT, Hi, DAG.getNode(ISD::SRL, dl, NVT, Lo, DAG.getConstant(ExcessBits, dl, TLI.getPointerTy(DAG.getDataLayout())))); } // Store both the high bits and maybe some of the low bits. Hi = DAG.getTruncStore(Ch, dl, Hi, Ptr, N->getPointerInfo(), HiVT, Alignment, MMOFlags, AAInfo); // Increment the pointer to the other half. Ptr = DAG.getObjectPtrOffset(dl, Ptr, IncrementSize); // Store the lowest ExcessBits bits in the second half. Lo = DAG.getTruncStore(Ch, dl, Lo, Ptr, N->getPointerInfo().getWithOffset(IncrementSize), EVT::getIntegerVT(*DAG.getContext(), ExcessBits), MinAlign(Alignment, IncrementSize), MMOFlags, AAInfo); return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); } SDValue DAGTypeLegalizer::ExpandIntOp_TRUNCATE(SDNode *N) { SDValue InL, InH; GetExpandedInteger(N->getOperand(0), InL, InH); // Just truncate the low part of the source. return DAG.getNode(ISD::TRUNCATE, SDLoc(N), N->getValueType(0), InL); } SDValue DAGTypeLegalizer::ExpandIntOp_UINT_TO_FP(SDNode *N) { bool IsStrict = N->isStrictFPOpcode(); SDValue Chain = IsStrict ? N->getOperand(0) : SDValue(); SDValue Op = N->getOperand(IsStrict ? 1 : 0); EVT DstVT = N->getValueType(0); RTLIB::Libcall LC = RTLIB::getUINTTOFP(Op.getValueType(), DstVT); assert(LC != RTLIB::UNKNOWN_LIBCALL && "Don't know how to expand this UINT_TO_FP!"); TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(true); std::pair Tmp = TLI.makeLibCall(DAG, LC, DstVT, Op, CallOptions, SDLoc(N), Chain); if (!IsStrict) return Tmp.first; ReplaceValueWith(SDValue(N, 1), Tmp.second); ReplaceValueWith(SDValue(N, 0), Tmp.first); return SDValue(); } SDValue DAGTypeLegalizer::ExpandIntOp_ATOMIC_STORE(SDNode *N) { SDLoc dl(N); SDValue Swap = DAG.getAtomic(ISD::ATOMIC_SWAP, dl, cast(N)->getMemoryVT(), N->getOperand(0), N->getOperand(1), N->getOperand(2), cast(N)->getMemOperand()); return Swap.getValue(1); } SDValue DAGTypeLegalizer::PromoteIntRes_EXTRACT_SUBVECTOR(SDNode *N) { EVT OutVT = N->getValueType(0); EVT NOutVT = TLI.getTypeToTransformTo(*DAG.getContext(), OutVT); assert(NOutVT.isVector() && "This type must be promoted to a vector type"); unsigned OutNumElems = OutVT.getVectorNumElements(); EVT NOutVTElem = NOutVT.getVectorElementType(); SDLoc dl(N); SDValue BaseIdx = N->getOperand(1); SDValue InOp0 = N->getOperand(0); if (getTypeAction(InOp0.getValueType()) == TargetLowering::TypePromoteInteger) InOp0 = GetPromotedInteger(N->getOperand(0)); EVT InVT = InOp0.getValueType(); SmallVector Ops; Ops.reserve(OutNumElems); for (unsigned i = 0; i != OutNumElems; ++i) { // Extract the element from the original vector. SDValue Index = DAG.getNode(ISD::ADD, dl, BaseIdx.getValueType(), BaseIdx, DAG.getConstant(i, dl, BaseIdx.getValueType())); SDValue Ext = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, InVT.getVectorElementType(), N->getOperand(0), Index); SDValue Op = DAG.getAnyExtOrTrunc(Ext, dl, NOutVTElem); // Insert the converted element to the new vector. Ops.push_back(Op); } return DAG.getBuildVector(NOutVT, dl, Ops); } SDValue DAGTypeLegalizer::PromoteIntRes_VECTOR_SHUFFLE(SDNode *N) { ShuffleVectorSDNode *SV = cast(N); EVT VT = N->getValueType(0); SDLoc dl(N); ArrayRef NewMask = SV->getMask().slice(0, VT.getVectorNumElements()); SDValue V0 = GetPromotedInteger(N->getOperand(0)); SDValue V1 = GetPromotedInteger(N->getOperand(1)); EVT OutVT = V0.getValueType(); return DAG.getVectorShuffle(OutVT, dl, V0, V1, NewMask); } SDValue DAGTypeLegalizer::PromoteIntRes_BUILD_VECTOR(SDNode *N) { EVT OutVT = N->getValueType(0); EVT NOutVT = TLI.getTypeToTransformTo(*DAG.getContext(), OutVT); assert(NOutVT.isVector() && "This type must be promoted to a vector type"); unsigned NumElems = N->getNumOperands(); EVT NOutVTElem = NOutVT.getVectorElementType(); SDLoc dl(N); SmallVector Ops; Ops.reserve(NumElems); for (unsigned i = 0; i != NumElems; ++i) { SDValue Op; // BUILD_VECTOR integer operand types are allowed to be larger than the // result's element type. This may still be true after the promotion. For // example, we might be promoting ( = BV , , ...) to // (v?i16 = BV , , ...), and we can't any_extend to . if (N->getOperand(i).getValueType().bitsLT(NOutVTElem)) Op = DAG.getNode(ISD::ANY_EXTEND, dl, NOutVTElem, N->getOperand(i)); else Op = N->getOperand(i); Ops.push_back(Op); } return DAG.getBuildVector(NOutVT, dl, Ops); } SDValue DAGTypeLegalizer::PromoteIntRes_SCALAR_TO_VECTOR(SDNode *N) { SDLoc dl(N); assert(!N->getOperand(0).getValueType().isVector() && "Input must be a scalar"); EVT OutVT = N->getValueType(0); EVT NOutVT = TLI.getTypeToTransformTo(*DAG.getContext(), OutVT); assert(NOutVT.isVector() && "This type must be promoted to a vector type"); EVT NOutVTElem = NOutVT.getVectorElementType(); SDValue Op = DAG.getNode(ISD::ANY_EXTEND, dl, NOutVTElem, N->getOperand(0)); return DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, NOutVT, Op); } SDValue DAGTypeLegalizer::PromoteIntRes_SPLAT_VECTOR(SDNode *N) { SDLoc dl(N); SDValue SplatVal = N->getOperand(0); assert(!SplatVal.getValueType().isVector() && "Input must be a scalar"); EVT OutVT = N->getValueType(0); EVT NOutVT = TLI.getTypeToTransformTo(*DAG.getContext(), OutVT); assert(NOutVT.isVector() && "Type must be promoted to a vector type"); EVT NOutElemVT = NOutVT.getVectorElementType(); SDValue Op = DAG.getNode(ISD::ANY_EXTEND, dl, NOutElemVT, SplatVal); return DAG.getNode(ISD::SPLAT_VECTOR, dl, NOutVT, Op); } SDValue DAGTypeLegalizer::PromoteIntRes_CONCAT_VECTORS(SDNode *N) { SDLoc dl(N); EVT OutVT = N->getValueType(0); EVT NOutVT = TLI.getTypeToTransformTo(*DAG.getContext(), OutVT); assert(NOutVT.isVector() && "This type must be promoted to a vector type"); EVT OutElemTy = NOutVT.getVectorElementType(); unsigned NumElem = N->getOperand(0).getValueType().getVectorNumElements(); unsigned NumOutElem = NOutVT.getVectorNumElements(); unsigned NumOperands = N->getNumOperands(); assert(NumElem * NumOperands == NumOutElem && "Unexpected number of elements"); // Take the elements from the first vector. SmallVector Ops(NumOutElem); for (unsigned i = 0; i < NumOperands; ++i) { SDValue Op = N->getOperand(i); if (getTypeAction(Op.getValueType()) == TargetLowering::TypePromoteInteger) Op = GetPromotedInteger(Op); EVT SclrTy = Op.getValueType().getVectorElementType(); assert(NumElem == Op.getValueType().getVectorNumElements() && "Unexpected number of elements"); for (unsigned j = 0; j < NumElem; ++j) { SDValue Ext = DAG.getNode( ISD::EXTRACT_VECTOR_ELT, dl, SclrTy, Op, DAG.getConstant(j, dl, TLI.getVectorIdxTy(DAG.getDataLayout()))); Ops[i * NumElem + j] = DAG.getAnyExtOrTrunc(Ext, dl, OutElemTy); } } return DAG.getBuildVector(NOutVT, dl, Ops); } SDValue DAGTypeLegalizer::PromoteIntRes_EXTEND_VECTOR_INREG(SDNode *N) { EVT VT = N->getValueType(0); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); assert(NVT.isVector() && "This type must be promoted to a vector type"); SDLoc dl(N); // For operands whose TypeAction is to promote, extend the promoted node // appropriately (ZERO_EXTEND or SIGN_EXTEND) from the original pre-promotion // type, and then construct a new *_EXTEND_VECTOR_INREG node to the promote-to // type.. if (getTypeAction(N->getOperand(0).getValueType()) == TargetLowering::TypePromoteInteger) { SDValue Promoted; switch(N->getOpcode()) { case ISD::SIGN_EXTEND_VECTOR_INREG: Promoted = SExtPromotedInteger(N->getOperand(0)); break; case ISD::ZERO_EXTEND_VECTOR_INREG: Promoted = ZExtPromotedInteger(N->getOperand(0)); break; case ISD::ANY_EXTEND_VECTOR_INREG: Promoted = GetPromotedInteger(N->getOperand(0)); break; default: llvm_unreachable("Node has unexpected Opcode"); } return DAG.getNode(N->getOpcode(), dl, NVT, Promoted); } // Directly extend to the appropriate transform-to type. return DAG.getNode(N->getOpcode(), dl, NVT, N->getOperand(0)); } SDValue DAGTypeLegalizer::PromoteIntRes_INSERT_VECTOR_ELT(SDNode *N) { EVT OutVT = N->getValueType(0); EVT NOutVT = TLI.getTypeToTransformTo(*DAG.getContext(), OutVT); assert(NOutVT.isVector() && "This type must be promoted to a vector type"); EVT NOutVTElem = NOutVT.getVectorElementType(); SDLoc dl(N); SDValue V0 = GetPromotedInteger(N->getOperand(0)); SDValue ConvElem = DAG.getNode(ISD::ANY_EXTEND, dl, NOutVTElem, N->getOperand(1)); return DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, NOutVT, V0, ConvElem, N->getOperand(2)); } SDValue DAGTypeLegalizer::PromoteIntRes_VECREDUCE(SDNode *N) { // The VECREDUCE result size may be larger than the element size, so // we can simply change the result type. SDLoc dl(N); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); return DAG.getNode(N->getOpcode(), dl, NVT, N->getOperand(0)); } SDValue DAGTypeLegalizer::PromoteIntOp_EXTRACT_VECTOR_ELT(SDNode *N) { SDLoc dl(N); SDValue V0 = GetPromotedInteger(N->getOperand(0)); SDValue V1 = DAG.getZExtOrTrunc(N->getOperand(1), dl, TLI.getVectorIdxTy(DAG.getDataLayout())); SDValue Ext = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, V0->getValueType(0).getScalarType(), V0, V1); // EXTRACT_VECTOR_ELT can return types which are wider than the incoming // element types. If this is the case then we need to expand the outgoing // value and not truncate it. return DAG.getAnyExtOrTrunc(Ext, dl, N->getValueType(0)); } SDValue DAGTypeLegalizer::PromoteIntOp_EXTRACT_SUBVECTOR(SDNode *N) { SDLoc dl(N); SDValue V0 = GetPromotedInteger(N->getOperand(0)); MVT InVT = V0.getValueType().getSimpleVT(); MVT OutVT = MVT::getVectorVT(InVT.getVectorElementType(), N->getValueType(0).getVectorNumElements()); SDValue Ext = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, OutVT, V0, N->getOperand(1)); return DAG.getNode(ISD::TRUNCATE, dl, N->getValueType(0), Ext); } SDValue DAGTypeLegalizer::PromoteIntOp_CONCAT_VECTORS(SDNode *N) { SDLoc dl(N); unsigned NumElems = N->getNumOperands(); EVT RetSclrTy = N->getValueType(0).getVectorElementType(); SmallVector NewOps; NewOps.reserve(NumElems); // For each incoming vector for (unsigned VecIdx = 0; VecIdx != NumElems; ++VecIdx) { SDValue Incoming = GetPromotedInteger(N->getOperand(VecIdx)); EVT SclrTy = Incoming->getValueType(0).getVectorElementType(); unsigned NumElem = Incoming->getValueType(0).getVectorNumElements(); for (unsigned i=0; igetValueType(0), dl, NewOps); } Index: head/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- head/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp (revision 362718) +++ head/contrib/llvm-project/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp (revision 362719) @@ -1,7661 +1,7665 @@ //===-- TargetLowering.cpp - Implement the TargetLowering class -----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This implements the TargetLowering class. // //===----------------------------------------------------------------------===// #include "llvm/CodeGen/TargetLowering.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/LLVMContext.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/MathExtras.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include using namespace llvm; /// NOTE: The TargetMachine owns TLOF. TargetLowering::TargetLowering(const TargetMachine &tm) : TargetLoweringBase(tm) {} const char *TargetLowering::getTargetNodeName(unsigned Opcode) const { return nullptr; } bool TargetLowering::isPositionIndependent() const { return getTargetMachine().isPositionIndependent(); } /// Check whether a given call node is in tail position within its function. If /// so, it sets Chain to the input chain of the tail call. bool TargetLowering::isInTailCallPosition(SelectionDAG &DAG, SDNode *Node, SDValue &Chain) const { const Function &F = DAG.getMachineFunction().getFunction(); // First, check if tail calls have been disabled in this function. if (F.getFnAttribute("disable-tail-calls").getValueAsString() == "true") return false; // Conservatively require the attributes of the call to match those of // the return. Ignore NoAlias and NonNull because they don't affect the // call sequence. AttributeList CallerAttrs = F.getAttributes(); if (AttrBuilder(CallerAttrs, AttributeList::ReturnIndex) .removeAttribute(Attribute::NoAlias) .removeAttribute(Attribute::NonNull) .hasAttributes()) return false; // It's not safe to eliminate the sign / zero extension of the return value. if (CallerAttrs.hasAttribute(AttributeList::ReturnIndex, Attribute::ZExt) || CallerAttrs.hasAttribute(AttributeList::ReturnIndex, Attribute::SExt)) return false; // Check if the only use is a function return node. return isUsedByReturnOnly(Node, Chain); } bool TargetLowering::parametersInCSRMatch(const MachineRegisterInfo &MRI, const uint32_t *CallerPreservedMask, const SmallVectorImpl &ArgLocs, const SmallVectorImpl &OutVals) const { for (unsigned I = 0, E = ArgLocs.size(); I != E; ++I) { const CCValAssign &ArgLoc = ArgLocs[I]; if (!ArgLoc.isRegLoc()) continue; Register Reg = ArgLoc.getLocReg(); // Only look at callee saved registers. if (MachineOperand::clobbersPhysReg(CallerPreservedMask, Reg)) continue; // Check that we pass the value used for the caller. // (We look for a CopyFromReg reading a virtual register that is used // for the function live-in value of register Reg) SDValue Value = OutVals[I]; if (Value->getOpcode() != ISD::CopyFromReg) return false; unsigned ArgReg = cast(Value->getOperand(1))->getReg(); if (MRI.getLiveInPhysReg(ArgReg) != Reg) return false; } return true; } /// Set CallLoweringInfo attribute flags based on a call instruction /// and called function attributes. void TargetLoweringBase::ArgListEntry::setAttributes(const CallBase *Call, unsigned ArgIdx) { IsSExt = Call->paramHasAttr(ArgIdx, Attribute::SExt); IsZExt = Call->paramHasAttr(ArgIdx, Attribute::ZExt); IsInReg = Call->paramHasAttr(ArgIdx, Attribute::InReg); IsSRet = Call->paramHasAttr(ArgIdx, Attribute::StructRet); IsNest = Call->paramHasAttr(ArgIdx, Attribute::Nest); IsByVal = Call->paramHasAttr(ArgIdx, Attribute::ByVal); IsInAlloca = Call->paramHasAttr(ArgIdx, Attribute::InAlloca); IsReturned = Call->paramHasAttr(ArgIdx, Attribute::Returned); IsSwiftSelf = Call->paramHasAttr(ArgIdx, Attribute::SwiftSelf); IsSwiftError = Call->paramHasAttr(ArgIdx, Attribute::SwiftError); Alignment = Call->getParamAlignment(ArgIdx); ByValType = nullptr; if (Call->paramHasAttr(ArgIdx, Attribute::ByVal)) ByValType = Call->getParamByValType(ArgIdx); } /// Generate a libcall taking the given operands as arguments and returning a /// result of type RetVT. std::pair TargetLowering::makeLibCall(SelectionDAG &DAG, RTLIB::Libcall LC, EVT RetVT, ArrayRef Ops, MakeLibCallOptions CallOptions, const SDLoc &dl, SDValue InChain) const { if (!InChain) InChain = DAG.getEntryNode(); TargetLowering::ArgListTy Args; Args.reserve(Ops.size()); TargetLowering::ArgListEntry Entry; for (unsigned i = 0; i < Ops.size(); ++i) { SDValue NewOp = Ops[i]; Entry.Node = NewOp; Entry.Ty = Entry.Node.getValueType().getTypeForEVT(*DAG.getContext()); Entry.IsSExt = shouldSignExtendTypeInLibCall(NewOp.getValueType(), CallOptions.IsSExt); Entry.IsZExt = !Entry.IsSExt; if (CallOptions.IsSoften && !shouldExtendTypeInLibCall(CallOptions.OpsVTBeforeSoften[i])) { Entry.IsSExt = Entry.IsZExt = false; } Args.push_back(Entry); } if (LC == RTLIB::UNKNOWN_LIBCALL) report_fatal_error("Unsupported library call operation!"); SDValue Callee = DAG.getExternalSymbol(getLibcallName(LC), getPointerTy(DAG.getDataLayout())); Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); TargetLowering::CallLoweringInfo CLI(DAG); bool signExtend = shouldSignExtendTypeInLibCall(RetVT, CallOptions.IsSExt); bool zeroExtend = !signExtend; if (CallOptions.IsSoften && !shouldExtendTypeInLibCall(CallOptions.RetVTBeforeSoften)) { signExtend = zeroExtend = false; } CLI.setDebugLoc(dl) .setChain(InChain) .setLibCallee(getLibcallCallingConv(LC), RetTy, Callee, std::move(Args)) .setNoReturn(CallOptions.DoesNotReturn) .setDiscardResult(!CallOptions.IsReturnValueUsed) .setIsPostTypeLegalization(CallOptions.IsPostTypeLegalization) .setSExtResult(signExtend) .setZExtResult(zeroExtend); return LowerCallTo(CLI); } bool TargetLowering::findOptimalMemOpLowering(std::vector &MemOps, unsigned Limit, uint64_t Size, unsigned DstAlign, unsigned SrcAlign, bool IsMemset, bool ZeroMemset, bool MemcpyStrSrc, bool AllowOverlap, unsigned DstAS, unsigned SrcAS, const AttributeList &FuncAttributes) const { // If 'SrcAlign' is zero, that means the memory operation does not need to // load the value, i.e. memset or memcpy from constant string. Otherwise, // it's the inferred alignment of the source. 'DstAlign', on the other hand, // is the specified alignment of the memory operation. If it is zero, that // means it's possible to change the alignment of the destination. // 'MemcpyStrSrc' indicates whether the memcpy source is constant so it does // not need to be loaded. if (!(SrcAlign == 0 || SrcAlign >= DstAlign)) return false; EVT VT = getOptimalMemOpType(Size, DstAlign, SrcAlign, IsMemset, ZeroMemset, MemcpyStrSrc, FuncAttributes); if (VT == MVT::Other) { // Use the largest integer type whose alignment constraints are satisfied. // We only need to check DstAlign here as SrcAlign is always greater or // equal to DstAlign (or zero). VT = MVT::i64; while (DstAlign && DstAlign < VT.getSizeInBits() / 8 && !allowsMisalignedMemoryAccesses(VT, DstAS, DstAlign)) VT = (MVT::SimpleValueType)(VT.getSimpleVT().SimpleTy - 1); assert(VT.isInteger()); // Find the largest legal integer type. MVT LVT = MVT::i64; while (!isTypeLegal(LVT)) LVT = (MVT::SimpleValueType)(LVT.SimpleTy - 1); assert(LVT.isInteger()); // If the type we've chosen is larger than the largest legal integer type // then use that instead. if (VT.bitsGT(LVT)) VT = LVT; } unsigned NumMemOps = 0; while (Size != 0) { unsigned VTSize = VT.getSizeInBits() / 8; while (VTSize > Size) { // For now, only use non-vector load / store's for the left-over pieces. EVT NewVT = VT; unsigned NewVTSize; bool Found = false; if (VT.isVector() || VT.isFloatingPoint()) { NewVT = (VT.getSizeInBits() > 64) ? MVT::i64 : MVT::i32; if (isOperationLegalOrCustom(ISD::STORE, NewVT) && isSafeMemOpType(NewVT.getSimpleVT())) Found = true; else if (NewVT == MVT::i64 && isOperationLegalOrCustom(ISD::STORE, MVT::f64) && isSafeMemOpType(MVT::f64)) { // i64 is usually not legal on 32-bit targets, but f64 may be. NewVT = MVT::f64; Found = true; } } if (!Found) { do { NewVT = (MVT::SimpleValueType)(NewVT.getSimpleVT().SimpleTy - 1); if (NewVT == MVT::i8) break; } while (!isSafeMemOpType(NewVT.getSimpleVT())); } NewVTSize = NewVT.getSizeInBits() / 8; // If the new VT cannot cover all of the remaining bits, then consider // issuing a (or a pair of) unaligned and overlapping load / store. bool Fast; if (NumMemOps && AllowOverlap && NewVTSize < Size && allowsMisalignedMemoryAccesses(VT, DstAS, DstAlign, MachineMemOperand::MONone, &Fast) && Fast) VTSize = Size; else { VT = NewVT; VTSize = NewVTSize; } } if (++NumMemOps > Limit) return false; MemOps.push_back(VT); Size -= VTSize; } return true; } /// Soften the operands of a comparison. This code is shared among BR_CC, /// SELECT_CC, and SETCC handlers. void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT, SDValue &NewLHS, SDValue &NewRHS, ISD::CondCode &CCCode, const SDLoc &dl, const SDValue OldLHS, const SDValue OldRHS) const { SDValue Chain; return softenSetCCOperands(DAG, VT, NewLHS, NewRHS, CCCode, dl, OldLHS, OldRHS, Chain); } void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT, SDValue &NewLHS, SDValue &NewRHS, ISD::CondCode &CCCode, const SDLoc &dl, const SDValue OldLHS, const SDValue OldRHS, SDValue &Chain, bool IsSignaling) const { // FIXME: Currently we cannot really respect all IEEE predicates due to libgcc // not supporting it. We can update this code when libgcc provides such // functions. assert((VT == MVT::f32 || VT == MVT::f64 || VT == MVT::f128 || VT == MVT::ppcf128) && "Unsupported setcc type!"); // Expand into one or more soft-fp libcall(s). RTLIB::Libcall LC1 = RTLIB::UNKNOWN_LIBCALL, LC2 = RTLIB::UNKNOWN_LIBCALL; bool ShouldInvertCC = false; switch (CCCode) { case ISD::SETEQ: case ISD::SETOEQ: LC1 = (VT == MVT::f32) ? RTLIB::OEQ_F32 : (VT == MVT::f64) ? RTLIB::OEQ_F64 : (VT == MVT::f128) ? RTLIB::OEQ_F128 : RTLIB::OEQ_PPCF128; break; case ISD::SETNE: case ISD::SETUNE: LC1 = (VT == MVT::f32) ? RTLIB::UNE_F32 : (VT == MVT::f64) ? RTLIB::UNE_F64 : (VT == MVT::f128) ? RTLIB::UNE_F128 : RTLIB::UNE_PPCF128; break; case ISD::SETGE: case ISD::SETOGE: LC1 = (VT == MVT::f32) ? RTLIB::OGE_F32 : (VT == MVT::f64) ? RTLIB::OGE_F64 : (VT == MVT::f128) ? RTLIB::OGE_F128 : RTLIB::OGE_PPCF128; break; case ISD::SETLT: case ISD::SETOLT: LC1 = (VT == MVT::f32) ? RTLIB::OLT_F32 : (VT == MVT::f64) ? RTLIB::OLT_F64 : (VT == MVT::f128) ? RTLIB::OLT_F128 : RTLIB::OLT_PPCF128; break; case ISD::SETLE: case ISD::SETOLE: LC1 = (VT == MVT::f32) ? RTLIB::OLE_F32 : (VT == MVT::f64) ? RTLIB::OLE_F64 : (VT == MVT::f128) ? RTLIB::OLE_F128 : RTLIB::OLE_PPCF128; break; case ISD::SETGT: case ISD::SETOGT: LC1 = (VT == MVT::f32) ? RTLIB::OGT_F32 : (VT == MVT::f64) ? RTLIB::OGT_F64 : (VT == MVT::f128) ? RTLIB::OGT_F128 : RTLIB::OGT_PPCF128; break; case ISD::SETO: ShouldInvertCC = true; LLVM_FALLTHROUGH; case ISD::SETUO: LC1 = (VT == MVT::f32) ? RTLIB::UO_F32 : (VT == MVT::f64) ? RTLIB::UO_F64 : (VT == MVT::f128) ? RTLIB::UO_F128 : RTLIB::UO_PPCF128; break; case ISD::SETONE: // SETONE = O && UNE ShouldInvertCC = true; LLVM_FALLTHROUGH; case ISD::SETUEQ: LC1 = (VT == MVT::f32) ? RTLIB::UO_F32 : (VT == MVT::f64) ? RTLIB::UO_F64 : (VT == MVT::f128) ? RTLIB::UO_F128 : RTLIB::UO_PPCF128; LC2 = (VT == MVT::f32) ? RTLIB::OEQ_F32 : (VT == MVT::f64) ? RTLIB::OEQ_F64 : (VT == MVT::f128) ? RTLIB::OEQ_F128 : RTLIB::OEQ_PPCF128; break; default: // Invert CC for unordered comparisons ShouldInvertCC = true; switch (CCCode) { case ISD::SETULT: LC1 = (VT == MVT::f32) ? RTLIB::OGE_F32 : (VT == MVT::f64) ? RTLIB::OGE_F64 : (VT == MVT::f128) ? RTLIB::OGE_F128 : RTLIB::OGE_PPCF128; break; case ISD::SETULE: LC1 = (VT == MVT::f32) ? RTLIB::OGT_F32 : (VT == MVT::f64) ? RTLIB::OGT_F64 : (VT == MVT::f128) ? RTLIB::OGT_F128 : RTLIB::OGT_PPCF128; break; case ISD::SETUGT: LC1 = (VT == MVT::f32) ? RTLIB::OLE_F32 : (VT == MVT::f64) ? RTLIB::OLE_F64 : (VT == MVT::f128) ? RTLIB::OLE_F128 : RTLIB::OLE_PPCF128; break; case ISD::SETUGE: LC1 = (VT == MVT::f32) ? RTLIB::OLT_F32 : (VT == MVT::f64) ? RTLIB::OLT_F64 : (VT == MVT::f128) ? RTLIB::OLT_F128 : RTLIB::OLT_PPCF128; break; default: llvm_unreachable("Do not know how to soften this setcc!"); } } // Use the target specific return value for comparions lib calls. EVT RetVT = getCmpLibcallReturnType(); SDValue Ops[2] = {NewLHS, NewRHS}; TargetLowering::MakeLibCallOptions CallOptions; EVT OpsVT[2] = { OldLHS.getValueType(), OldRHS.getValueType() }; CallOptions.setTypeListBeforeSoften(OpsVT, RetVT, true); auto Call = makeLibCall(DAG, LC1, RetVT, Ops, CallOptions, dl, Chain); NewLHS = Call.first; NewRHS = DAG.getConstant(0, dl, RetVT); CCCode = getCmpLibcallCC(LC1); if (ShouldInvertCC) { assert(RetVT.isInteger()); CCCode = getSetCCInverse(CCCode, RetVT); } if (LC2 == RTLIB::UNKNOWN_LIBCALL) { // Update Chain. Chain = Call.second; } else { EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), RetVT); SDValue Tmp = DAG.getSetCC(dl, SetCCVT, NewLHS, NewRHS, CCCode); auto Call2 = makeLibCall(DAG, LC2, RetVT, Ops, CallOptions, dl, Chain); CCCode = getCmpLibcallCC(LC2); if (ShouldInvertCC) CCCode = getSetCCInverse(CCCode, RetVT); NewLHS = DAG.getSetCC(dl, SetCCVT, Call2.first, NewRHS, CCCode); if (Chain) Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Call.second, Call2.second); NewLHS = DAG.getNode(ShouldInvertCC ? ISD::AND : ISD::OR, dl, Tmp.getValueType(), Tmp, NewLHS); NewRHS = SDValue(); } } /// Return the entry encoding for a jump table in the current function. The /// returned value is a member of the MachineJumpTableInfo::JTEntryKind enum. unsigned TargetLowering::getJumpTableEncoding() const { // In non-pic modes, just use the address of a block. if (!isPositionIndependent()) return MachineJumpTableInfo::EK_BlockAddress; // In PIC mode, if the target supports a GPRel32 directive, use it. if (getTargetMachine().getMCAsmInfo()->getGPRel32Directive() != nullptr) return MachineJumpTableInfo::EK_GPRel32BlockAddress; // Otherwise, use a label difference. return MachineJumpTableInfo::EK_LabelDifference32; } SDValue TargetLowering::getPICJumpTableRelocBase(SDValue Table, SelectionDAG &DAG) const { // If our PIC model is GP relative, use the global offset table as the base. unsigned JTEncoding = getJumpTableEncoding(); if ((JTEncoding == MachineJumpTableInfo::EK_GPRel64BlockAddress) || (JTEncoding == MachineJumpTableInfo::EK_GPRel32BlockAddress)) return DAG.getGLOBAL_OFFSET_TABLE(getPointerTy(DAG.getDataLayout())); return Table; } /// This returns the relocation base for the given PIC jumptable, the same as /// getPICJumpTableRelocBase, but as an MCExpr. const MCExpr * TargetLowering::getPICJumpTableRelocBaseExpr(const MachineFunction *MF, unsigned JTI,MCContext &Ctx) const{ // The normal PIC reloc base is the label at the start of the jump table. return MCSymbolRefExpr::create(MF->getJTISymbol(JTI, Ctx), Ctx); } bool TargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { const TargetMachine &TM = getTargetMachine(); const GlobalValue *GV = GA->getGlobal(); // If the address is not even local to this DSO we will have to load it from // a got and then add the offset. if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) return false; // If the code is position independent we will have to add a base register. if (isPositionIndependent()) return false; // Otherwise we can do it. return true; } //===----------------------------------------------------------------------===// // Optimization Methods //===----------------------------------------------------------------------===// /// If the specified instruction has a constant integer operand and there are /// bits set in that constant that are not demanded, then clear those bits and /// return true. bool TargetLowering::ShrinkDemandedConstant(SDValue Op, const APInt &Demanded, TargetLoweringOpt &TLO) const { SDLoc DL(Op); unsigned Opcode = Op.getOpcode(); // Do target-specific constant optimization. if (targetShrinkDemandedConstant(Op, Demanded, TLO)) return TLO.New.getNode(); // FIXME: ISD::SELECT, ISD::SELECT_CC switch (Opcode) { default: break; case ISD::XOR: case ISD::AND: case ISD::OR: { auto *Op1C = dyn_cast(Op.getOperand(1)); if (!Op1C) return false; // If this is a 'not' op, don't touch it because that's a canonical form. const APInt &C = Op1C->getAPIntValue(); if (Opcode == ISD::XOR && Demanded.isSubsetOf(C)) return false; if (!C.isSubsetOf(Demanded)) { EVT VT = Op.getValueType(); SDValue NewC = TLO.DAG.getConstant(Demanded & C, DL, VT); SDValue NewOp = TLO.DAG.getNode(Opcode, DL, VT, Op.getOperand(0), NewC); return TLO.CombineTo(Op, NewOp); } break; } } return false; } /// Convert x+y to (VT)((SmallVT)x+(SmallVT)y) if the casts are free. /// This uses isZExtFree and ZERO_EXTEND for the widening cast, but it could be /// generalized for targets with other types of implicit widening casts. bool TargetLowering::ShrinkDemandedOp(SDValue Op, unsigned BitWidth, const APInt &Demanded, TargetLoweringOpt &TLO) const { assert(Op.getNumOperands() == 2 && "ShrinkDemandedOp only supports binary operators!"); assert(Op.getNode()->getNumValues() == 1 && "ShrinkDemandedOp only supports nodes with one result!"); SelectionDAG &DAG = TLO.DAG; SDLoc dl(Op); // Early return, as this function cannot handle vector types. if (Op.getValueType().isVector()) return false; // Don't do this if the node has another user, which may require the // full value. if (!Op.getNode()->hasOneUse()) return false; // Search for the smallest integer type with free casts to and from // Op's type. For expedience, just check power-of-2 integer types. const TargetLowering &TLI = DAG.getTargetLoweringInfo(); unsigned DemandedSize = Demanded.getActiveBits(); unsigned SmallVTBits = DemandedSize; if (!isPowerOf2_32(SmallVTBits)) SmallVTBits = NextPowerOf2(SmallVTBits); for (; SmallVTBits < BitWidth; SmallVTBits = NextPowerOf2(SmallVTBits)) { EVT SmallVT = EVT::getIntegerVT(*DAG.getContext(), SmallVTBits); if (TLI.isTruncateFree(Op.getValueType(), SmallVT) && TLI.isZExtFree(SmallVT, Op.getValueType())) { // We found a type with free casts. SDValue X = DAG.getNode( Op.getOpcode(), dl, SmallVT, DAG.getNode(ISD::TRUNCATE, dl, SmallVT, Op.getOperand(0)), DAG.getNode(ISD::TRUNCATE, dl, SmallVT, Op.getOperand(1))); assert(DemandedSize <= SmallVTBits && "Narrowed below demanded bits?"); SDValue Z = DAG.getNode(ISD::ANY_EXTEND, dl, Op.getValueType(), X); return TLO.CombineTo(Op, Z); } } return false; } bool TargetLowering::SimplifyDemandedBits(SDValue Op, const APInt &DemandedBits, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; TargetLoweringOpt TLO(DAG, !DCI.isBeforeLegalize(), !DCI.isBeforeLegalizeOps()); KnownBits Known; bool Simplified = SimplifyDemandedBits(Op, DemandedBits, Known, TLO); if (Simplified) { DCI.AddToWorklist(Op.getNode()); DCI.CommitTargetLoweringOpt(TLO); } return Simplified; } bool TargetLowering::SimplifyDemandedBits(SDValue Op, const APInt &DemandedBits, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth, bool AssumeSingleUse) const { EVT VT = Op.getValueType(); APInt DemandedElts = VT.isVector() ? APInt::getAllOnesValue(VT.getVectorNumElements()) : APInt(1, 1); return SimplifyDemandedBits(Op, DemandedBits, DemandedElts, Known, TLO, Depth, AssumeSingleUse); } // TODO: Can we merge SelectionDAG::GetDemandedBits into this? // TODO: Under what circumstances can we create nodes? Constant folding? SDValue TargetLowering::SimplifyMultipleUseDemandedBits( SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, SelectionDAG &DAG, unsigned Depth) const { // Limit search depth. if (Depth >= SelectionDAG::MaxRecursionDepth) return SDValue(); // Ignore UNDEFs. if (Op.isUndef()) return SDValue(); // Not demanding any bits/elts from Op. if (DemandedBits == 0 || DemandedElts == 0) return DAG.getUNDEF(Op.getValueType()); unsigned NumElts = DemandedElts.getBitWidth(); KnownBits LHSKnown, RHSKnown; switch (Op.getOpcode()) { case ISD::BITCAST: { SDValue Src = peekThroughBitcasts(Op.getOperand(0)); EVT SrcVT = Src.getValueType(); EVT DstVT = Op.getValueType(); unsigned NumSrcEltBits = SrcVT.getScalarSizeInBits(); unsigned NumDstEltBits = DstVT.getScalarSizeInBits(); if (NumSrcEltBits == NumDstEltBits) if (SDValue V = SimplifyMultipleUseDemandedBits( Src, DemandedBits, DemandedElts, DAG, Depth + 1)) return DAG.getBitcast(DstVT, V); // TODO - bigendian once we have test coverage. if (SrcVT.isVector() && (NumDstEltBits % NumSrcEltBits) == 0 && DAG.getDataLayout().isLittleEndian()) { unsigned Scale = NumDstEltBits / NumSrcEltBits; unsigned NumSrcElts = SrcVT.getVectorNumElements(); APInt DemandedSrcBits = APInt::getNullValue(NumSrcEltBits); APInt DemandedSrcElts = APInt::getNullValue(NumSrcElts); for (unsigned i = 0; i != Scale; ++i) { unsigned Offset = i * NumSrcEltBits; APInt Sub = DemandedBits.extractBits(NumSrcEltBits, Offset); if (!Sub.isNullValue()) { DemandedSrcBits |= Sub; for (unsigned j = 0; j != NumElts; ++j) if (DemandedElts[j]) DemandedSrcElts.setBit((j * Scale) + i); } } if (SDValue V = SimplifyMultipleUseDemandedBits( Src, DemandedSrcBits, DemandedSrcElts, DAG, Depth + 1)) return DAG.getBitcast(DstVT, V); } // TODO - bigendian once we have test coverage. if ((NumSrcEltBits % NumDstEltBits) == 0 && DAG.getDataLayout().isLittleEndian()) { unsigned Scale = NumSrcEltBits / NumDstEltBits; unsigned NumSrcElts = SrcVT.isVector() ? SrcVT.getVectorNumElements() : 1; APInt DemandedSrcBits = APInt::getNullValue(NumSrcEltBits); APInt DemandedSrcElts = APInt::getNullValue(NumSrcElts); for (unsigned i = 0; i != NumElts; ++i) if (DemandedElts[i]) { unsigned Offset = (i % Scale) * NumDstEltBits; DemandedSrcBits.insertBits(DemandedBits, Offset); DemandedSrcElts.setBit(i / Scale); } if (SDValue V = SimplifyMultipleUseDemandedBits( Src, DemandedSrcBits, DemandedSrcElts, DAG, Depth + 1)) return DAG.getBitcast(DstVT, V); } break; } case ISD::AND: { LHSKnown = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); RHSKnown = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); // If all of the demanded bits are known 1 on one side, return the other. // These bits cannot contribute to the result of the 'and' in this // context. if (DemandedBits.isSubsetOf(LHSKnown.Zero | RHSKnown.One)) return Op.getOperand(0); if (DemandedBits.isSubsetOf(RHSKnown.Zero | LHSKnown.One)) return Op.getOperand(1); break; } case ISD::OR: { LHSKnown = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); RHSKnown = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); // If all of the demanded bits are known zero on one side, return the // other. These bits cannot contribute to the result of the 'or' in this // context. if (DemandedBits.isSubsetOf(LHSKnown.One | RHSKnown.Zero)) return Op.getOperand(0); if (DemandedBits.isSubsetOf(RHSKnown.One | LHSKnown.Zero)) return Op.getOperand(1); break; } case ISD::XOR: { LHSKnown = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); RHSKnown = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1); // If all of the demanded bits are known zero on one side, return the // other. if (DemandedBits.isSubsetOf(RHSKnown.Zero)) return Op.getOperand(0); if (DemandedBits.isSubsetOf(LHSKnown.Zero)) return Op.getOperand(1); break; } case ISD::SETCC: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); ISD::CondCode CC = cast(Op.getOperand(2))->get(); // If (1) we only need the sign-bit, (2) the setcc operands are the same // width as the setcc result, and (3) the result of a setcc conforms to 0 or // -1, we may be able to bypass the setcc. if (DemandedBits.isSignMask() && Op0.getScalarValueSizeInBits() == DemandedBits.getBitWidth() && getBooleanContents(Op0.getValueType()) == BooleanContent::ZeroOrNegativeOneBooleanContent) { // If we're testing X < 0, then this compare isn't needed - just use X! // FIXME: We're limiting to integer types here, but this should also work // if we don't care about FP signed-zero. The use of SETLT with FP means // that we don't care about NaNs. if (CC == ISD::SETLT && Op1.getValueType().isInteger() && (isNullConstant(Op1) || ISD::isBuildVectorAllZeros(Op1.getNode()))) return Op0; } break; } case ISD::SIGN_EXTEND_INREG: { // If none of the extended bits are demanded, eliminate the sextinreg. EVT ExVT = cast(Op.getOperand(1))->getVT(); if (DemandedBits.getActiveBits() <= ExVT.getScalarSizeInBits()) return Op.getOperand(0); break; } case ISD::INSERT_VECTOR_ELT: { // If we don't demand the inserted element, return the base vector. SDValue Vec = Op.getOperand(0); auto *CIdx = dyn_cast(Op.getOperand(2)); EVT VecVT = Vec.getValueType(); if (CIdx && CIdx->getAPIntValue().ult(VecVT.getVectorNumElements()) && !DemandedElts[CIdx->getZExtValue()]) return Vec; break; } case ISD::VECTOR_SHUFFLE: { ArrayRef ShuffleMask = cast(Op)->getMask(); // If all the demanded elts are from one operand and are inline, // then we can use the operand directly. bool AllUndef = true, IdentityLHS = true, IdentityRHS = true; for (unsigned i = 0; i != NumElts; ++i) { int M = ShuffleMask[i]; if (M < 0 || !DemandedElts[i]) continue; AllUndef = false; IdentityLHS &= (M == (int)i); IdentityRHS &= ((M - NumElts) == i); } if (AllUndef) return DAG.getUNDEF(Op.getValueType()); if (IdentityLHS) return Op.getOperand(0); if (IdentityRHS) return Op.getOperand(1); break; } default: if (Op.getOpcode() >= ISD::BUILTIN_OP_END) if (SDValue V = SimplifyMultipleUseDemandedBitsForTargetNode( Op, DemandedBits, DemandedElts, DAG, Depth)) return V; break; } return SDValue(); } /// Look at Op. At this point, we know that only the OriginalDemandedBits of the /// result of Op are ever used downstream. If we can use this information to /// simplify Op, create a new simplified DAG node and return true, returning the /// original and new nodes in Old and New. Otherwise, analyze the expression and /// return a mask of Known bits for the expression (used to simplify the /// caller). The Known bits may only be accurate for those bits in the /// OriginalDemandedBits and OriginalDemandedElts. bool TargetLowering::SimplifyDemandedBits( SDValue Op, const APInt &OriginalDemandedBits, const APInt &OriginalDemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth, bool AssumeSingleUse) const { unsigned BitWidth = OriginalDemandedBits.getBitWidth(); assert(Op.getScalarValueSizeInBits() == BitWidth && "Mask size mismatches value type size!"); unsigned NumElts = OriginalDemandedElts.getBitWidth(); assert((!Op.getValueType().isVector() || NumElts == Op.getValueType().getVectorNumElements()) && "Unexpected vector size"); APInt DemandedBits = OriginalDemandedBits; APInt DemandedElts = OriginalDemandedElts; SDLoc dl(Op); auto &DL = TLO.DAG.getDataLayout(); // Don't know anything. Known = KnownBits(BitWidth); // Undef operand. if (Op.isUndef()) return false; if (Op.getOpcode() == ISD::Constant) { // We know all of the bits for a constant! Known.One = cast(Op)->getAPIntValue(); Known.Zero = ~Known.One; return false; } // Other users may use these bits. EVT VT = Op.getValueType(); if (!Op.getNode()->hasOneUse() && !AssumeSingleUse) { if (Depth != 0) { // If not at the root, Just compute the Known bits to // simplify things downstream. Known = TLO.DAG.computeKnownBits(Op, DemandedElts, Depth); return false; } // If this is the root being simplified, allow it to have multiple uses, // just set the DemandedBits/Elts to all bits. DemandedBits = APInt::getAllOnesValue(BitWidth); DemandedElts = APInt::getAllOnesValue(NumElts); } else if (OriginalDemandedBits == 0 || OriginalDemandedElts == 0) { // Not demanding any bits/elts from Op. return TLO.CombineTo(Op, TLO.DAG.getUNDEF(VT)); } else if (Depth >= SelectionDAG::MaxRecursionDepth) { // Limit search depth. return false; } KnownBits Known2, KnownOut; switch (Op.getOpcode()) { case ISD::TargetConstant: llvm_unreachable("Can't simplify this node"); case ISD::SCALAR_TO_VECTOR: { if (!DemandedElts[0]) return TLO.CombineTo(Op, TLO.DAG.getUNDEF(VT)); KnownBits SrcKnown; SDValue Src = Op.getOperand(0); unsigned SrcBitWidth = Src.getScalarValueSizeInBits(); APInt SrcDemandedBits = DemandedBits.zextOrSelf(SrcBitWidth); if (SimplifyDemandedBits(Src, SrcDemandedBits, SrcKnown, TLO, Depth + 1)) return true; Known = SrcKnown.zextOrTrunc(BitWidth, false); break; } case ISD::BUILD_VECTOR: // Collect the known bits that are shared by every demanded element. // TODO: Call SimplifyDemandedBits for non-constant demanded elements. Known = TLO.DAG.computeKnownBits(Op, DemandedElts, Depth); return false; // Don't fall through, will infinitely loop. case ISD::LOAD: { LoadSDNode *LD = cast(Op); if (getTargetConstantFromLoad(LD)) { Known = TLO.DAG.computeKnownBits(Op, DemandedElts, Depth); return false; // Don't fall through, will infinitely loop. } break; } case ISD::INSERT_VECTOR_ELT: { SDValue Vec = Op.getOperand(0); SDValue Scl = Op.getOperand(1); auto *CIdx = dyn_cast(Op.getOperand(2)); EVT VecVT = Vec.getValueType(); // If index isn't constant, assume we need all vector elements AND the // inserted element. APInt DemandedVecElts(DemandedElts); if (CIdx && CIdx->getAPIntValue().ult(VecVT.getVectorNumElements())) { unsigned Idx = CIdx->getZExtValue(); DemandedVecElts.clearBit(Idx); // Inserted element is not required. if (!DemandedElts[Idx]) return TLO.CombineTo(Op, Vec); } KnownBits KnownScl; unsigned NumSclBits = Scl.getScalarValueSizeInBits(); APInt DemandedSclBits = DemandedBits.zextOrTrunc(NumSclBits); if (SimplifyDemandedBits(Scl, DemandedSclBits, KnownScl, TLO, Depth + 1)) return true; Known = KnownScl.zextOrTrunc(BitWidth, false); KnownBits KnownVec; if (SimplifyDemandedBits(Vec, DemandedBits, DemandedVecElts, KnownVec, TLO, Depth + 1)) return true; if (!!DemandedVecElts) { Known.One &= KnownVec.One; Known.Zero &= KnownVec.Zero; } return false; } case ISD::INSERT_SUBVECTOR: { SDValue Base = Op.getOperand(0); SDValue Sub = Op.getOperand(1); EVT SubVT = Sub.getValueType(); unsigned NumSubElts = SubVT.getVectorNumElements(); // If index isn't constant, assume we need the original demanded base // elements and ALL the inserted subvector elements. APInt BaseElts = DemandedElts; APInt SubElts = APInt::getAllOnesValue(NumSubElts); if (isa(Op.getOperand(2))) { const APInt &Idx = Op.getConstantOperandAPInt(2); if (Idx.ule(NumElts - NumSubElts)) { unsigned SubIdx = Idx.getZExtValue(); SubElts = DemandedElts.extractBits(NumSubElts, SubIdx); BaseElts.insertBits(APInt::getNullValue(NumSubElts), SubIdx); } } KnownBits KnownSub, KnownBase; if (SimplifyDemandedBits(Sub, DemandedBits, SubElts, KnownSub, TLO, Depth + 1)) return true; if (SimplifyDemandedBits(Base, DemandedBits, BaseElts, KnownBase, TLO, Depth + 1)) return true; Known.Zero.setAllBits(); Known.One.setAllBits(); if (!!SubElts) { Known.One &= KnownSub.One; Known.Zero &= KnownSub.Zero; } if (!!BaseElts) { Known.One &= KnownBase.One; Known.Zero &= KnownBase.Zero; } break; } case ISD::EXTRACT_SUBVECTOR: { // If index isn't constant, assume we need all the source vector elements. SDValue Src = Op.getOperand(0); ConstantSDNode *SubIdx = dyn_cast(Op.getOperand(1)); unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); APInt SrcElts = APInt::getAllOnesValue(NumSrcElts); if (SubIdx && SubIdx->getAPIntValue().ule(NumSrcElts - NumElts)) { // Offset the demanded elts by the subvector index. uint64_t Idx = SubIdx->getZExtValue(); SrcElts = DemandedElts.zextOrSelf(NumSrcElts).shl(Idx); } if (SimplifyDemandedBits(Src, DemandedBits, SrcElts, Known, TLO, Depth + 1)) return true; break; } case ISD::CONCAT_VECTORS: { Known.Zero.setAllBits(); Known.One.setAllBits(); EVT SubVT = Op.getOperand(0).getValueType(); unsigned NumSubVecs = Op.getNumOperands(); unsigned NumSubElts = SubVT.getVectorNumElements(); for (unsigned i = 0; i != NumSubVecs; ++i) { APInt DemandedSubElts = DemandedElts.extractBits(NumSubElts, i * NumSubElts); if (SimplifyDemandedBits(Op.getOperand(i), DemandedBits, DemandedSubElts, Known2, TLO, Depth + 1)) return true; // Known bits are shared by every demanded subvector element. if (!!DemandedSubElts) { Known.One &= Known2.One; Known.Zero &= Known2.Zero; } } break; } case ISD::VECTOR_SHUFFLE: { ArrayRef ShuffleMask = cast(Op)->getMask(); // Collect demanded elements from shuffle operands.. APInt DemandedLHS(NumElts, 0); APInt DemandedRHS(NumElts, 0); for (unsigned i = 0; i != NumElts; ++i) { if (!DemandedElts[i]) continue; int M = ShuffleMask[i]; if (M < 0) { // For UNDEF elements, we don't know anything about the common state of // the shuffle result. DemandedLHS.clearAllBits(); DemandedRHS.clearAllBits(); break; } assert(0 <= M && M < (int)(2 * NumElts) && "Shuffle index out of range"); if (M < (int)NumElts) DemandedLHS.setBit(M); else DemandedRHS.setBit(M - NumElts); } if (!!DemandedLHS || !!DemandedRHS) { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); Known.Zero.setAllBits(); Known.One.setAllBits(); if (!!DemandedLHS) { if (SimplifyDemandedBits(Op0, DemandedBits, DemandedLHS, Known2, TLO, Depth + 1)) return true; Known.One &= Known2.One; Known.Zero &= Known2.Zero; } if (!!DemandedRHS) { if (SimplifyDemandedBits(Op1, DemandedBits, DemandedRHS, Known2, TLO, Depth + 1)) return true; Known.One &= Known2.One; Known.Zero &= Known2.Zero; } // Attempt to avoid multi-use ops if we don't need anything from them. SDValue DemandedOp0 = SimplifyMultipleUseDemandedBits( Op0, DemandedBits, DemandedLHS, TLO.DAG, Depth + 1); SDValue DemandedOp1 = SimplifyMultipleUseDemandedBits( Op1, DemandedBits, DemandedRHS, TLO.DAG, Depth + 1); if (DemandedOp0 || DemandedOp1) { Op0 = DemandedOp0 ? DemandedOp0 : Op0; Op1 = DemandedOp1 ? DemandedOp1 : Op1; SDValue NewOp = TLO.DAG.getVectorShuffle(VT, dl, Op0, Op1, ShuffleMask); return TLO.CombineTo(Op, NewOp); } } break; } case ISD::AND: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); // If the RHS is a constant, check to see if the LHS would be zero without // using the bits from the RHS. Below, we use knowledge about the RHS to // simplify the LHS, here we're using information from the LHS to simplify // the RHS. if (ConstantSDNode *RHSC = isConstOrConstSplat(Op1)) { // Do not increment Depth here; that can cause an infinite loop. KnownBits LHSKnown = TLO.DAG.computeKnownBits(Op0, DemandedElts, Depth); // If the LHS already has zeros where RHSC does, this 'and' is dead. if ((LHSKnown.Zero & DemandedBits) == (~RHSC->getAPIntValue() & DemandedBits)) return TLO.CombineTo(Op, Op0); // If any of the set bits in the RHS are known zero on the LHS, shrink // the constant. if (ShrinkDemandedConstant(Op, ~LHSKnown.Zero & DemandedBits, TLO)) return true; // Bitwise-not (xor X, -1) is a special case: we don't usually shrink its // constant, but if this 'and' is only clearing bits that were just set by // the xor, then this 'and' can be eliminated by shrinking the mask of // the xor. For example, for a 32-bit X: // and (xor (srl X, 31), -1), 1 --> xor (srl X, 31), 1 if (isBitwiseNot(Op0) && Op0.hasOneUse() && LHSKnown.One == ~RHSC->getAPIntValue()) { SDValue Xor = TLO.DAG.getNode(ISD::XOR, dl, VT, Op0.getOperand(0), Op1); return TLO.CombineTo(Op, Xor); } } if (SimplifyDemandedBits(Op1, DemandedBits, DemandedElts, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); if (SimplifyDemandedBits(Op0, ~Known.Zero & DemandedBits, DemandedElts, Known2, TLO, Depth + 1)) return true; assert(!Known2.hasConflict() && "Bits known to be one AND zero?"); // Attempt to avoid multi-use ops if we don't need anything from them. if (!DemandedBits.isAllOnesValue() || !DemandedElts.isAllOnesValue()) { SDValue DemandedOp0 = SimplifyMultipleUseDemandedBits( Op0, DemandedBits, DemandedElts, TLO.DAG, Depth + 1); SDValue DemandedOp1 = SimplifyMultipleUseDemandedBits( Op1, DemandedBits, DemandedElts, TLO.DAG, Depth + 1); if (DemandedOp0 || DemandedOp1) { Op0 = DemandedOp0 ? DemandedOp0 : Op0; Op1 = DemandedOp1 ? DemandedOp1 : Op1; SDValue NewOp = TLO.DAG.getNode(Op.getOpcode(), dl, VT, Op0, Op1); return TLO.CombineTo(Op, NewOp); } } // If all of the demanded bits are known one on one side, return the other. // These bits cannot contribute to the result of the 'and'. if (DemandedBits.isSubsetOf(Known2.Zero | Known.One)) return TLO.CombineTo(Op, Op0); if (DemandedBits.isSubsetOf(Known.Zero | Known2.One)) return TLO.CombineTo(Op, Op1); // If all of the demanded bits in the inputs are known zeros, return zero. if (DemandedBits.isSubsetOf(Known.Zero | Known2.Zero)) return TLO.CombineTo(Op, TLO.DAG.getConstant(0, dl, VT)); // If the RHS is a constant, see if we can simplify it. if (ShrinkDemandedConstant(Op, ~Known2.Zero & DemandedBits, TLO)) return true; // If the operation can be done in a smaller type, do so. if (ShrinkDemandedOp(Op, BitWidth, DemandedBits, TLO)) return true; // Output known-1 bits are only known if set in both the LHS & RHS. Known.One &= Known2.One; // Output known-0 are known to be clear if zero in either the LHS | RHS. Known.Zero |= Known2.Zero; break; } case ISD::OR: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); if (SimplifyDemandedBits(Op1, DemandedBits, DemandedElts, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); if (SimplifyDemandedBits(Op0, ~Known.One & DemandedBits, DemandedElts, Known2, TLO, Depth + 1)) return true; assert(!Known2.hasConflict() && "Bits known to be one AND zero?"); // Attempt to avoid multi-use ops if we don't need anything from them. if (!DemandedBits.isAllOnesValue() || !DemandedElts.isAllOnesValue()) { SDValue DemandedOp0 = SimplifyMultipleUseDemandedBits( Op0, DemandedBits, DemandedElts, TLO.DAG, Depth + 1); SDValue DemandedOp1 = SimplifyMultipleUseDemandedBits( Op1, DemandedBits, DemandedElts, TLO.DAG, Depth + 1); if (DemandedOp0 || DemandedOp1) { Op0 = DemandedOp0 ? DemandedOp0 : Op0; Op1 = DemandedOp1 ? DemandedOp1 : Op1; SDValue NewOp = TLO.DAG.getNode(Op.getOpcode(), dl, VT, Op0, Op1); return TLO.CombineTo(Op, NewOp); } } // If all of the demanded bits are known zero on one side, return the other. // These bits cannot contribute to the result of the 'or'. if (DemandedBits.isSubsetOf(Known2.One | Known.Zero)) return TLO.CombineTo(Op, Op0); if (DemandedBits.isSubsetOf(Known.One | Known2.Zero)) return TLO.CombineTo(Op, Op1); // If the RHS is a constant, see if we can simplify it. if (ShrinkDemandedConstant(Op, DemandedBits, TLO)) return true; // If the operation can be done in a smaller type, do so. if (ShrinkDemandedOp(Op, BitWidth, DemandedBits, TLO)) return true; // Output known-0 bits are only known if clear in both the LHS & RHS. Known.Zero &= Known2.Zero; // Output known-1 are known to be set if set in either the LHS | RHS. Known.One |= Known2.One; break; } case ISD::XOR: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); if (SimplifyDemandedBits(Op1, DemandedBits, DemandedElts, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); if (SimplifyDemandedBits(Op0, DemandedBits, DemandedElts, Known2, TLO, Depth + 1)) return true; assert(!Known2.hasConflict() && "Bits known to be one AND zero?"); // Attempt to avoid multi-use ops if we don't need anything from them. if (!DemandedBits.isAllOnesValue() || !DemandedElts.isAllOnesValue()) { SDValue DemandedOp0 = SimplifyMultipleUseDemandedBits( Op0, DemandedBits, DemandedElts, TLO.DAG, Depth + 1); SDValue DemandedOp1 = SimplifyMultipleUseDemandedBits( Op1, DemandedBits, DemandedElts, TLO.DAG, Depth + 1); if (DemandedOp0 || DemandedOp1) { Op0 = DemandedOp0 ? DemandedOp0 : Op0; Op1 = DemandedOp1 ? DemandedOp1 : Op1; SDValue NewOp = TLO.DAG.getNode(Op.getOpcode(), dl, VT, Op0, Op1); return TLO.CombineTo(Op, NewOp); } } // If all of the demanded bits are known zero on one side, return the other. // These bits cannot contribute to the result of the 'xor'. if (DemandedBits.isSubsetOf(Known.Zero)) return TLO.CombineTo(Op, Op0); if (DemandedBits.isSubsetOf(Known2.Zero)) return TLO.CombineTo(Op, Op1); // If the operation can be done in a smaller type, do so. if (ShrinkDemandedOp(Op, BitWidth, DemandedBits, TLO)) return true; // If all of the unknown bits are known to be zero on one side or the other // (but not both) turn this into an *inclusive* or. // e.g. (A & C1)^(B & C2) -> (A & C1)|(B & C2) iff C1&C2 == 0 if (DemandedBits.isSubsetOf(Known.Zero | Known2.Zero)) return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::OR, dl, VT, Op0, Op1)); // Output known-0 bits are known if clear or set in both the LHS & RHS. KnownOut.Zero = (Known.Zero & Known2.Zero) | (Known.One & Known2.One); // Output known-1 are known to be set if set in only one of the LHS, RHS. KnownOut.One = (Known.Zero & Known2.One) | (Known.One & Known2.Zero); if (ConstantSDNode *C = isConstOrConstSplat(Op1)) { // If one side is a constant, and all of the known set bits on the other // side are also set in the constant, turn this into an AND, as we know // the bits will be cleared. // e.g. (X | C1) ^ C2 --> (X | C1) & ~C2 iff (C1&C2) == C2 // NB: it is okay if more bits are known than are requested if (C->getAPIntValue() == Known2.One) { SDValue ANDC = TLO.DAG.getConstant(~C->getAPIntValue() & DemandedBits, dl, VT); return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::AND, dl, VT, Op0, ANDC)); } // If the RHS is a constant, see if we can change it. Don't alter a -1 // constant because that's a 'not' op, and that is better for combining // and codegen. if (!C->isAllOnesValue()) { if (DemandedBits.isSubsetOf(C->getAPIntValue())) { // We're flipping all demanded bits. Flip the undemanded bits too. SDValue New = TLO.DAG.getNOT(dl, Op0, VT); return TLO.CombineTo(Op, New); } // If we can't turn this into a 'not', try to shrink the constant. if (ShrinkDemandedConstant(Op, DemandedBits, TLO)) return true; } } Known = std::move(KnownOut); break; } case ISD::SELECT: if (SimplifyDemandedBits(Op.getOperand(2), DemandedBits, Known, TLO, Depth + 1)) return true; if (SimplifyDemandedBits(Op.getOperand(1), DemandedBits, Known2, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); assert(!Known2.hasConflict() && "Bits known to be one AND zero?"); // If the operands are constants, see if we can simplify them. if (ShrinkDemandedConstant(Op, DemandedBits, TLO)) return true; // Only known if known in both the LHS and RHS. Known.One &= Known2.One; Known.Zero &= Known2.Zero; break; case ISD::SELECT_CC: if (SimplifyDemandedBits(Op.getOperand(3), DemandedBits, Known, TLO, Depth + 1)) return true; if (SimplifyDemandedBits(Op.getOperand(2), DemandedBits, Known2, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); assert(!Known2.hasConflict() && "Bits known to be one AND zero?"); // If the operands are constants, see if we can simplify them. if (ShrinkDemandedConstant(Op, DemandedBits, TLO)) return true; // Only known if known in both the LHS and RHS. Known.One &= Known2.One; Known.Zero &= Known2.Zero; break; case ISD::SETCC: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); ISD::CondCode CC = cast(Op.getOperand(2))->get(); // If (1) we only need the sign-bit, (2) the setcc operands are the same // width as the setcc result, and (3) the result of a setcc conforms to 0 or // -1, we may be able to bypass the setcc. if (DemandedBits.isSignMask() && Op0.getScalarValueSizeInBits() == BitWidth && getBooleanContents(Op0.getValueType()) == BooleanContent::ZeroOrNegativeOneBooleanContent) { // If we're testing X < 0, then this compare isn't needed - just use X! // FIXME: We're limiting to integer types here, but this should also work // if we don't care about FP signed-zero. The use of SETLT with FP means // that we don't care about NaNs. if (CC == ISD::SETLT && Op1.getValueType().isInteger() && (isNullConstant(Op1) || ISD::isBuildVectorAllZeros(Op1.getNode()))) return TLO.CombineTo(Op, Op0); // TODO: Should we check for other forms of sign-bit comparisons? // Examples: X <= -1, X >= 0 } if (getBooleanContents(Op0.getValueType()) == TargetLowering::ZeroOrOneBooleanContent && BitWidth > 1) Known.Zero.setBitsFrom(1); break; } case ISD::SHL: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); if (ConstantSDNode *SA = isConstOrConstSplat(Op1, DemandedElts)) { // If the shift count is an invalid immediate, don't do anything. if (SA->getAPIntValue().uge(BitWidth)) break; unsigned ShAmt = SA->getZExtValue(); if (ShAmt == 0) return TLO.CombineTo(Op, Op0); // If this is ((X >>u C1) << ShAmt), see if we can simplify this into a // single shift. We can do this if the bottom bits (which are shifted // out) are never demanded. // TODO - support non-uniform vector amounts. if (Op0.getOpcode() == ISD::SRL) { if (!DemandedBits.intersects(APInt::getLowBitsSet(BitWidth, ShAmt))) { if (ConstantSDNode *SA2 = isConstOrConstSplat(Op0.getOperand(1), DemandedElts)) { if (SA2->getAPIntValue().ult(BitWidth)) { unsigned C1 = SA2->getZExtValue(); unsigned Opc = ISD::SHL; int Diff = ShAmt - C1; if (Diff < 0) { Diff = -Diff; Opc = ISD::SRL; } SDValue NewSA = TLO.DAG.getConstant(Diff, dl, Op1.getValueType()); return TLO.CombineTo( Op, TLO.DAG.getNode(Opc, dl, VT, Op0.getOperand(0), NewSA)); } } } } if (SimplifyDemandedBits(Op0, DemandedBits.lshr(ShAmt), DemandedElts, Known, TLO, Depth + 1)) return true; // Try shrinking the operation as long as the shift amount will still be // in range. if ((ShAmt < DemandedBits.getActiveBits()) && ShrinkDemandedOp(Op, BitWidth, DemandedBits, TLO)) return true; // Convert (shl (anyext x, c)) to (anyext (shl x, c)) if the high bits // are not demanded. This will likely allow the anyext to be folded away. if (Op0.getOpcode() == ISD::ANY_EXTEND) { SDValue InnerOp = Op0.getOperand(0); EVT InnerVT = InnerOp.getValueType(); unsigned InnerBits = InnerVT.getScalarSizeInBits(); if (ShAmt < InnerBits && DemandedBits.getActiveBits() <= InnerBits && isTypeDesirableForOp(ISD::SHL, InnerVT)) { EVT ShTy = getShiftAmountTy(InnerVT, DL); if (!APInt(BitWidth, ShAmt).isIntN(ShTy.getSizeInBits())) ShTy = InnerVT; SDValue NarrowShl = TLO.DAG.getNode(ISD::SHL, dl, InnerVT, InnerOp, TLO.DAG.getConstant(ShAmt, dl, ShTy)); return TLO.CombineTo( Op, TLO.DAG.getNode(ISD::ANY_EXTEND, dl, VT, NarrowShl)); } // Repeat the SHL optimization above in cases where an extension // intervenes: (shl (anyext (shr x, c1)), c2) to // (shl (anyext x), c2-c1). This requires that the bottom c1 bits // aren't demanded (as above) and that the shifted upper c1 bits of // x aren't demanded. if (Op0.hasOneUse() && InnerOp.getOpcode() == ISD::SRL && InnerOp.hasOneUse()) { if (ConstantSDNode *SA2 = isConstOrConstSplat(InnerOp.getOperand(1))) { unsigned InnerShAmt = SA2->getLimitedValue(InnerBits); if (InnerShAmt < ShAmt && InnerShAmt < InnerBits && DemandedBits.getActiveBits() <= (InnerBits - InnerShAmt + ShAmt) && DemandedBits.countTrailingZeros() >= ShAmt) { SDValue NewSA = TLO.DAG.getConstant(ShAmt - InnerShAmt, dl, Op1.getValueType()); SDValue NewExt = TLO.DAG.getNode(ISD::ANY_EXTEND, dl, VT, InnerOp.getOperand(0)); return TLO.CombineTo( Op, TLO.DAG.getNode(ISD::SHL, dl, VT, NewExt, NewSA)); } } } } Known.Zero <<= ShAmt; Known.One <<= ShAmt; // low bits known zero. Known.Zero.setLowBits(ShAmt); } break; } case ISD::SRL: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); if (ConstantSDNode *SA = isConstOrConstSplat(Op1, DemandedElts)) { // If the shift count is an invalid immediate, don't do anything. if (SA->getAPIntValue().uge(BitWidth)) break; unsigned ShAmt = SA->getZExtValue(); if (ShAmt == 0) return TLO.CombineTo(Op, Op0); EVT ShiftVT = Op1.getValueType(); APInt InDemandedMask = (DemandedBits << ShAmt); // If the shift is exact, then it does demand the low bits (and knows that // they are zero). if (Op->getFlags().hasExact()) InDemandedMask.setLowBits(ShAmt); // If this is ((X << C1) >>u ShAmt), see if we can simplify this into a // single shift. We can do this if the top bits (which are shifted out) // are never demanded. // TODO - support non-uniform vector amounts. if (Op0.getOpcode() == ISD::SHL) { if (ConstantSDNode *SA2 = isConstOrConstSplat(Op0.getOperand(1), DemandedElts)) { if (!DemandedBits.intersects( APInt::getHighBitsSet(BitWidth, ShAmt))) { if (SA2->getAPIntValue().ult(BitWidth)) { unsigned C1 = SA2->getZExtValue(); unsigned Opc = ISD::SRL; int Diff = ShAmt - C1; if (Diff < 0) { Diff = -Diff; Opc = ISD::SHL; } SDValue NewSA = TLO.DAG.getConstant(Diff, dl, ShiftVT); return TLO.CombineTo( Op, TLO.DAG.getNode(Opc, dl, VT, Op0.getOperand(0), NewSA)); } } } } // Compute the new bits that are at the top now. if (SimplifyDemandedBits(Op0, InDemandedMask, DemandedElts, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); Known.Zero.lshrInPlace(ShAmt); Known.One.lshrInPlace(ShAmt); Known.Zero.setHighBits(ShAmt); // High bits known zero. } break; } case ISD::SRA: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); // If this is an arithmetic shift right and only the low-bit is set, we can // always convert this into a logical shr, even if the shift amount is // variable. The low bit of the shift cannot be an input sign bit unless // the shift amount is >= the size of the datatype, which is undefined. if (DemandedBits.isOneValue()) return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::SRL, dl, VT, Op0, Op1)); if (ConstantSDNode *SA = isConstOrConstSplat(Op1, DemandedElts)) { // If the shift count is an invalid immediate, don't do anything. if (SA->getAPIntValue().uge(BitWidth)) break; unsigned ShAmt = SA->getZExtValue(); if (ShAmt == 0) return TLO.CombineTo(Op, Op0); APInt InDemandedMask = (DemandedBits << ShAmt); // If the shift is exact, then it does demand the low bits (and knows that // they are zero). if (Op->getFlags().hasExact()) InDemandedMask.setLowBits(ShAmt); // If any of the demanded bits are produced by the sign extension, we also // demand the input sign bit. if (DemandedBits.countLeadingZeros() < ShAmt) InDemandedMask.setSignBit(); if (SimplifyDemandedBits(Op0, InDemandedMask, DemandedElts, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); Known.Zero.lshrInPlace(ShAmt); Known.One.lshrInPlace(ShAmt); // If the input sign bit is known to be zero, or if none of the top bits // are demanded, turn this into an unsigned shift right. if (Known.Zero[BitWidth - ShAmt - 1] || DemandedBits.countLeadingZeros() >= ShAmt) { SDNodeFlags Flags; Flags.setExact(Op->getFlags().hasExact()); return TLO.CombineTo( Op, TLO.DAG.getNode(ISD::SRL, dl, VT, Op0, Op1, Flags)); } int Log2 = DemandedBits.exactLogBase2(); if (Log2 >= 0) { // The bit must come from the sign. SDValue NewSA = TLO.DAG.getConstant(BitWidth - 1 - Log2, dl, Op1.getValueType()); return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::SRL, dl, VT, Op0, NewSA)); } if (Known.One[BitWidth - ShAmt - 1]) // New bits are known one. Known.One.setHighBits(ShAmt); } break; } case ISD::FSHL: case ISD::FSHR: { SDValue Op0 = Op.getOperand(0); SDValue Op1 = Op.getOperand(1); SDValue Op2 = Op.getOperand(2); bool IsFSHL = (Op.getOpcode() == ISD::FSHL); if (ConstantSDNode *SA = isConstOrConstSplat(Op2, DemandedElts)) { unsigned Amt = SA->getAPIntValue().urem(BitWidth); // For fshl, 0-shift returns the 1st arg. // For fshr, 0-shift returns the 2nd arg. if (Amt == 0) { if (SimplifyDemandedBits(IsFSHL ? Op0 : Op1, DemandedBits, DemandedElts, Known, TLO, Depth + 1)) return true; break; } // fshl: (Op0 << Amt) | (Op1 >> (BW - Amt)) // fshr: (Op0 << (BW - Amt)) | (Op1 >> Amt) APInt Demanded0 = DemandedBits.lshr(IsFSHL ? Amt : (BitWidth - Amt)); APInt Demanded1 = DemandedBits << (IsFSHL ? (BitWidth - Amt) : Amt); if (SimplifyDemandedBits(Op0, Demanded0, DemandedElts, Known2, TLO, Depth + 1)) return true; if (SimplifyDemandedBits(Op1, Demanded1, DemandedElts, Known, TLO, Depth + 1)) return true; Known2.One <<= (IsFSHL ? Amt : (BitWidth - Amt)); Known2.Zero <<= (IsFSHL ? Amt : (BitWidth - Amt)); Known.One.lshrInPlace(IsFSHL ? (BitWidth - Amt) : Amt); Known.Zero.lshrInPlace(IsFSHL ? (BitWidth - Amt) : Amt); Known.One |= Known2.One; Known.Zero |= Known2.Zero; } break; } case ISD::BITREVERSE: { SDValue Src = Op.getOperand(0); APInt DemandedSrcBits = DemandedBits.reverseBits(); if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedElts, Known2, TLO, Depth + 1)) return true; Known.One = Known2.One.reverseBits(); Known.Zero = Known2.Zero.reverseBits(); break; } case ISD::BSWAP: { SDValue Src = Op.getOperand(0); APInt DemandedSrcBits = DemandedBits.byteSwap(); if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedElts, Known2, TLO, Depth + 1)) return true; Known.One = Known2.One.byteSwap(); Known.Zero = Known2.Zero.byteSwap(); break; } case ISD::SIGN_EXTEND_INREG: { SDValue Op0 = Op.getOperand(0); EVT ExVT = cast(Op.getOperand(1))->getVT(); unsigned ExVTBits = ExVT.getScalarSizeInBits(); // If we only care about the highest bit, don't bother shifting right. if (DemandedBits.isSignMask()) { unsigned NumSignBits = TLO.DAG.ComputeNumSignBits(Op0); bool AlreadySignExtended = NumSignBits >= BitWidth - ExVTBits + 1; // However if the input is already sign extended we expect the sign // extension to be dropped altogether later and do not simplify. if (!AlreadySignExtended) { // Compute the correct shift amount type, which must be getShiftAmountTy // for scalar types after legalization. EVT ShiftAmtTy = VT; if (TLO.LegalTypes() && !ShiftAmtTy.isVector()) ShiftAmtTy = getShiftAmountTy(ShiftAmtTy, DL); SDValue ShiftAmt = TLO.DAG.getConstant(BitWidth - ExVTBits, dl, ShiftAmtTy); return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::SHL, dl, VT, Op0, ShiftAmt)); } } // If none of the extended bits are demanded, eliminate the sextinreg. if (DemandedBits.getActiveBits() <= ExVTBits) return TLO.CombineTo(Op, Op0); APInt InputDemandedBits = DemandedBits.getLoBits(ExVTBits); // Since the sign extended bits are demanded, we know that the sign // bit is demanded. InputDemandedBits.setBit(ExVTBits - 1); if (SimplifyDemandedBits(Op0, InputDemandedBits, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); // If the sign bit of the input is known set or clear, then we know the // top bits of the result. // If the input sign bit is known zero, convert this into a zero extension. if (Known.Zero[ExVTBits - 1]) return TLO.CombineTo( Op, TLO.DAG.getZeroExtendInReg(Op0, dl, ExVT.getScalarType())); APInt Mask = APInt::getLowBitsSet(BitWidth, ExVTBits); if (Known.One[ExVTBits - 1]) { // Input sign bit known set Known.One.setBitsFrom(ExVTBits); Known.Zero &= Mask; } else { // Input sign bit unknown Known.Zero &= Mask; Known.One &= Mask; } break; } case ISD::BUILD_PAIR: { EVT HalfVT = Op.getOperand(0).getValueType(); unsigned HalfBitWidth = HalfVT.getScalarSizeInBits(); APInt MaskLo = DemandedBits.getLoBits(HalfBitWidth).trunc(HalfBitWidth); APInt MaskHi = DemandedBits.getHiBits(HalfBitWidth).trunc(HalfBitWidth); KnownBits KnownLo, KnownHi; if (SimplifyDemandedBits(Op.getOperand(0), MaskLo, KnownLo, TLO, Depth + 1)) return true; if (SimplifyDemandedBits(Op.getOperand(1), MaskHi, KnownHi, TLO, Depth + 1)) return true; Known.Zero = KnownLo.Zero.zext(BitWidth) | KnownHi.Zero.zext(BitWidth).shl(HalfBitWidth); Known.One = KnownLo.One.zext(BitWidth) | KnownHi.One.zext(BitWidth).shl(HalfBitWidth); break; } case ISD::ZERO_EXTEND: case ISD::ZERO_EXTEND_VECTOR_INREG: { SDValue Src = Op.getOperand(0); EVT SrcVT = Src.getValueType(); unsigned InBits = SrcVT.getScalarSizeInBits(); unsigned InElts = SrcVT.isVector() ? SrcVT.getVectorNumElements() : 1; bool IsVecInReg = Op.getOpcode() == ISD::ZERO_EXTEND_VECTOR_INREG; // If none of the top bits are demanded, convert this into an any_extend. if (DemandedBits.getActiveBits() <= InBits) { // If we only need the non-extended bits of the bottom element // then we can just bitcast to the result. if (IsVecInReg && DemandedElts == 1 && VT.getSizeInBits() == SrcVT.getSizeInBits() && TLO.DAG.getDataLayout().isLittleEndian()) return TLO.CombineTo(Op, TLO.DAG.getBitcast(VT, Src)); unsigned Opc = IsVecInReg ? ISD::ANY_EXTEND_VECTOR_INREG : ISD::ANY_EXTEND; if (!TLO.LegalOperations() || isOperationLegal(Opc, VT)) return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, dl, VT, Src)); } APInt InDemandedBits = DemandedBits.trunc(InBits); APInt InDemandedElts = DemandedElts.zextOrSelf(InElts); if (SimplifyDemandedBits(Src, InDemandedBits, InDemandedElts, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); assert(Known.getBitWidth() == InBits && "Src width has changed?"); Known = Known.zext(BitWidth, true /* ExtendedBitsAreKnownZero */); break; } case ISD::SIGN_EXTEND: case ISD::SIGN_EXTEND_VECTOR_INREG: { SDValue Src = Op.getOperand(0); EVT SrcVT = Src.getValueType(); unsigned InBits = SrcVT.getScalarSizeInBits(); unsigned InElts = SrcVT.isVector() ? SrcVT.getVectorNumElements() : 1; bool IsVecInReg = Op.getOpcode() == ISD::SIGN_EXTEND_VECTOR_INREG; // If none of the top bits are demanded, convert this into an any_extend. if (DemandedBits.getActiveBits() <= InBits) { // If we only need the non-extended bits of the bottom element // then we can just bitcast to the result. if (IsVecInReg && DemandedElts == 1 && VT.getSizeInBits() == SrcVT.getSizeInBits() && TLO.DAG.getDataLayout().isLittleEndian()) return TLO.CombineTo(Op, TLO.DAG.getBitcast(VT, Src)); unsigned Opc = IsVecInReg ? ISD::ANY_EXTEND_VECTOR_INREG : ISD::ANY_EXTEND; if (!TLO.LegalOperations() || isOperationLegal(Opc, VT)) return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, dl, VT, Src)); } APInt InDemandedBits = DemandedBits.trunc(InBits); APInt InDemandedElts = DemandedElts.zextOrSelf(InElts); // Since some of the sign extended bits are demanded, we know that the sign // bit is demanded. InDemandedBits.setBit(InBits - 1); if (SimplifyDemandedBits(Src, InDemandedBits, InDemandedElts, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); assert(Known.getBitWidth() == InBits && "Src width has changed?"); // If the sign bit is known one, the top bits match. Known = Known.sext(BitWidth); // If the sign bit is known zero, convert this to a zero extend. if (Known.isNonNegative()) { unsigned Opc = IsVecInReg ? ISD::ZERO_EXTEND_VECTOR_INREG : ISD::ZERO_EXTEND; if (!TLO.LegalOperations() || isOperationLegal(Opc, VT)) return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, dl, VT, Src)); } break; } case ISD::ANY_EXTEND: case ISD::ANY_EXTEND_VECTOR_INREG: { SDValue Src = Op.getOperand(0); EVT SrcVT = Src.getValueType(); unsigned InBits = SrcVT.getScalarSizeInBits(); unsigned InElts = SrcVT.isVector() ? SrcVT.getVectorNumElements() : 1; bool IsVecInReg = Op.getOpcode() == ISD::ANY_EXTEND_VECTOR_INREG; // If we only need the bottom element then we can just bitcast. // TODO: Handle ANY_EXTEND? if (IsVecInReg && DemandedElts == 1 && VT.getSizeInBits() == SrcVT.getSizeInBits() && TLO.DAG.getDataLayout().isLittleEndian()) return TLO.CombineTo(Op, TLO.DAG.getBitcast(VT, Src)); APInt InDemandedBits = DemandedBits.trunc(InBits); APInt InDemandedElts = DemandedElts.zextOrSelf(InElts); if (SimplifyDemandedBits(Src, InDemandedBits, InDemandedElts, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); assert(Known.getBitWidth() == InBits && "Src width has changed?"); Known = Known.zext(BitWidth, false /* => any extend */); break; } case ISD::TRUNCATE: { SDValue Src = Op.getOperand(0); // Simplify the input, using demanded bit information, and compute the known // zero/one bits live out. unsigned OperandBitWidth = Src.getScalarValueSizeInBits(); APInt TruncMask = DemandedBits.zext(OperandBitWidth); if (SimplifyDemandedBits(Src, TruncMask, Known, TLO, Depth + 1)) return true; Known = Known.trunc(BitWidth); // Attempt to avoid multi-use ops if we don't need anything from them. if (SDValue NewSrc = SimplifyMultipleUseDemandedBits( Src, TruncMask, DemandedElts, TLO.DAG, Depth + 1)) return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::TRUNCATE, dl, VT, NewSrc)); // If the input is only used by this truncate, see if we can shrink it based // on the known demanded bits. if (Src.getNode()->hasOneUse()) { switch (Src.getOpcode()) { default: break; case ISD::SRL: // Shrink SRL by a constant if none of the high bits shifted in are // demanded. if (TLO.LegalTypes() && !isTypeDesirableForOp(ISD::SRL, VT)) // Do not turn (vt1 truncate (vt2 srl)) into (vt1 srl) if vt1 is // undesirable. break; SDValue ShAmt = Src.getOperand(1); auto *ShAmtC = dyn_cast(ShAmt); if (!ShAmtC || ShAmtC->getAPIntValue().uge(BitWidth)) break; uint64_t ShVal = ShAmtC->getZExtValue(); APInt HighBits = APInt::getHighBitsSet(OperandBitWidth, OperandBitWidth - BitWidth); HighBits.lshrInPlace(ShVal); HighBits = HighBits.trunc(BitWidth); if (!(HighBits & DemandedBits)) { // None of the shifted in bits are needed. Add a truncate of the // shift input, then shift it. if (TLO.LegalTypes()) ShAmt = TLO.DAG.getConstant(ShVal, dl, getShiftAmountTy(VT, DL)); SDValue NewTrunc = TLO.DAG.getNode(ISD::TRUNCATE, dl, VT, Src.getOperand(0)); return TLO.CombineTo( Op, TLO.DAG.getNode(ISD::SRL, dl, VT, NewTrunc, ShAmt)); } break; } } assert(!Known.hasConflict() && "Bits known to be one AND zero?"); break; } case ISD::AssertZext: { // AssertZext demands all of the high bits, plus any of the low bits // demanded by its users. EVT ZVT = cast(Op.getOperand(1))->getVT(); APInt InMask = APInt::getLowBitsSet(BitWidth, ZVT.getSizeInBits()); if (SimplifyDemandedBits(Op.getOperand(0), ~InMask | DemandedBits, Known, TLO, Depth + 1)) return true; assert(!Known.hasConflict() && "Bits known to be one AND zero?"); Known.Zero |= ~InMask; break; } case ISD::EXTRACT_VECTOR_ELT: { SDValue Src = Op.getOperand(0); SDValue Idx = Op.getOperand(1); unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); unsigned EltBitWidth = Src.getScalarValueSizeInBits(); // Demand the bits from every vector element without a constant index. APInt DemandedSrcElts = APInt::getAllOnesValue(NumSrcElts); if (auto *CIdx = dyn_cast(Idx)) if (CIdx->getAPIntValue().ult(NumSrcElts)) DemandedSrcElts = APInt::getOneBitSet(NumSrcElts, CIdx->getZExtValue()); // If BitWidth > EltBitWidth the value is anyext:ed. So we do not know // anything about the extended bits. APInt DemandedSrcBits = DemandedBits; if (BitWidth > EltBitWidth) DemandedSrcBits = DemandedSrcBits.trunc(EltBitWidth); if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedSrcElts, Known2, TLO, Depth + 1)) return true; // Attempt to avoid multi-use ops if we don't need anything from them. if (!DemandedSrcBits.isAllOnesValue() || !DemandedSrcElts.isAllOnesValue()) { if (SDValue DemandedSrc = SimplifyMultipleUseDemandedBits( Src, DemandedSrcBits, DemandedSrcElts, TLO.DAG, Depth + 1)) { SDValue NewOp = TLO.DAG.getNode(Op.getOpcode(), dl, VT, DemandedSrc, Idx); return TLO.CombineTo(Op, NewOp); } } Known = Known2; if (BitWidth > EltBitWidth) Known = Known.zext(BitWidth, false /* => any extend */); break; } case ISD::BITCAST: { SDValue Src = Op.getOperand(0); EVT SrcVT = Src.getValueType(); unsigned NumSrcEltBits = SrcVT.getScalarSizeInBits(); // If this is an FP->Int bitcast and if the sign bit is the only // thing demanded, turn this into a FGETSIGN. if (!TLO.LegalOperations() && !VT.isVector() && !SrcVT.isVector() && DemandedBits == APInt::getSignMask(Op.getValueSizeInBits()) && SrcVT.isFloatingPoint()) { bool OpVTLegal = isOperationLegalOrCustom(ISD::FGETSIGN, VT); bool i32Legal = isOperationLegalOrCustom(ISD::FGETSIGN, MVT::i32); if ((OpVTLegal || i32Legal) && VT.isSimple() && SrcVT != MVT::f16 && SrcVT != MVT::f128) { // Cannot eliminate/lower SHL for f128 yet. EVT Ty = OpVTLegal ? VT : MVT::i32; // Make a FGETSIGN + SHL to move the sign bit into the appropriate // place. We expect the SHL to be eliminated by other optimizations. SDValue Sign = TLO.DAG.getNode(ISD::FGETSIGN, dl, Ty, Src); unsigned OpVTSizeInBits = Op.getValueSizeInBits(); if (!OpVTLegal && OpVTSizeInBits > 32) Sign = TLO.DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Sign); unsigned ShVal = Op.getValueSizeInBits() - 1; SDValue ShAmt = TLO.DAG.getConstant(ShVal, dl, VT); return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::SHL, dl, VT, Sign, ShAmt)); } } // Bitcast from a vector using SimplifyDemanded Bits/VectorElts. // Demand the elt/bit if any of the original elts/bits are demanded. // TODO - bigendian once we have test coverage. if (SrcVT.isVector() && (BitWidth % NumSrcEltBits) == 0 && TLO.DAG.getDataLayout().isLittleEndian()) { unsigned Scale = BitWidth / NumSrcEltBits; unsigned NumSrcElts = SrcVT.getVectorNumElements(); APInt DemandedSrcBits = APInt::getNullValue(NumSrcEltBits); APInt DemandedSrcElts = APInt::getNullValue(NumSrcElts); for (unsigned i = 0; i != Scale; ++i) { unsigned Offset = i * NumSrcEltBits; APInt Sub = DemandedBits.extractBits(NumSrcEltBits, Offset); if (!Sub.isNullValue()) { DemandedSrcBits |= Sub; for (unsigned j = 0; j != NumElts; ++j) if (DemandedElts[j]) DemandedSrcElts.setBit((j * Scale) + i); } } APInt KnownSrcUndef, KnownSrcZero; if (SimplifyDemandedVectorElts(Src, DemandedSrcElts, KnownSrcUndef, KnownSrcZero, TLO, Depth + 1)) return true; KnownBits KnownSrcBits; if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedSrcElts, KnownSrcBits, TLO, Depth + 1)) return true; } else if ((NumSrcEltBits % BitWidth) == 0 && TLO.DAG.getDataLayout().isLittleEndian()) { unsigned Scale = NumSrcEltBits / BitWidth; unsigned NumSrcElts = SrcVT.isVector() ? SrcVT.getVectorNumElements() : 1; APInt DemandedSrcBits = APInt::getNullValue(NumSrcEltBits); APInt DemandedSrcElts = APInt::getNullValue(NumSrcElts); for (unsigned i = 0; i != NumElts; ++i) if (DemandedElts[i]) { unsigned Offset = (i % Scale) * BitWidth; DemandedSrcBits.insertBits(DemandedBits, Offset); DemandedSrcElts.setBit(i / Scale); } if (SrcVT.isVector()) { APInt KnownSrcUndef, KnownSrcZero; if (SimplifyDemandedVectorElts(Src, DemandedSrcElts, KnownSrcUndef, KnownSrcZero, TLO, Depth + 1)) return true; } KnownBits KnownSrcBits; if (SimplifyDemandedBits(Src, DemandedSrcBits, DemandedSrcElts, KnownSrcBits, TLO, Depth + 1)) return true; } // If this is a bitcast, let computeKnownBits handle it. Only do this on a // recursive call where Known may be useful to the caller. if (Depth > 0) { Known = TLO.DAG.computeKnownBits(Op, DemandedElts, Depth); return false; } break; } case ISD::ADD: case ISD::MUL: case ISD::SUB: { // Add, Sub, and Mul don't demand any bits in positions beyond that // of the highest bit demanded of them. SDValue Op0 = Op.getOperand(0), Op1 = Op.getOperand(1); SDNodeFlags Flags = Op.getNode()->getFlags(); unsigned DemandedBitsLZ = DemandedBits.countLeadingZeros(); APInt LoMask = APInt::getLowBitsSet(BitWidth, BitWidth - DemandedBitsLZ); if (SimplifyDemandedBits(Op0, LoMask, DemandedElts, Known2, TLO, Depth + 1) || SimplifyDemandedBits(Op1, LoMask, DemandedElts, Known2, TLO, Depth + 1) || // See if the operation should be performed at a smaller bit width. ShrinkDemandedOp(Op, BitWidth, DemandedBits, TLO)) { if (Flags.hasNoSignedWrap() || Flags.hasNoUnsignedWrap()) { // Disable the nsw and nuw flags. We can no longer guarantee that we // won't wrap after simplification. Flags.setNoSignedWrap(false); Flags.setNoUnsignedWrap(false); SDValue NewOp = TLO.DAG.getNode(Op.getOpcode(), dl, VT, Op0, Op1, Flags); return TLO.CombineTo(Op, NewOp); } return true; } // Attempt to avoid multi-use ops if we don't need anything from them. if (!LoMask.isAllOnesValue() || !DemandedElts.isAllOnesValue()) { SDValue DemandedOp0 = SimplifyMultipleUseDemandedBits( Op0, LoMask, DemandedElts, TLO.DAG, Depth + 1); SDValue DemandedOp1 = SimplifyMultipleUseDemandedBits( Op1, LoMask, DemandedElts, TLO.DAG, Depth + 1); if (DemandedOp0 || DemandedOp1) { Flags.setNoSignedWrap(false); Flags.setNoUnsignedWrap(false); Op0 = DemandedOp0 ? DemandedOp0 : Op0; Op1 = DemandedOp1 ? DemandedOp1 : Op1; SDValue NewOp = TLO.DAG.getNode(Op.getOpcode(), dl, VT, Op0, Op1, Flags); return TLO.CombineTo(Op, NewOp); } } // If we have a constant operand, we may be able to turn it into -1 if we // do not demand the high bits. This can make the constant smaller to // encode, allow more general folding, or match specialized instruction // patterns (eg, 'blsr' on x86). Don't bother changing 1 to -1 because that // is probably not useful (and could be detrimental). ConstantSDNode *C = isConstOrConstSplat(Op1); APInt HighMask = APInt::getHighBitsSet(BitWidth, DemandedBitsLZ); if (C && !C->isAllOnesValue() && !C->isOne() && (C->getAPIntValue() | HighMask).isAllOnesValue()) { SDValue Neg1 = TLO.DAG.getAllOnesConstant(dl, VT); // Disable the nsw and nuw flags. We can no longer guarantee that we // won't wrap after simplification. Flags.setNoSignedWrap(false); Flags.setNoUnsignedWrap(false); SDValue NewOp = TLO.DAG.getNode(Op.getOpcode(), dl, VT, Op0, Neg1, Flags); return TLO.CombineTo(Op, NewOp); } LLVM_FALLTHROUGH; } default: if (Op.getOpcode() >= ISD::BUILTIN_OP_END) { if (SimplifyDemandedBitsForTargetNode(Op, DemandedBits, DemandedElts, Known, TLO, Depth)) return true; break; } // Just use computeKnownBits to compute output bits. Known = TLO.DAG.computeKnownBits(Op, DemandedElts, Depth); break; } // If we know the value of all of the demanded bits, return this as a // constant. if (DemandedBits.isSubsetOf(Known.Zero | Known.One)) { // Avoid folding to a constant if any OpaqueConstant is involved. const SDNode *N = Op.getNode(); for (SDNodeIterator I = SDNodeIterator::begin(N), E = SDNodeIterator::end(N); I != E; ++I) { SDNode *Op = *I; if (ConstantSDNode *C = dyn_cast(Op)) if (C->isOpaque()) return false; } // TODO: Handle float bits as well. if (VT.isInteger()) return TLO.CombineTo(Op, TLO.DAG.getConstant(Known.One, dl, VT)); } return false; } bool TargetLowering::SimplifyDemandedVectorElts(SDValue Op, const APInt &DemandedElts, APInt &KnownUndef, APInt &KnownZero, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; TargetLoweringOpt TLO(DAG, !DCI.isBeforeLegalize(), !DCI.isBeforeLegalizeOps()); bool Simplified = SimplifyDemandedVectorElts(Op, DemandedElts, KnownUndef, KnownZero, TLO); if (Simplified) { DCI.AddToWorklist(Op.getNode()); DCI.CommitTargetLoweringOpt(TLO); } return Simplified; } /// Given a vector binary operation and known undefined elements for each input /// operand, compute whether each element of the output is undefined. static APInt getKnownUndefForVectorBinop(SDValue BO, SelectionDAG &DAG, const APInt &UndefOp0, const APInt &UndefOp1) { EVT VT = BO.getValueType(); assert(DAG.getTargetLoweringInfo().isBinOp(BO.getOpcode()) && VT.isVector() && "Vector binop only"); EVT EltVT = VT.getVectorElementType(); unsigned NumElts = VT.getVectorNumElements(); assert(UndefOp0.getBitWidth() == NumElts && UndefOp1.getBitWidth() == NumElts && "Bad type for undef analysis"); auto getUndefOrConstantElt = [&](SDValue V, unsigned Index, const APInt &UndefVals) { if (UndefVals[Index]) return DAG.getUNDEF(EltVT); if (auto *BV = dyn_cast(V)) { // Try hard to make sure that the getNode() call is not creating temporary // nodes. Ignore opaque integers because they do not constant fold. SDValue Elt = BV->getOperand(Index); auto *C = dyn_cast(Elt); if (isa(Elt) || Elt.isUndef() || (C && !C->isOpaque())) return Elt; } return SDValue(); }; APInt KnownUndef = APInt::getNullValue(NumElts); for (unsigned i = 0; i != NumElts; ++i) { // If both inputs for this element are either constant or undef and match // the element type, compute the constant/undef result for this element of // the vector. // TODO: Ideally we would use FoldConstantArithmetic() here, but that does // not handle FP constants. The code within getNode() should be refactored // to avoid the danger of creating a bogus temporary node here. SDValue C0 = getUndefOrConstantElt(BO.getOperand(0), i, UndefOp0); SDValue C1 = getUndefOrConstantElt(BO.getOperand(1), i, UndefOp1); if (C0 && C1 && C0.getValueType() == EltVT && C1.getValueType() == EltVT) if (DAG.getNode(BO.getOpcode(), SDLoc(BO), EltVT, C0, C1).isUndef()) KnownUndef.setBit(i); } return KnownUndef; } bool TargetLowering::SimplifyDemandedVectorElts( SDValue Op, const APInt &OriginalDemandedElts, APInt &KnownUndef, APInt &KnownZero, TargetLoweringOpt &TLO, unsigned Depth, bool AssumeSingleUse) const { EVT VT = Op.getValueType(); APInt DemandedElts = OriginalDemandedElts; unsigned NumElts = DemandedElts.getBitWidth(); assert(VT.isVector() && "Expected vector op"); assert(VT.getVectorNumElements() == NumElts && "Mask size mismatches value type element count!"); KnownUndef = KnownZero = APInt::getNullValue(NumElts); // Undef operand. if (Op.isUndef()) { KnownUndef.setAllBits(); return false; } // If Op has other users, assume that all elements are needed. if (!Op.getNode()->hasOneUse() && !AssumeSingleUse) DemandedElts.setAllBits(); // Not demanding any elements from Op. if (DemandedElts == 0) { KnownUndef.setAllBits(); return TLO.CombineTo(Op, TLO.DAG.getUNDEF(VT)); } // Limit search depth. if (Depth >= SelectionDAG::MaxRecursionDepth) return false; SDLoc DL(Op); unsigned EltSizeInBits = VT.getScalarSizeInBits(); switch (Op.getOpcode()) { case ISD::SCALAR_TO_VECTOR: { if (!DemandedElts[0]) { KnownUndef.setAllBits(); return TLO.CombineTo(Op, TLO.DAG.getUNDEF(VT)); } KnownUndef.setHighBits(NumElts - 1); break; } case ISD::BITCAST: { SDValue Src = Op.getOperand(0); EVT SrcVT = Src.getValueType(); // We only handle vectors here. // TODO - investigate calling SimplifyDemandedBits/ComputeKnownBits? if (!SrcVT.isVector()) break; // Fast handling of 'identity' bitcasts. unsigned NumSrcElts = SrcVT.getVectorNumElements(); if (NumSrcElts == NumElts) return SimplifyDemandedVectorElts(Src, DemandedElts, KnownUndef, KnownZero, TLO, Depth + 1); APInt SrcZero, SrcUndef; APInt SrcDemandedElts = APInt::getNullValue(NumSrcElts); // Bitcast from 'large element' src vector to 'small element' vector, we // must demand a source element if any DemandedElt maps to it. if ((NumElts % NumSrcElts) == 0) { unsigned Scale = NumElts / NumSrcElts; for (unsigned i = 0; i != NumElts; ++i) if (DemandedElts[i]) SrcDemandedElts.setBit(i / Scale); if (SimplifyDemandedVectorElts(Src, SrcDemandedElts, SrcUndef, SrcZero, TLO, Depth + 1)) return true; // Try calling SimplifyDemandedBits, converting demanded elts to the bits // of the large element. // TODO - bigendian once we have test coverage. if (TLO.DAG.getDataLayout().isLittleEndian()) { unsigned SrcEltSizeInBits = SrcVT.getScalarSizeInBits(); APInt SrcDemandedBits = APInt::getNullValue(SrcEltSizeInBits); for (unsigned i = 0; i != NumElts; ++i) if (DemandedElts[i]) { unsigned Ofs = (i % Scale) * EltSizeInBits; SrcDemandedBits.setBits(Ofs, Ofs + EltSizeInBits); } KnownBits Known; if (SimplifyDemandedBits(Src, SrcDemandedBits, Known, TLO, Depth + 1)) return true; } // If the src element is zero/undef then all the output elements will be - // only demanded elements are guaranteed to be correct. for (unsigned i = 0; i != NumSrcElts; ++i) { if (SrcDemandedElts[i]) { if (SrcZero[i]) KnownZero.setBits(i * Scale, (i + 1) * Scale); if (SrcUndef[i]) KnownUndef.setBits(i * Scale, (i + 1) * Scale); } } } // Bitcast from 'small element' src vector to 'large element' vector, we // demand all smaller source elements covered by the larger demanded element // of this vector. if ((NumSrcElts % NumElts) == 0) { unsigned Scale = NumSrcElts / NumElts; for (unsigned i = 0; i != NumElts; ++i) if (DemandedElts[i]) SrcDemandedElts.setBits(i * Scale, (i + 1) * Scale); if (SimplifyDemandedVectorElts(Src, SrcDemandedElts, SrcUndef, SrcZero, TLO, Depth + 1)) return true; // If all the src elements covering an output element are zero/undef, then // the output element will be as well, assuming it was demanded. for (unsigned i = 0; i != NumElts; ++i) { if (DemandedElts[i]) { if (SrcZero.extractBits(Scale, i * Scale).isAllOnesValue()) KnownZero.setBit(i); if (SrcUndef.extractBits(Scale, i * Scale).isAllOnesValue()) KnownUndef.setBit(i); } } } break; } case ISD::BUILD_VECTOR: { // Check all elements and simplify any unused elements with UNDEF. if (!DemandedElts.isAllOnesValue()) { // Don't simplify BROADCASTS. if (llvm::any_of(Op->op_values(), [&](SDValue Elt) { return Op.getOperand(0) != Elt; })) { SmallVector Ops(Op->op_begin(), Op->op_end()); bool Updated = false; for (unsigned i = 0; i != NumElts; ++i) { if (!DemandedElts[i] && !Ops[i].isUndef()) { Ops[i] = TLO.DAG.getUNDEF(Ops[0].getValueType()); KnownUndef.setBit(i); Updated = true; } } if (Updated) return TLO.CombineTo(Op, TLO.DAG.getBuildVector(VT, DL, Ops)); } } for (unsigned i = 0; i != NumElts; ++i) { SDValue SrcOp = Op.getOperand(i); if (SrcOp.isUndef()) { KnownUndef.setBit(i); } else if (EltSizeInBits == SrcOp.getScalarValueSizeInBits() && (isNullConstant(SrcOp) || isNullFPConstant(SrcOp))) { KnownZero.setBit(i); } } break; } case ISD::CONCAT_VECTORS: { EVT SubVT = Op.getOperand(0).getValueType(); unsigned NumSubVecs = Op.getNumOperands(); unsigned NumSubElts = SubVT.getVectorNumElements(); for (unsigned i = 0; i != NumSubVecs; ++i) { SDValue SubOp = Op.getOperand(i); APInt SubElts = DemandedElts.extractBits(NumSubElts, i * NumSubElts); APInt SubUndef, SubZero; if (SimplifyDemandedVectorElts(SubOp, SubElts, SubUndef, SubZero, TLO, Depth + 1)) return true; KnownUndef.insertBits(SubUndef, i * NumSubElts); KnownZero.insertBits(SubZero, i * NumSubElts); } break; } case ISD::INSERT_SUBVECTOR: { if (!isa(Op.getOperand(2))) break; SDValue Base = Op.getOperand(0); SDValue Sub = Op.getOperand(1); EVT SubVT = Sub.getValueType(); unsigned NumSubElts = SubVT.getVectorNumElements(); const APInt &Idx = Op.getConstantOperandAPInt(2); if (Idx.ugt(NumElts - NumSubElts)) break; unsigned SubIdx = Idx.getZExtValue(); APInt SubElts = DemandedElts.extractBits(NumSubElts, SubIdx); APInt SubUndef, SubZero; if (SimplifyDemandedVectorElts(Sub, SubElts, SubUndef, SubZero, TLO, Depth + 1)) return true; APInt BaseElts = DemandedElts; BaseElts.insertBits(APInt::getNullValue(NumSubElts), SubIdx); // If none of the base operand elements are demanded, replace it with undef. if (!BaseElts && !Base.isUndef()) return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::INSERT_SUBVECTOR, DL, VT, TLO.DAG.getUNDEF(VT), Op.getOperand(1), Op.getOperand(2))); if (SimplifyDemandedVectorElts(Base, BaseElts, KnownUndef, KnownZero, TLO, Depth + 1)) return true; KnownUndef.insertBits(SubUndef, SubIdx); KnownZero.insertBits(SubZero, SubIdx); break; } case ISD::EXTRACT_SUBVECTOR: { SDValue Src = Op.getOperand(0); ConstantSDNode *SubIdx = dyn_cast(Op.getOperand(1)); unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); if (SubIdx && SubIdx->getAPIntValue().ule(NumSrcElts - NumElts)) { // Offset the demanded elts by the subvector index. uint64_t Idx = SubIdx->getZExtValue(); APInt SrcElts = DemandedElts.zextOrSelf(NumSrcElts).shl(Idx); APInt SrcUndef, SrcZero; if (SimplifyDemandedVectorElts(Src, SrcElts, SrcUndef, SrcZero, TLO, Depth + 1)) return true; KnownUndef = SrcUndef.extractBits(NumElts, Idx); KnownZero = SrcZero.extractBits(NumElts, Idx); } break; } case ISD::INSERT_VECTOR_ELT: { SDValue Vec = Op.getOperand(0); SDValue Scl = Op.getOperand(1); auto *CIdx = dyn_cast(Op.getOperand(2)); // For a legal, constant insertion index, if we don't need this insertion // then strip it, else remove it from the demanded elts. if (CIdx && CIdx->getAPIntValue().ult(NumElts)) { unsigned Idx = CIdx->getZExtValue(); if (!DemandedElts[Idx]) return TLO.CombineTo(Op, Vec); APInt DemandedVecElts(DemandedElts); DemandedVecElts.clearBit(Idx); if (SimplifyDemandedVectorElts(Vec, DemandedVecElts, KnownUndef, KnownZero, TLO, Depth + 1)) return true; KnownUndef.clearBit(Idx); if (Scl.isUndef()) KnownUndef.setBit(Idx); KnownZero.clearBit(Idx); if (isNullConstant(Scl) || isNullFPConstant(Scl)) KnownZero.setBit(Idx); break; } APInt VecUndef, VecZero; if (SimplifyDemandedVectorElts(Vec, DemandedElts, VecUndef, VecZero, TLO, Depth + 1)) return true; // Without knowing the insertion index we can't set KnownUndef/KnownZero. break; } case ISD::VSELECT: { // Try to transform the select condition based on the current demanded // elements. // TODO: If a condition element is undef, we can choose from one arm of the // select (and if one arm is undef, then we can propagate that to the // result). // TODO - add support for constant vselect masks (see IR version of this). APInt UnusedUndef, UnusedZero; if (SimplifyDemandedVectorElts(Op.getOperand(0), DemandedElts, UnusedUndef, UnusedZero, TLO, Depth + 1)) return true; // See if we can simplify either vselect operand. APInt DemandedLHS(DemandedElts); APInt DemandedRHS(DemandedElts); APInt UndefLHS, ZeroLHS; APInt UndefRHS, ZeroRHS; if (SimplifyDemandedVectorElts(Op.getOperand(1), DemandedLHS, UndefLHS, ZeroLHS, TLO, Depth + 1)) return true; if (SimplifyDemandedVectorElts(Op.getOperand(2), DemandedRHS, UndefRHS, ZeroRHS, TLO, Depth + 1)) return true; KnownUndef = UndefLHS & UndefRHS; KnownZero = ZeroLHS & ZeroRHS; break; } case ISD::VECTOR_SHUFFLE: { ArrayRef ShuffleMask = cast(Op)->getMask(); // Collect demanded elements from shuffle operands.. APInt DemandedLHS(NumElts, 0); APInt DemandedRHS(NumElts, 0); for (unsigned i = 0; i != NumElts; ++i) { int M = ShuffleMask[i]; if (M < 0 || !DemandedElts[i]) continue; assert(0 <= M && M < (int)(2 * NumElts) && "Shuffle index out of range"); if (M < (int)NumElts) DemandedLHS.setBit(M); else DemandedRHS.setBit(M - NumElts); } // See if we can simplify either shuffle operand. APInt UndefLHS, ZeroLHS; APInt UndefRHS, ZeroRHS; if (SimplifyDemandedVectorElts(Op.getOperand(0), DemandedLHS, UndefLHS, ZeroLHS, TLO, Depth + 1)) return true; if (SimplifyDemandedVectorElts(Op.getOperand(1), DemandedRHS, UndefRHS, ZeroRHS, TLO, Depth + 1)) return true; // Simplify mask using undef elements from LHS/RHS. bool Updated = false; bool IdentityLHS = true, IdentityRHS = true; SmallVector NewMask(ShuffleMask.begin(), ShuffleMask.end()); for (unsigned i = 0; i != NumElts; ++i) { int &M = NewMask[i]; if (M < 0) continue; if (!DemandedElts[i] || (M < (int)NumElts && UndefLHS[M]) || (M >= (int)NumElts && UndefRHS[M - NumElts])) { Updated = true; M = -1; } IdentityLHS &= (M < 0) || (M == (int)i); IdentityRHS &= (M < 0) || ((M - NumElts) == i); } // Update legal shuffle masks based on demanded elements if it won't reduce // to Identity which can cause premature removal of the shuffle mask. if (Updated && !IdentityLHS && !IdentityRHS && !TLO.LegalOps) { SDValue LegalShuffle = buildLegalVectorShuffle(VT, DL, Op.getOperand(0), Op.getOperand(1), NewMask, TLO.DAG); if (LegalShuffle) return TLO.CombineTo(Op, LegalShuffle); } // Propagate undef/zero elements from LHS/RHS. for (unsigned i = 0; i != NumElts; ++i) { int M = ShuffleMask[i]; if (M < 0) { KnownUndef.setBit(i); } else if (M < (int)NumElts) { if (UndefLHS[M]) KnownUndef.setBit(i); if (ZeroLHS[M]) KnownZero.setBit(i); } else { if (UndefRHS[M - NumElts]) KnownUndef.setBit(i); if (ZeroRHS[M - NumElts]) KnownZero.setBit(i); } } break; } case ISD::ANY_EXTEND_VECTOR_INREG: case ISD::SIGN_EXTEND_VECTOR_INREG: case ISD::ZERO_EXTEND_VECTOR_INREG: { APInt SrcUndef, SrcZero; SDValue Src = Op.getOperand(0); unsigned NumSrcElts = Src.getValueType().getVectorNumElements(); APInt DemandedSrcElts = DemandedElts.zextOrSelf(NumSrcElts); if (SimplifyDemandedVectorElts(Src, DemandedSrcElts, SrcUndef, SrcZero, TLO, Depth + 1)) return true; KnownZero = SrcZero.zextOrTrunc(NumElts); KnownUndef = SrcUndef.zextOrTrunc(NumElts); if (Op.getOpcode() == ISD::ANY_EXTEND_VECTOR_INREG && Op.getValueSizeInBits() == Src.getValueSizeInBits() && DemandedSrcElts == 1 && TLO.DAG.getDataLayout().isLittleEndian()) { // aext - if we just need the bottom element then we can bitcast. return TLO.CombineTo(Op, TLO.DAG.getBitcast(VT, Src)); } if (Op.getOpcode() == ISD::ZERO_EXTEND_VECTOR_INREG) { // zext(undef) upper bits are guaranteed to be zero. if (DemandedElts.isSubsetOf(KnownUndef)) return TLO.CombineTo(Op, TLO.DAG.getConstant(0, SDLoc(Op), VT)); KnownUndef.clearAllBits(); } break; } // TODO: There are more binop opcodes that could be handled here - MUL, MIN, // MAX, saturated math, etc. case ISD::OR: case ISD::XOR: case ISD::ADD: case ISD::SUB: case ISD::FADD: case ISD::FSUB: case ISD::FMUL: case ISD::FDIV: case ISD::FREM: { APInt UndefRHS, ZeroRHS; if (SimplifyDemandedVectorElts(Op.getOperand(1), DemandedElts, UndefRHS, ZeroRHS, TLO, Depth + 1)) return true; APInt UndefLHS, ZeroLHS; if (SimplifyDemandedVectorElts(Op.getOperand(0), DemandedElts, UndefLHS, ZeroLHS, TLO, Depth + 1)) return true; KnownZero = ZeroLHS & ZeroRHS; KnownUndef = getKnownUndefForVectorBinop(Op, TLO.DAG, UndefLHS, UndefRHS); break; } case ISD::SHL: case ISD::SRL: case ISD::SRA: case ISD::ROTL: case ISD::ROTR: { APInt UndefRHS, ZeroRHS; if (SimplifyDemandedVectorElts(Op.getOperand(1), DemandedElts, UndefRHS, ZeroRHS, TLO, Depth + 1)) return true; APInt UndefLHS, ZeroLHS; if (SimplifyDemandedVectorElts(Op.getOperand(0), DemandedElts, UndefLHS, ZeroLHS, TLO, Depth + 1)) return true; KnownZero = ZeroLHS; KnownUndef = UndefLHS & UndefRHS; // TODO: use getKnownUndefForVectorBinop? break; } case ISD::MUL: case ISD::AND: { APInt SrcUndef, SrcZero; if (SimplifyDemandedVectorElts(Op.getOperand(1), DemandedElts, SrcUndef, SrcZero, TLO, Depth + 1)) return true; if (SimplifyDemandedVectorElts(Op.getOperand(0), DemandedElts, KnownUndef, KnownZero, TLO, Depth + 1)) return true; // If either side has a zero element, then the result element is zero, even // if the other is an UNDEF. // TODO: Extend getKnownUndefForVectorBinop to also deal with known zeros // and then handle 'and' nodes with the rest of the binop opcodes. KnownZero |= SrcZero; KnownUndef &= SrcUndef; KnownUndef &= ~KnownZero; break; } case ISD::TRUNCATE: case ISD::SIGN_EXTEND: case ISD::ZERO_EXTEND: if (SimplifyDemandedVectorElts(Op.getOperand(0), DemandedElts, KnownUndef, KnownZero, TLO, Depth + 1)) return true; if (Op.getOpcode() == ISD::ZERO_EXTEND) { // zext(undef) upper bits are guaranteed to be zero. if (DemandedElts.isSubsetOf(KnownUndef)) return TLO.CombineTo(Op, TLO.DAG.getConstant(0, SDLoc(Op), VT)); KnownUndef.clearAllBits(); } break; default: { if (Op.getOpcode() >= ISD::BUILTIN_OP_END) { if (SimplifyDemandedVectorEltsForTargetNode(Op, DemandedElts, KnownUndef, KnownZero, TLO, Depth)) return true; } else { KnownBits Known; APInt DemandedBits = APInt::getAllOnesValue(EltSizeInBits); if (SimplifyDemandedBits(Op, DemandedBits, OriginalDemandedElts, Known, TLO, Depth, AssumeSingleUse)) return true; } break; } } assert((KnownUndef & KnownZero) == 0 && "Elements flagged as undef AND zero"); // Constant fold all undef cases. // TODO: Handle zero cases as well. if (DemandedElts.isSubsetOf(KnownUndef)) return TLO.CombineTo(Op, TLO.DAG.getUNDEF(VT)); return false; } /// Determine which of the bits specified in Mask are known to be either zero or /// one and return them in the Known. void TargetLowering::computeKnownBitsForTargetNode(const SDValue Op, KnownBits &Known, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const { assert((Op.getOpcode() >= ISD::BUILTIN_OP_END || Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || Op.getOpcode() == ISD::INTRINSIC_VOID) && "Should use MaskedValueIsZero if you don't know whether Op" " is a target node!"); Known.resetAll(); } void TargetLowering::computeKnownBitsForTargetInstr( GISelKnownBits &Analysis, Register R, KnownBits &Known, const APInt &DemandedElts, const MachineRegisterInfo &MRI, unsigned Depth) const { Known.resetAll(); } void TargetLowering::computeKnownBitsForFrameIndex(const SDValue Op, KnownBits &Known, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const { assert(isa(Op) && "expected FrameIndex"); if (unsigned Align = DAG.InferPtrAlignment(Op)) { // The low bits are known zero if the pointer is aligned. Known.Zero.setLowBits(Log2_32(Align)); } } /// This method can be implemented by targets that want to expose additional /// information about sign bits to the DAG Combiner. unsigned TargetLowering::ComputeNumSignBitsForTargetNode(SDValue Op, const APInt &, const SelectionDAG &, unsigned Depth) const { assert((Op.getOpcode() >= ISD::BUILTIN_OP_END || Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || Op.getOpcode() == ISD::INTRINSIC_VOID) && "Should use ComputeNumSignBits if you don't know whether Op" " is a target node!"); return 1; } bool TargetLowering::SimplifyDemandedVectorEltsForTargetNode( SDValue Op, const APInt &DemandedElts, APInt &KnownUndef, APInt &KnownZero, TargetLoweringOpt &TLO, unsigned Depth) const { assert((Op.getOpcode() >= ISD::BUILTIN_OP_END || Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || Op.getOpcode() == ISD::INTRINSIC_VOID) && "Should use SimplifyDemandedVectorElts if you don't know whether Op" " is a target node!"); return false; } bool TargetLowering::SimplifyDemandedBitsForTargetNode( SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, KnownBits &Known, TargetLoweringOpt &TLO, unsigned Depth) const { assert((Op.getOpcode() >= ISD::BUILTIN_OP_END || Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || Op.getOpcode() == ISD::INTRINSIC_VOID) && "Should use SimplifyDemandedBits if you don't know whether Op" " is a target node!"); computeKnownBitsForTargetNode(Op, Known, DemandedElts, TLO.DAG, Depth); return false; } SDValue TargetLowering::SimplifyMultipleUseDemandedBitsForTargetNode( SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts, SelectionDAG &DAG, unsigned Depth) const { assert( (Op.getOpcode() >= ISD::BUILTIN_OP_END || Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || Op.getOpcode() == ISD::INTRINSIC_VOID) && "Should use SimplifyMultipleUseDemandedBits if you don't know whether Op" " is a target node!"); return SDValue(); } SDValue TargetLowering::buildLegalVectorShuffle(EVT VT, const SDLoc &DL, SDValue N0, SDValue N1, MutableArrayRef Mask, SelectionDAG &DAG) const { bool LegalMask = isShuffleMaskLegal(Mask, VT); if (!LegalMask) { std::swap(N0, N1); ShuffleVectorSDNode::commuteMask(Mask); LegalMask = isShuffleMaskLegal(Mask, VT); } if (!LegalMask) return SDValue(); return DAG.getVectorShuffle(VT, DL, N0, N1, Mask); } const Constant *TargetLowering::getTargetConstantFromLoad(LoadSDNode*) const { return nullptr; } bool TargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, const SelectionDAG &DAG, bool SNaN, unsigned Depth) const { assert((Op.getOpcode() >= ISD::BUILTIN_OP_END || Op.getOpcode() == ISD::INTRINSIC_WO_CHAIN || Op.getOpcode() == ISD::INTRINSIC_W_CHAIN || Op.getOpcode() == ISD::INTRINSIC_VOID) && "Should use isKnownNeverNaN if you don't know whether Op" " is a target node!"); return false; } // FIXME: Ideally, this would use ISD::isConstantSplatVector(), but that must // work with truncating build vectors and vectors with elements of less than // 8 bits. bool TargetLowering::isConstTrueVal(const SDNode *N) const { if (!N) return false; APInt CVal; if (auto *CN = dyn_cast(N)) { CVal = CN->getAPIntValue(); } else if (auto *BV = dyn_cast(N)) { auto *CN = BV->getConstantSplatNode(); if (!CN) return false; // If this is a truncating build vector, truncate the splat value. // Otherwise, we may fail to match the expected values below. unsigned BVEltWidth = BV->getValueType(0).getScalarSizeInBits(); CVal = CN->getAPIntValue(); if (BVEltWidth < CVal.getBitWidth()) CVal = CVal.trunc(BVEltWidth); } else { return false; } switch (getBooleanContents(N->getValueType(0))) { case UndefinedBooleanContent: return CVal[0]; case ZeroOrOneBooleanContent: return CVal.isOneValue(); case ZeroOrNegativeOneBooleanContent: return CVal.isAllOnesValue(); } llvm_unreachable("Invalid boolean contents"); } bool TargetLowering::isConstFalseVal(const SDNode *N) const { if (!N) return false; const ConstantSDNode *CN = dyn_cast(N); if (!CN) { const BuildVectorSDNode *BV = dyn_cast(N); if (!BV) return false; // Only interested in constant splats, we don't care about undef // elements in identifying boolean constants and getConstantSplatNode // returns NULL if all ops are undef; CN = BV->getConstantSplatNode(); if (!CN) return false; } if (getBooleanContents(N->getValueType(0)) == UndefinedBooleanContent) return !CN->getAPIntValue()[0]; return CN->isNullValue(); } bool TargetLowering::isExtendedTrueVal(const ConstantSDNode *N, EVT VT, bool SExt) const { if (VT == MVT::i1) return N->isOne(); TargetLowering::BooleanContent Cnt = getBooleanContents(VT); switch (Cnt) { case TargetLowering::ZeroOrOneBooleanContent: // An extended value of 1 is always true, unless its original type is i1, // in which case it will be sign extended to -1. return (N->isOne() && !SExt) || (SExt && (N->getValueType(0) != MVT::i1)); case TargetLowering::UndefinedBooleanContent: case TargetLowering::ZeroOrNegativeOneBooleanContent: return N->isAllOnesValue() && SExt; } llvm_unreachable("Unexpected enumeration."); } /// This helper function of SimplifySetCC tries to optimize the comparison when /// either operand of the SetCC node is a bitwise-and instruction. SDValue TargetLowering::foldSetCCWithAnd(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond, const SDLoc &DL, DAGCombinerInfo &DCI) const { // Match these patterns in any of their permutations: // (X & Y) == Y // (X & Y) != Y if (N1.getOpcode() == ISD::AND && N0.getOpcode() != ISD::AND) std::swap(N0, N1); EVT OpVT = N0.getValueType(); if (N0.getOpcode() != ISD::AND || !OpVT.isInteger() || (Cond != ISD::SETEQ && Cond != ISD::SETNE)) return SDValue(); SDValue X, Y; if (N0.getOperand(0) == N1) { X = N0.getOperand(1); Y = N0.getOperand(0); } else if (N0.getOperand(1) == N1) { X = N0.getOperand(0); Y = N0.getOperand(1); } else { return SDValue(); } SelectionDAG &DAG = DCI.DAG; SDValue Zero = DAG.getConstant(0, DL, OpVT); if (DAG.isKnownToBeAPowerOfTwo(Y)) { // Simplify X & Y == Y to X & Y != 0 if Y has exactly one bit set. // Note that where Y is variable and is known to have at most one bit set // (for example, if it is Z & 1) we cannot do this; the expressions are not // equivalent when Y == 0. assert(OpVT.isInteger()); Cond = ISD::getSetCCInverse(Cond, OpVT); if (DCI.isBeforeLegalizeOps() || isCondCodeLegal(Cond, N0.getSimpleValueType())) return DAG.getSetCC(DL, VT, N0, Zero, Cond); } else if (N0.hasOneUse() && hasAndNotCompare(Y)) { // If the target supports an 'and-not' or 'and-complement' logic operation, // try to use that to make a comparison operation more efficient. // But don't do this transform if the mask is a single bit because there are // more efficient ways to deal with that case (for example, 'bt' on x86 or // 'rlwinm' on PPC). // Bail out if the compare operand that we want to turn into a zero is // already a zero (otherwise, infinite loop). auto *YConst = dyn_cast(Y); if (YConst && YConst->isNullValue()) return SDValue(); // Transform this into: ~X & Y == 0. SDValue NotX = DAG.getNOT(SDLoc(X), X, OpVT); SDValue NewAnd = DAG.getNode(ISD::AND, SDLoc(N0), OpVT, NotX, Y); return DAG.getSetCC(DL, VT, NewAnd, Zero, Cond); } return SDValue(); } /// There are multiple IR patterns that could be checking whether certain /// truncation of a signed number would be lossy or not. The pattern which is /// best at IR level, may not lower optimally. Thus, we want to unfold it. /// We are looking for the following pattern: (KeptBits is a constant) /// (add %x, (1 << (KeptBits-1))) srccond (1 << KeptBits) /// KeptBits won't be bitwidth(x), that will be constant-folded to true/false. /// KeptBits also can't be 1, that would have been folded to %x dstcond 0 /// We will unfold it into the natural trunc+sext pattern: /// ((%x << C) a>> C) dstcond %x /// Where C = bitwidth(x) - KeptBits and C u< bitwidth(x) SDValue TargetLowering::optimizeSetCCOfSignedTruncationCheck( EVT SCCVT, SDValue N0, SDValue N1, ISD::CondCode Cond, DAGCombinerInfo &DCI, const SDLoc &DL) const { // We must be comparing with a constant. ConstantSDNode *C1; if (!(C1 = dyn_cast(N1))) return SDValue(); // N0 should be: add %x, (1 << (KeptBits-1)) if (N0->getOpcode() != ISD::ADD) return SDValue(); // And we must be 'add'ing a constant. ConstantSDNode *C01; if (!(C01 = dyn_cast(N0->getOperand(1)))) return SDValue(); SDValue X = N0->getOperand(0); EVT XVT = X.getValueType(); // Validate constants ... APInt I1 = C1->getAPIntValue(); ISD::CondCode NewCond; if (Cond == ISD::CondCode::SETULT) { NewCond = ISD::CondCode::SETEQ; } else if (Cond == ISD::CondCode::SETULE) { NewCond = ISD::CondCode::SETEQ; // But need to 'canonicalize' the constant. I1 += 1; } else if (Cond == ISD::CondCode::SETUGT) { NewCond = ISD::CondCode::SETNE; // But need to 'canonicalize' the constant. I1 += 1; } else if (Cond == ISD::CondCode::SETUGE) { NewCond = ISD::CondCode::SETNE; } else return SDValue(); APInt I01 = C01->getAPIntValue(); auto checkConstants = [&I1, &I01]() -> bool { // Both of them must be power-of-two, and the constant from setcc is bigger. return I1.ugt(I01) && I1.isPowerOf2() && I01.isPowerOf2(); }; if (checkConstants()) { // Great, e.g. got icmp ult i16 (add i16 %x, 128), 256 } else { // What if we invert constants? (and the target predicate) I1.negate(); I01.negate(); assert(XVT.isInteger()); NewCond = getSetCCInverse(NewCond, XVT); if (!checkConstants()) return SDValue(); // Great, e.g. got icmp uge i16 (add i16 %x, -128), -256 } // They are power-of-two, so which bit is set? const unsigned KeptBits = I1.logBase2(); const unsigned KeptBitsMinusOne = I01.logBase2(); // Magic! if (KeptBits != (KeptBitsMinusOne + 1)) return SDValue(); assert(KeptBits > 0 && KeptBits < XVT.getSizeInBits() && "unreachable"); // We don't want to do this in every single case. SelectionDAG &DAG = DCI.DAG; if (!DAG.getTargetLoweringInfo().shouldTransformSignedTruncationCheck( XVT, KeptBits)) return SDValue(); const unsigned MaskedBits = XVT.getSizeInBits() - KeptBits; assert(MaskedBits > 0 && MaskedBits < XVT.getSizeInBits() && "unreachable"); // Unfold into: ((%x << C) a>> C) cond %x // Where 'cond' will be either 'eq' or 'ne'. SDValue ShiftAmt = DAG.getConstant(MaskedBits, DL, XVT); SDValue T0 = DAG.getNode(ISD::SHL, DL, XVT, X, ShiftAmt); SDValue T1 = DAG.getNode(ISD::SRA, DL, XVT, T0, ShiftAmt); SDValue T2 = DAG.getSetCC(DL, SCCVT, T1, X, NewCond); return T2; } // (X & (C l>>/<< Y)) ==/!= 0 --> ((X <> Y) & C) ==/!= 0 SDValue TargetLowering::optimizeSetCCByHoistingAndByConstFromLogicalShift( EVT SCCVT, SDValue N0, SDValue N1C, ISD::CondCode Cond, DAGCombinerInfo &DCI, const SDLoc &DL) const { assert(isConstOrConstSplat(N1C) && isConstOrConstSplat(N1C)->getAPIntValue().isNullValue() && "Should be a comparison with 0."); assert((Cond == ISD::SETEQ || Cond == ISD::SETNE) && "Valid only for [in]equality comparisons."); unsigned NewShiftOpcode; SDValue X, C, Y; SelectionDAG &DAG = DCI.DAG; const TargetLowering &TLI = DAG.getTargetLoweringInfo(); // Look for '(C l>>/<< Y)'. auto Match = [&NewShiftOpcode, &X, &C, &Y, &TLI, &DAG](SDValue V) { // The shift should be one-use. if (!V.hasOneUse()) return false; unsigned OldShiftOpcode = V.getOpcode(); switch (OldShiftOpcode) { case ISD::SHL: NewShiftOpcode = ISD::SRL; break; case ISD::SRL: NewShiftOpcode = ISD::SHL; break; default: return false; // must be a logical shift. } // We should be shifting a constant. // FIXME: best to use isConstantOrConstantVector(). C = V.getOperand(0); ConstantSDNode *CC = isConstOrConstSplat(C, /*AllowUndefs=*/true, /*AllowTruncation=*/true); if (!CC) return false; Y = V.getOperand(1); ConstantSDNode *XC = isConstOrConstSplat(X, /*AllowUndefs=*/true, /*AllowTruncation=*/true); return TLI.shouldProduceAndByConstByHoistingConstFromShiftsLHSOfAnd( X, XC, CC, Y, OldShiftOpcode, NewShiftOpcode, DAG); }; // LHS of comparison should be an one-use 'and'. if (N0.getOpcode() != ISD::AND || !N0.hasOneUse()) return SDValue(); X = N0.getOperand(0); SDValue Mask = N0.getOperand(1); // 'and' is commutative! if (!Match(Mask)) { std::swap(X, Mask); if (!Match(Mask)) return SDValue(); } EVT VT = X.getValueType(); // Produce: // ((X 'OppositeShiftOpcode' Y) & C) Cond 0 SDValue T0 = DAG.getNode(NewShiftOpcode, DL, VT, X, Y); SDValue T1 = DAG.getNode(ISD::AND, DL, VT, T0, C); SDValue T2 = DAG.getSetCC(DL, SCCVT, T1, N1C, Cond); return T2; } /// Try to fold an equality comparison with a {add/sub/xor} binary operation as /// the 1st operand (N0). Callers are expected to swap the N0/N1 parameters to /// handle the commuted versions of these patterns. SDValue TargetLowering::foldSetCCWithBinOp(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond, const SDLoc &DL, DAGCombinerInfo &DCI) const { unsigned BOpcode = N0.getOpcode(); assert((BOpcode == ISD::ADD || BOpcode == ISD::SUB || BOpcode == ISD::XOR) && "Unexpected binop"); assert((Cond == ISD::SETEQ || Cond == ISD::SETNE) && "Unexpected condcode"); // (X + Y) == X --> Y == 0 // (X - Y) == X --> Y == 0 // (X ^ Y) == X --> Y == 0 SelectionDAG &DAG = DCI.DAG; EVT OpVT = N0.getValueType(); SDValue X = N0.getOperand(0); SDValue Y = N0.getOperand(1); if (X == N1) return DAG.getSetCC(DL, VT, Y, DAG.getConstant(0, DL, OpVT), Cond); if (Y != N1) return SDValue(); // (X + Y) == Y --> X == 0 // (X ^ Y) == Y --> X == 0 if (BOpcode == ISD::ADD || BOpcode == ISD::XOR) return DAG.getSetCC(DL, VT, X, DAG.getConstant(0, DL, OpVT), Cond); // The shift would not be valid if the operands are boolean (i1). if (!N0.hasOneUse() || OpVT.getScalarSizeInBits() == 1) return SDValue(); // (X - Y) == Y --> X == Y << 1 EVT ShiftVT = getShiftAmountTy(OpVT, DAG.getDataLayout(), !DCI.isBeforeLegalize()); SDValue One = DAG.getConstant(1, DL, ShiftVT); SDValue YShl1 = DAG.getNode(ISD::SHL, DL, N1.getValueType(), Y, One); if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(YShl1.getNode()); return DAG.getSetCC(DL, VT, X, YShl1, Cond); } /// Try to simplify a setcc built with the specified operands and cc. If it is /// unable to simplify it, return a null SDValue. SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, ISD::CondCode Cond, bool foldBooleans, DAGCombinerInfo &DCI, const SDLoc &dl) const { SelectionDAG &DAG = DCI.DAG; const DataLayout &Layout = DAG.getDataLayout(); EVT OpVT = N0.getValueType(); // Constant fold or commute setcc. if (SDValue Fold = DAG.FoldSetCC(VT, N0, N1, Cond, dl)) return Fold; // Ensure that the constant occurs on the RHS and fold constant comparisons. // TODO: Handle non-splat vector constants. All undef causes trouble. ISD::CondCode SwappedCC = ISD::getSetCCSwappedOperands(Cond); if (isConstOrConstSplat(N0) && (DCI.isBeforeLegalizeOps() || isCondCodeLegal(SwappedCC, N0.getSimpleValueType()))) return DAG.getSetCC(dl, VT, N1, N0, SwappedCC); // If we have a subtract with the same 2 non-constant operands as this setcc // -- but in reverse order -- then try to commute the operands of this setcc // to match. A matching pair of setcc (cmp) and sub may be combined into 1 // instruction on some targets. if (!isConstOrConstSplat(N0) && !isConstOrConstSplat(N1) && (DCI.isBeforeLegalizeOps() || isCondCodeLegal(SwappedCC, N0.getSimpleValueType())) && DAG.getNodeIfExists(ISD::SUB, DAG.getVTList(OpVT), { N1, N0 } ) && !DAG.getNodeIfExists(ISD::SUB, DAG.getVTList(OpVT), { N0, N1 } )) return DAG.getSetCC(dl, VT, N1, N0, SwappedCC); if (auto *N1C = dyn_cast(N1.getNode())) { const APInt &C1 = N1C->getAPIntValue(); // If the LHS is '(srl (ctlz x), 5)', the RHS is 0/1, and this is an // equality comparison, then we're just comparing whether X itself is // zero. if (N0.getOpcode() == ISD::SRL && (C1.isNullValue() || C1.isOneValue()) && N0.getOperand(0).getOpcode() == ISD::CTLZ && N0.getOperand(1).getOpcode() == ISD::Constant) { const APInt &ShAmt = N0.getConstantOperandAPInt(1); if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) && ShAmt == Log2_32(N0.getValueSizeInBits())) { if ((C1 == 0) == (Cond == ISD::SETEQ)) { // (srl (ctlz x), 5) == 0 -> X != 0 // (srl (ctlz x), 5) != 1 -> X != 0 Cond = ISD::SETNE; } else { // (srl (ctlz x), 5) != 0 -> X == 0 // (srl (ctlz x), 5) == 1 -> X == 0 Cond = ISD::SETEQ; } SDValue Zero = DAG.getConstant(0, dl, N0.getValueType()); return DAG.getSetCC(dl, VT, N0.getOperand(0).getOperand(0), Zero, Cond); } } SDValue CTPOP = N0; // Look through truncs that don't change the value of a ctpop. if (N0.hasOneUse() && N0.getOpcode() == ISD::TRUNCATE) CTPOP = N0.getOperand(0); if (CTPOP.hasOneUse() && CTPOP.getOpcode() == ISD::CTPOP && (N0 == CTPOP || N0.getValueSizeInBits() > Log2_32_Ceil(CTPOP.getValueSizeInBits()))) { EVT CTVT = CTPOP.getValueType(); SDValue CTOp = CTPOP.getOperand(0); // (ctpop x) u< 2 -> (x & x-1) == 0 // (ctpop x) u> 1 -> (x & x-1) != 0 if ((Cond == ISD::SETULT && C1 == 2) || (Cond == ISD::SETUGT && C1 == 1)){ SDValue NegOne = DAG.getAllOnesConstant(dl, CTVT); SDValue Add = DAG.getNode(ISD::ADD, dl, CTVT, CTOp, NegOne); SDValue And = DAG.getNode(ISD::AND, dl, CTVT, CTOp, Add); ISD::CondCode CC = Cond == ISD::SETULT ? ISD::SETEQ : ISD::SETNE; return DAG.getSetCC(dl, VT, And, DAG.getConstant(0, dl, CTVT), CC); } // If ctpop is not supported, expand a power-of-2 comparison based on it. if (C1 == 1 && !isOperationLegalOrCustom(ISD::CTPOP, CTVT) && (Cond == ISD::SETEQ || Cond == ISD::SETNE)) { // (ctpop x) == 1 --> (x != 0) && ((x & x-1) == 0) // (ctpop x) != 1 --> (x == 0) || ((x & x-1) != 0) SDValue Zero = DAG.getConstant(0, dl, CTVT); SDValue NegOne = DAG.getAllOnesConstant(dl, CTVT); assert(CTVT.isInteger()); ISD::CondCode InvCond = ISD::getSetCCInverse(Cond, CTVT); SDValue Add = DAG.getNode(ISD::ADD, dl, CTVT, CTOp, NegOne); SDValue And = DAG.getNode(ISD::AND, dl, CTVT, CTOp, Add); SDValue LHS = DAG.getSetCC(dl, VT, CTOp, Zero, InvCond); SDValue RHS = DAG.getSetCC(dl, VT, And, Zero, Cond); unsigned LogicOpcode = Cond == ISD::SETEQ ? ISD::AND : ISD::OR; return DAG.getNode(LogicOpcode, dl, VT, LHS, RHS); } } // (zext x) == C --> x == (trunc C) // (sext x) == C --> x == (trunc C) if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) && DCI.isBeforeLegalize() && N0->hasOneUse()) { unsigned MinBits = N0.getValueSizeInBits(); SDValue PreExt; bool Signed = false; if (N0->getOpcode() == ISD::ZERO_EXTEND) { // ZExt MinBits = N0->getOperand(0).getValueSizeInBits(); PreExt = N0->getOperand(0); } else if (N0->getOpcode() == ISD::AND) { // DAGCombine turns costly ZExts into ANDs if (auto *C = dyn_cast(N0->getOperand(1))) if ((C->getAPIntValue()+1).isPowerOf2()) { MinBits = C->getAPIntValue().countTrailingOnes(); PreExt = N0->getOperand(0); } } else if (N0->getOpcode() == ISD::SIGN_EXTEND) { // SExt MinBits = N0->getOperand(0).getValueSizeInBits(); PreExt = N0->getOperand(0); Signed = true; } else if (auto *LN0 = dyn_cast(N0)) { // ZEXTLOAD / SEXTLOAD if (LN0->getExtensionType() == ISD::ZEXTLOAD) { MinBits = LN0->getMemoryVT().getSizeInBits(); PreExt = N0; } else if (LN0->getExtensionType() == ISD::SEXTLOAD) { Signed = true; MinBits = LN0->getMemoryVT().getSizeInBits(); PreExt = N0; } } // Figure out how many bits we need to preserve this constant. unsigned ReqdBits = Signed ? C1.getBitWidth() - C1.getNumSignBits() + 1 : C1.getActiveBits(); // Make sure we're not losing bits from the constant. if (MinBits > 0 && MinBits < C1.getBitWidth() && MinBits >= ReqdBits) { EVT MinVT = EVT::getIntegerVT(*DAG.getContext(), MinBits); if (isTypeDesirableForOp(ISD::SETCC, MinVT)) { // Will get folded away. SDValue Trunc = DAG.getNode(ISD::TRUNCATE, dl, MinVT, PreExt); if (MinBits == 1 && C1 == 1) // Invert the condition. return DAG.getSetCC(dl, VT, Trunc, DAG.getConstant(0, dl, MVT::i1), Cond == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ); SDValue C = DAG.getConstant(C1.trunc(MinBits), dl, MinVT); return DAG.getSetCC(dl, VT, Trunc, C, Cond); } // If truncating the setcc operands is not desirable, we can still // simplify the expression in some cases: // setcc ([sz]ext (setcc x, y, cc)), 0, setne) -> setcc (x, y, cc) // setcc ([sz]ext (setcc x, y, cc)), 0, seteq) -> setcc (x, y, inv(cc)) // setcc (zext (setcc x, y, cc)), 1, setne) -> setcc (x, y, inv(cc)) // setcc (zext (setcc x, y, cc)), 1, seteq) -> setcc (x, y, cc) // setcc (sext (setcc x, y, cc)), -1, setne) -> setcc (x, y, inv(cc)) // setcc (sext (setcc x, y, cc)), -1, seteq) -> setcc (x, y, cc) SDValue TopSetCC = N0->getOperand(0); unsigned N0Opc = N0->getOpcode(); bool SExt = (N0Opc == ISD::SIGN_EXTEND); if (TopSetCC.getValueType() == MVT::i1 && VT == MVT::i1 && TopSetCC.getOpcode() == ISD::SETCC && (N0Opc == ISD::ZERO_EXTEND || N0Opc == ISD::SIGN_EXTEND) && (isConstFalseVal(N1C) || isExtendedTrueVal(N1C, N0->getValueType(0), SExt))) { bool Inverse = (N1C->isNullValue() && Cond == ISD::SETEQ) || (!N1C->isNullValue() && Cond == ISD::SETNE); if (!Inverse) return TopSetCC; ISD::CondCode InvCond = ISD::getSetCCInverse( cast(TopSetCC.getOperand(2))->get(), TopSetCC.getOperand(0).getValueType()); return DAG.getSetCC(dl, VT, TopSetCC.getOperand(0), TopSetCC.getOperand(1), InvCond); } } } // If the LHS is '(and load, const)', the RHS is 0, the test is for // equality or unsigned, and all 1 bits of the const are in the same // partial word, see if we can shorten the load. if (DCI.isBeforeLegalize() && !ISD::isSignedIntSetCC(Cond) && N0.getOpcode() == ISD::AND && C1 == 0 && N0.getNode()->hasOneUse() && isa(N0.getOperand(0)) && N0.getOperand(0).getNode()->hasOneUse() && isa(N0.getOperand(1))) { LoadSDNode *Lod = cast(N0.getOperand(0)); APInt bestMask; unsigned bestWidth = 0, bestOffset = 0; if (Lod->isSimple() && Lod->isUnindexed()) { unsigned origWidth = N0.getValueSizeInBits(); unsigned maskWidth = origWidth; // We can narrow (e.g.) 16-bit extending loads on 32-bit target to // 8 bits, but have to be careful... if (Lod->getExtensionType() != ISD::NON_EXTLOAD) origWidth = Lod->getMemoryVT().getSizeInBits(); const APInt &Mask = N0.getConstantOperandAPInt(1); for (unsigned width = origWidth / 2; width>=8; width /= 2) { APInt newMask = APInt::getLowBitsSet(maskWidth, width); for (unsigned offset=0; offsetgetBasePtr(); if (bestOffset != 0) Ptr = DAG.getMemBasePlusOffset(Ptr, bestOffset, dl); unsigned NewAlign = MinAlign(Lod->getAlignment(), bestOffset); SDValue NewLoad = DAG.getLoad( newVT, dl, Lod->getChain(), Ptr, Lod->getPointerInfo().getWithOffset(bestOffset), NewAlign); return DAG.getSetCC(dl, VT, DAG.getNode(ISD::AND, dl, newVT, NewLoad, DAG.getConstant(bestMask.trunc(bestWidth), dl, newVT)), DAG.getConstant(0LL, dl, newVT), Cond); } } } // If the LHS is a ZERO_EXTEND, perform the comparison on the input. if (N0.getOpcode() == ISD::ZERO_EXTEND) { unsigned InSize = N0.getOperand(0).getValueSizeInBits(); // If the comparison constant has bits in the upper part, the // zero-extended value could never match. if (C1.intersects(APInt::getHighBitsSet(C1.getBitWidth(), C1.getBitWidth() - InSize))) { switch (Cond) { case ISD::SETUGT: case ISD::SETUGE: case ISD::SETEQ: return DAG.getConstant(0, dl, VT); case ISD::SETULT: case ISD::SETULE: case ISD::SETNE: return DAG.getConstant(1, dl, VT); case ISD::SETGT: case ISD::SETGE: // True if the sign bit of C1 is set. return DAG.getConstant(C1.isNegative(), dl, VT); case ISD::SETLT: case ISD::SETLE: // True if the sign bit of C1 isn't set. return DAG.getConstant(C1.isNonNegative(), dl, VT); default: break; } } // Otherwise, we can perform the comparison with the low bits. switch (Cond) { case ISD::SETEQ: case ISD::SETNE: case ISD::SETUGT: case ISD::SETUGE: case ISD::SETULT: case ISD::SETULE: { EVT newVT = N0.getOperand(0).getValueType(); if (DCI.isBeforeLegalizeOps() || (isOperationLegal(ISD::SETCC, newVT) && isCondCodeLegal(Cond, newVT.getSimpleVT()))) { EVT NewSetCCVT = getSetCCResultType(Layout, *DAG.getContext(), newVT); SDValue NewConst = DAG.getConstant(C1.trunc(InSize), dl, newVT); SDValue NewSetCC = DAG.getSetCC(dl, NewSetCCVT, N0.getOperand(0), NewConst, Cond); return DAG.getBoolExtOrTrunc(NewSetCC, dl, VT, N0.getValueType()); } break; } default: break; // todo, be more careful with signed comparisons } } else if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG && (Cond == ISD::SETEQ || Cond == ISD::SETNE)) { EVT ExtSrcTy = cast(N0.getOperand(1))->getVT(); unsigned ExtSrcTyBits = ExtSrcTy.getSizeInBits(); EVT ExtDstTy = N0.getValueType(); unsigned ExtDstTyBits = ExtDstTy.getSizeInBits(); // If the constant doesn't fit into the number of bits for the source of // the sign extension, it is impossible for both sides to be equal. if (C1.getMinSignedBits() > ExtSrcTyBits) return DAG.getConstant(Cond == ISD::SETNE, dl, VT); SDValue ZextOp; EVT Op0Ty = N0.getOperand(0).getValueType(); if (Op0Ty == ExtSrcTy) { ZextOp = N0.getOperand(0); } else { APInt Imm = APInt::getLowBitsSet(ExtDstTyBits, ExtSrcTyBits); ZextOp = DAG.getNode(ISD::AND, dl, Op0Ty, N0.getOperand(0), DAG.getConstant(Imm, dl, Op0Ty)); } if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(ZextOp.getNode()); // Otherwise, make this a use of a zext. return DAG.getSetCC(dl, VT, ZextOp, DAG.getConstant(C1 & APInt::getLowBitsSet( ExtDstTyBits, ExtSrcTyBits), dl, ExtDstTy), Cond); } else if ((N1C->isNullValue() || N1C->isOne()) && (Cond == ISD::SETEQ || Cond == ISD::SETNE)) { // SETCC (SETCC), [0|1], [EQ|NE] -> SETCC if (N0.getOpcode() == ISD::SETCC && isTypeLegal(VT) && VT.bitsLE(N0.getValueType()) && (N0.getValueType() == MVT::i1 || getBooleanContents(N0.getOperand(0).getValueType()) == ZeroOrOneBooleanContent)) { bool TrueWhenTrue = (Cond == ISD::SETEQ) ^ (!N1C->isOne()); if (TrueWhenTrue) return DAG.getNode(ISD::TRUNCATE, dl, VT, N0); // Invert the condition. ISD::CondCode CC = cast(N0.getOperand(2))->get(); CC = ISD::getSetCCInverse(CC, N0.getOperand(0).getValueType()); if (DCI.isBeforeLegalizeOps() || isCondCodeLegal(CC, N0.getOperand(0).getSimpleValueType())) return DAG.getSetCC(dl, VT, N0.getOperand(0), N0.getOperand(1), CC); } if ((N0.getOpcode() == ISD::XOR || (N0.getOpcode() == ISD::AND && N0.getOperand(0).getOpcode() == ISD::XOR && N0.getOperand(1) == N0.getOperand(0).getOperand(1))) && isa(N0.getOperand(1)) && cast(N0.getOperand(1))->isOne()) { // If this is (X^1) == 0/1, swap the RHS and eliminate the xor. We // can only do this if the top bits are known zero. unsigned BitWidth = N0.getValueSizeInBits(); if (DAG.MaskedValueIsZero(N0, APInt::getHighBitsSet(BitWidth, BitWidth-1))) { // Okay, get the un-inverted input value. SDValue Val; if (N0.getOpcode() == ISD::XOR) { Val = N0.getOperand(0); } else { assert(N0.getOpcode() == ISD::AND && N0.getOperand(0).getOpcode() == ISD::XOR); // ((X^1)&1)^1 -> X & 1 Val = DAG.getNode(ISD::AND, dl, N0.getValueType(), N0.getOperand(0).getOperand(0), N0.getOperand(1)); } return DAG.getSetCC(dl, VT, Val, N1, Cond == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ); } } else if (N1C->isOne()) { SDValue Op0 = N0; if (Op0.getOpcode() == ISD::TRUNCATE) Op0 = Op0.getOperand(0); if ((Op0.getOpcode() == ISD::XOR) && Op0.getOperand(0).getOpcode() == ISD::SETCC && Op0.getOperand(1).getOpcode() == ISD::SETCC) { SDValue XorLHS = Op0.getOperand(0); SDValue XorRHS = Op0.getOperand(1); // Ensure that the input setccs return an i1 type or 0/1 value. if (Op0.getValueType() == MVT::i1 || (getBooleanContents(XorLHS.getOperand(0).getValueType()) == ZeroOrOneBooleanContent && getBooleanContents(XorRHS.getOperand(0).getValueType()) == ZeroOrOneBooleanContent)) { // (xor (setcc), (setcc)) == / != 1 -> (setcc) != / == (setcc) Cond = (Cond == ISD::SETEQ) ? ISD::SETNE : ISD::SETEQ; return DAG.getSetCC(dl, VT, XorLHS, XorRHS, Cond); } } if (Op0.getOpcode() == ISD::AND && isa(Op0.getOperand(1)) && cast(Op0.getOperand(1))->isOne()) { // If this is (X&1) == / != 1, normalize it to (X&1) != / == 0. if (Op0.getValueType().bitsGT(VT)) Op0 = DAG.getNode(ISD::AND, dl, VT, DAG.getNode(ISD::TRUNCATE, dl, VT, Op0.getOperand(0)), DAG.getConstant(1, dl, VT)); else if (Op0.getValueType().bitsLT(VT)) Op0 = DAG.getNode(ISD::AND, dl, VT, DAG.getNode(ISD::ANY_EXTEND, dl, VT, Op0.getOperand(0)), DAG.getConstant(1, dl, VT)); return DAG.getSetCC(dl, VT, Op0, DAG.getConstant(0, dl, Op0.getValueType()), Cond == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ); } if (Op0.getOpcode() == ISD::AssertZext && cast(Op0.getOperand(1))->getVT() == MVT::i1) return DAG.getSetCC(dl, VT, Op0, DAG.getConstant(0, dl, Op0.getValueType()), Cond == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ); } } // Given: // icmp eq/ne (urem %x, %y), 0 // Iff %x has 0 or 1 bits set, and %y has at least 2 bits set, omit 'urem': // icmp eq/ne %x, 0 if (N0.getOpcode() == ISD::UREM && N1C->isNullValue() && (Cond == ISD::SETEQ || Cond == ISD::SETNE)) { KnownBits XKnown = DAG.computeKnownBits(N0.getOperand(0)); KnownBits YKnown = DAG.computeKnownBits(N0.getOperand(1)); if (XKnown.countMaxPopulation() == 1 && YKnown.countMinPopulation() >= 2) return DAG.getSetCC(dl, VT, N0.getOperand(0), N1, Cond); } if (SDValue V = optimizeSetCCOfSignedTruncationCheck(VT, N0, N1, Cond, DCI, dl)) return V; } // These simplifications apply to splat vectors as well. // TODO: Handle more splat vector cases. if (auto *N1C = isConstOrConstSplat(N1)) { const APInt &C1 = N1C->getAPIntValue(); APInt MinVal, MaxVal; unsigned OperandBitSize = N1C->getValueType(0).getScalarSizeInBits(); if (ISD::isSignedIntSetCC(Cond)) { MinVal = APInt::getSignedMinValue(OperandBitSize); MaxVal = APInt::getSignedMaxValue(OperandBitSize); } else { MinVal = APInt::getMinValue(OperandBitSize); MaxVal = APInt::getMaxValue(OperandBitSize); } // Canonicalize GE/LE comparisons to use GT/LT comparisons. if (Cond == ISD::SETGE || Cond == ISD::SETUGE) { // X >= MIN --> true if (C1 == MinVal) return DAG.getBoolConstant(true, dl, VT, OpVT); if (!VT.isVector()) { // TODO: Support this for vectors. // X >= C0 --> X > (C0 - 1) APInt C = C1 - 1; ISD::CondCode NewCC = (Cond == ISD::SETGE) ? ISD::SETGT : ISD::SETUGT; if ((DCI.isBeforeLegalizeOps() || isCondCodeLegal(NewCC, VT.getSimpleVT())) && (!N1C->isOpaque() || (C.getBitWidth() <= 64 && isLegalICmpImmediate(C.getSExtValue())))) { return DAG.getSetCC(dl, VT, N0, DAG.getConstant(C, dl, N1.getValueType()), NewCC); } } } if (Cond == ISD::SETLE || Cond == ISD::SETULE) { // X <= MAX --> true if (C1 == MaxVal) return DAG.getBoolConstant(true, dl, VT, OpVT); // X <= C0 --> X < (C0 + 1) if (!VT.isVector()) { // TODO: Support this for vectors. APInt C = C1 + 1; ISD::CondCode NewCC = (Cond == ISD::SETLE) ? ISD::SETLT : ISD::SETULT; if ((DCI.isBeforeLegalizeOps() || isCondCodeLegal(NewCC, VT.getSimpleVT())) && (!N1C->isOpaque() || (C.getBitWidth() <= 64 && isLegalICmpImmediate(C.getSExtValue())))) { return DAG.getSetCC(dl, VT, N0, DAG.getConstant(C, dl, N1.getValueType()), NewCC); } } } if (Cond == ISD::SETLT || Cond == ISD::SETULT) { if (C1 == MinVal) return DAG.getBoolConstant(false, dl, VT, OpVT); // X < MIN --> false // TODO: Support this for vectors after legalize ops. if (!VT.isVector() || DCI.isBeforeLegalizeOps()) { // Canonicalize setlt X, Max --> setne X, Max if (C1 == MaxVal) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETNE); // If we have setult X, 1, turn it into seteq X, 0 if (C1 == MinVal+1) return DAG.getSetCC(dl, VT, N0, DAG.getConstant(MinVal, dl, N0.getValueType()), ISD::SETEQ); } } if (Cond == ISD::SETGT || Cond == ISD::SETUGT) { if (C1 == MaxVal) return DAG.getBoolConstant(false, dl, VT, OpVT); // X > MAX --> false // TODO: Support this for vectors after legalize ops. if (!VT.isVector() || DCI.isBeforeLegalizeOps()) { // Canonicalize setgt X, Min --> setne X, Min if (C1 == MinVal) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETNE); // If we have setugt X, Max-1, turn it into seteq X, Max if (C1 == MaxVal-1) return DAG.getSetCC(dl, VT, N0, DAG.getConstant(MaxVal, dl, N0.getValueType()), ISD::SETEQ); } } if (Cond == ISD::SETEQ || Cond == ISD::SETNE) { // (X & (C l>>/<< Y)) ==/!= 0 --> ((X <> Y) & C) ==/!= 0 if (C1.isNullValue()) if (SDValue CC = optimizeSetCCByHoistingAndByConstFromLogicalShift( VT, N0, N1, Cond, DCI, dl)) return CC; } // If we have "setcc X, C0", check to see if we can shrink the immediate // by changing cc. // TODO: Support this for vectors after legalize ops. if (!VT.isVector() || DCI.isBeforeLegalizeOps()) { // SETUGT X, SINTMAX -> SETLT X, 0 if (Cond == ISD::SETUGT && C1 == APInt::getSignedMaxValue(OperandBitSize)) return DAG.getSetCC(dl, VT, N0, DAG.getConstant(0, dl, N1.getValueType()), ISD::SETLT); // SETULT X, SINTMIN -> SETGT X, -1 if (Cond == ISD::SETULT && C1 == APInt::getSignedMinValue(OperandBitSize)) { SDValue ConstMinusOne = DAG.getConstant(APInt::getAllOnesValue(OperandBitSize), dl, N1.getValueType()); return DAG.getSetCC(dl, VT, N0, ConstMinusOne, ISD::SETGT); } } } // Back to non-vector simplifications. // TODO: Can we do these for vector splats? if (auto *N1C = dyn_cast(N1.getNode())) { const TargetLowering &TLI = DAG.getTargetLoweringInfo(); const APInt &C1 = N1C->getAPIntValue(); EVT ShValTy = N0.getValueType(); // Fold bit comparisons when we can. if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) && (VT == ShValTy || (isTypeLegal(VT) && VT.bitsLE(ShValTy))) && N0.getOpcode() == ISD::AND) { if (auto *AndRHS = dyn_cast(N0.getOperand(1))) { EVT ShiftTy = getShiftAmountTy(ShValTy, Layout, !DCI.isBeforeLegalize()); if (Cond == ISD::SETNE && C1 == 0) {// (X & 8) != 0 --> (X & 8) >> 3 // Perform the xform if the AND RHS is a single bit. unsigned ShCt = AndRHS->getAPIntValue().logBase2(); if (AndRHS->getAPIntValue().isPowerOf2() && !TLI.shouldAvoidTransformToShift(ShValTy, ShCt)) { return DAG.getNode(ISD::TRUNCATE, dl, VT, DAG.getNode(ISD::SRL, dl, ShValTy, N0, DAG.getConstant(ShCt, dl, ShiftTy))); } } else if (Cond == ISD::SETEQ && C1 == AndRHS->getAPIntValue()) { // (X & 8) == 8 --> (X & 8) >> 3 // Perform the xform if C1 is a single bit. unsigned ShCt = C1.logBase2(); if (C1.isPowerOf2() && !TLI.shouldAvoidTransformToShift(ShValTy, ShCt)) { return DAG.getNode(ISD::TRUNCATE, dl, VT, DAG.getNode(ISD::SRL, dl, ShValTy, N0, DAG.getConstant(ShCt, dl, ShiftTy))); } } } } if (C1.getMinSignedBits() <= 64 && !isLegalICmpImmediate(C1.getSExtValue())) { EVT ShiftTy = getShiftAmountTy(ShValTy, Layout, !DCI.isBeforeLegalize()); // (X & -256) == 256 -> (X >> 8) == 1 if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) && N0.getOpcode() == ISD::AND && N0.hasOneUse()) { if (auto *AndRHS = dyn_cast(N0.getOperand(1))) { const APInt &AndRHSC = AndRHS->getAPIntValue(); if ((-AndRHSC).isPowerOf2() && (AndRHSC & C1) == C1) { unsigned ShiftBits = AndRHSC.countTrailingZeros(); if (!TLI.shouldAvoidTransformToShift(ShValTy, ShiftBits)) { SDValue Shift = DAG.getNode(ISD::SRL, dl, ShValTy, N0.getOperand(0), DAG.getConstant(ShiftBits, dl, ShiftTy)); SDValue CmpRHS = DAG.getConstant(C1.lshr(ShiftBits), dl, ShValTy); return DAG.getSetCC(dl, VT, Shift, CmpRHS, Cond); } } } } else if (Cond == ISD::SETULT || Cond == ISD::SETUGE || Cond == ISD::SETULE || Cond == ISD::SETUGT) { bool AdjOne = (Cond == ISD::SETULE || Cond == ISD::SETUGT); // X < 0x100000000 -> (X >> 32) < 1 // X >= 0x100000000 -> (X >> 32) >= 1 // X <= 0x0ffffffff -> (X >> 32) < 1 // X > 0x0ffffffff -> (X >> 32) >= 1 unsigned ShiftBits; APInt NewC = C1; ISD::CondCode NewCond = Cond; if (AdjOne) { ShiftBits = C1.countTrailingOnes(); NewC = NewC + 1; NewCond = (Cond == ISD::SETULE) ? ISD::SETULT : ISD::SETUGE; } else { ShiftBits = C1.countTrailingZeros(); } NewC.lshrInPlace(ShiftBits); if (ShiftBits && NewC.getMinSignedBits() <= 64 && isLegalICmpImmediate(NewC.getSExtValue()) && !TLI.shouldAvoidTransformToShift(ShValTy, ShiftBits)) { SDValue Shift = DAG.getNode(ISD::SRL, dl, ShValTy, N0, DAG.getConstant(ShiftBits, dl, ShiftTy)); SDValue CmpRHS = DAG.getConstant(NewC, dl, ShValTy); return DAG.getSetCC(dl, VT, Shift, CmpRHS, NewCond); } } } } if (!isa(N0) && isa(N1)) { auto *CFP = cast(N1); assert(!CFP->getValueAPF().isNaN() && "Unexpected NaN value"); // Otherwise, we know the RHS is not a NaN. Simplify the node to drop the // constant if knowing that the operand is non-nan is enough. We prefer to // have SETO(x,x) instead of SETO(x, 0.0) because this avoids having to // materialize 0.0. if (Cond == ISD::SETO || Cond == ISD::SETUO) return DAG.getSetCC(dl, VT, N0, N0, Cond); // setcc (fneg x), C -> setcc swap(pred) x, -C if (N0.getOpcode() == ISD::FNEG) { ISD::CondCode SwapCond = ISD::getSetCCSwappedOperands(Cond); if (DCI.isBeforeLegalizeOps() || isCondCodeLegal(SwapCond, N0.getSimpleValueType())) { SDValue NegN1 = DAG.getNode(ISD::FNEG, dl, N0.getValueType(), N1); return DAG.getSetCC(dl, VT, N0.getOperand(0), NegN1, SwapCond); } } // If the condition is not legal, see if we can find an equivalent one // which is legal. if (!isCondCodeLegal(Cond, N0.getSimpleValueType())) { // If the comparison was an awkward floating-point == or != and one of // the comparison operands is infinity or negative infinity, convert the // condition to a less-awkward <= or >=. if (CFP->getValueAPF().isInfinity()) { if (CFP->getValueAPF().isNegative()) { if (Cond == ISD::SETOEQ && isCondCodeLegal(ISD::SETOLE, N0.getSimpleValueType())) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETOLE); if (Cond == ISD::SETUEQ && isCondCodeLegal(ISD::SETOLE, N0.getSimpleValueType())) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETULE); if (Cond == ISD::SETUNE && isCondCodeLegal(ISD::SETUGT, N0.getSimpleValueType())) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETUGT); if (Cond == ISD::SETONE && isCondCodeLegal(ISD::SETUGT, N0.getSimpleValueType())) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETOGT); } else { if (Cond == ISD::SETOEQ && isCondCodeLegal(ISD::SETOGE, N0.getSimpleValueType())) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETOGE); if (Cond == ISD::SETUEQ && isCondCodeLegal(ISD::SETOGE, N0.getSimpleValueType())) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETUGE); if (Cond == ISD::SETUNE && isCondCodeLegal(ISD::SETULT, N0.getSimpleValueType())) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETULT); if (Cond == ISD::SETONE && isCondCodeLegal(ISD::SETULT, N0.getSimpleValueType())) return DAG.getSetCC(dl, VT, N0, N1, ISD::SETOLT); } } } } if (N0 == N1) { // The sext(setcc()) => setcc() optimization relies on the appropriate // constant being emitted. assert(!N0.getValueType().isInteger() && "Integer types should be handled by FoldSetCC"); bool EqTrue = ISD::isTrueWhenEqual(Cond); unsigned UOF = ISD::getUnorderedFlavor(Cond); if (UOF == 2) // FP operators that are undefined on NaNs. return DAG.getBoolConstant(EqTrue, dl, VT, OpVT); if (UOF == unsigned(EqTrue)) return DAG.getBoolConstant(EqTrue, dl, VT, OpVT); // Otherwise, we can't fold it. However, we can simplify it to SETUO/SETO // if it is not already. ISD::CondCode NewCond = UOF == 0 ? ISD::SETO : ISD::SETUO; if (NewCond != Cond && (DCI.isBeforeLegalizeOps() || isCondCodeLegal(NewCond, N0.getSimpleValueType()))) return DAG.getSetCC(dl, VT, N0, N1, NewCond); } if ((Cond == ISD::SETEQ || Cond == ISD::SETNE) && N0.getValueType().isInteger()) { if (N0.getOpcode() == ISD::ADD || N0.getOpcode() == ISD::SUB || N0.getOpcode() == ISD::XOR) { // Simplify (X+Y) == (X+Z) --> Y == Z if (N0.getOpcode() == N1.getOpcode()) { if (N0.getOperand(0) == N1.getOperand(0)) return DAG.getSetCC(dl, VT, N0.getOperand(1), N1.getOperand(1), Cond); if (N0.getOperand(1) == N1.getOperand(1)) return DAG.getSetCC(dl, VT, N0.getOperand(0), N1.getOperand(0), Cond); if (isCommutativeBinOp(N0.getOpcode())) { // If X op Y == Y op X, try other combinations. if (N0.getOperand(0) == N1.getOperand(1)) return DAG.getSetCC(dl, VT, N0.getOperand(1), N1.getOperand(0), Cond); if (N0.getOperand(1) == N1.getOperand(0)) return DAG.getSetCC(dl, VT, N0.getOperand(0), N1.getOperand(1), Cond); } } // If RHS is a legal immediate value for a compare instruction, we need // to be careful about increasing register pressure needlessly. bool LegalRHSImm = false; if (auto *RHSC = dyn_cast(N1)) { if (auto *LHSR = dyn_cast(N0.getOperand(1))) { // Turn (X+C1) == C2 --> X == C2-C1 if (N0.getOpcode() == ISD::ADD && N0.getNode()->hasOneUse()) { return DAG.getSetCC(dl, VT, N0.getOperand(0), DAG.getConstant(RHSC->getAPIntValue()- LHSR->getAPIntValue(), dl, N0.getValueType()), Cond); } // Turn (X^C1) == C2 into X == C1^C2 iff X&~C1 = 0. if (N0.getOpcode() == ISD::XOR) // If we know that all of the inverted bits are zero, don't bother // performing the inversion. if (DAG.MaskedValueIsZero(N0.getOperand(0), ~LHSR->getAPIntValue())) return DAG.getSetCC(dl, VT, N0.getOperand(0), DAG.getConstant(LHSR->getAPIntValue() ^ RHSC->getAPIntValue(), dl, N0.getValueType()), Cond); } // Turn (C1-X) == C2 --> X == C1-C2 if (auto *SUBC = dyn_cast(N0.getOperand(0))) { if (N0.getOpcode() == ISD::SUB && N0.getNode()->hasOneUse()) { return DAG.getSetCC(dl, VT, N0.getOperand(1), DAG.getConstant(SUBC->getAPIntValue() - RHSC->getAPIntValue(), dl, N0.getValueType()), Cond); } } // Could RHSC fold directly into a compare? if (RHSC->getValueType(0).getSizeInBits() <= 64) LegalRHSImm = isLegalICmpImmediate(RHSC->getSExtValue()); } // (X+Y) == X --> Y == 0 and similar folds. // Don't do this if X is an immediate that can fold into a cmp // instruction and X+Y has other uses. It could be an induction variable // chain, and the transform would increase register pressure. if (!LegalRHSImm || N0.hasOneUse()) if (SDValue V = foldSetCCWithBinOp(VT, N0, N1, Cond, dl, DCI)) return V; } if (N1.getOpcode() == ISD::ADD || N1.getOpcode() == ISD::SUB || N1.getOpcode() == ISD::XOR) if (SDValue V = foldSetCCWithBinOp(VT, N1, N0, Cond, dl, DCI)) return V; if (SDValue V = foldSetCCWithAnd(VT, N0, N1, Cond, dl, DCI)) return V; } // Fold remainder of division by a constant. if ((N0.getOpcode() == ISD::UREM || N0.getOpcode() == ISD::SREM) && N0.hasOneUse() && (Cond == ISD::SETEQ || Cond == ISD::SETNE)) { AttributeList Attr = DAG.getMachineFunction().getFunction().getAttributes(); // When division is cheap or optimizing for minimum size, // fall through to DIVREM creation by skipping this fold. if (!isIntDivCheap(VT, Attr) && !Attr.hasFnAttribute(Attribute::MinSize)) { if (N0.getOpcode() == ISD::UREM) { if (SDValue Folded = buildUREMEqFold(VT, N0, N1, Cond, DCI, dl)) return Folded; } else if (N0.getOpcode() == ISD::SREM) { if (SDValue Folded = buildSREMEqFold(VT, N0, N1, Cond, DCI, dl)) return Folded; } } } // Fold away ALL boolean setcc's. if (N0.getValueType().getScalarType() == MVT::i1 && foldBooleans) { SDValue Temp; switch (Cond) { default: llvm_unreachable("Unknown integer setcc!"); case ISD::SETEQ: // X == Y -> ~(X^Y) Temp = DAG.getNode(ISD::XOR, dl, OpVT, N0, N1); N0 = DAG.getNOT(dl, Temp, OpVT); if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(Temp.getNode()); break; case ISD::SETNE: // X != Y --> (X^Y) N0 = DAG.getNode(ISD::XOR, dl, OpVT, N0, N1); break; case ISD::SETGT: // X >s Y --> X == 0 & Y == 1 --> ~X & Y case ISD::SETULT: // X X == 0 & Y == 1 --> ~X & Y Temp = DAG.getNOT(dl, N0, OpVT); N0 = DAG.getNode(ISD::AND, dl, OpVT, N1, Temp); if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(Temp.getNode()); break; case ISD::SETLT: // X X == 1 & Y == 0 --> ~Y & X case ISD::SETUGT: // X >u Y --> X == 1 & Y == 0 --> ~Y & X Temp = DAG.getNOT(dl, N1, OpVT); N0 = DAG.getNode(ISD::AND, dl, OpVT, N0, Temp); if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(Temp.getNode()); break; case ISD::SETULE: // X <=u Y --> X == 0 | Y == 1 --> ~X | Y case ISD::SETGE: // X >=s Y --> X == 0 | Y == 1 --> ~X | Y Temp = DAG.getNOT(dl, N0, OpVT); N0 = DAG.getNode(ISD::OR, dl, OpVT, N1, Temp); if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(Temp.getNode()); break; case ISD::SETUGE: // X >=u Y --> X == 1 | Y == 0 --> ~Y | X case ISD::SETLE: // X <=s Y --> X == 1 | Y == 0 --> ~Y | X Temp = DAG.getNOT(dl, N1, OpVT); N0 = DAG.getNode(ISD::OR, dl, OpVT, N0, Temp); break; } if (VT.getScalarType() != MVT::i1) { if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(N0.getNode()); // FIXME: If running after legalize, we probably can't do this. ISD::NodeType ExtendCode = getExtendForContent(getBooleanContents(OpVT)); N0 = DAG.getNode(ExtendCode, dl, VT, N0); } return N0; } // Could not fold it. return SDValue(); } /// Returns true (and the GlobalValue and the offset) if the node is a /// GlobalAddress + offset. bool TargetLowering::isGAPlusOffset(SDNode *WN, const GlobalValue *&GA, int64_t &Offset) const { SDNode *N = unwrapAddress(SDValue(WN, 0)).getNode(); if (auto *GASD = dyn_cast(N)) { GA = GASD->getGlobal(); Offset += GASD->getOffset(); return true; } if (N->getOpcode() == ISD::ADD) { SDValue N1 = N->getOperand(0); SDValue N2 = N->getOperand(1); if (isGAPlusOffset(N1.getNode(), GA, Offset)) { if (auto *V = dyn_cast(N2)) { Offset += V->getSExtValue(); return true; } } else if (isGAPlusOffset(N2.getNode(), GA, Offset)) { if (auto *V = dyn_cast(N1)) { Offset += V->getSExtValue(); return true; } } } return false; } SDValue TargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { // Default implementation: no optimization. return SDValue(); } //===----------------------------------------------------------------------===// // Inline Assembler Implementation Methods //===----------------------------------------------------------------------===// TargetLowering::ConstraintType TargetLowering::getConstraintType(StringRef Constraint) const { unsigned S = Constraint.size(); if (S == 1) { switch (Constraint[0]) { default: break; case 'r': return C_RegisterClass; case 'm': // memory case 'o': // offsetable case 'V': // not offsetable return C_Memory; case 'n': // Simple Integer case 'E': // Floating Point Constant case 'F': // Floating Point Constant return C_Immediate; case 'i': // Simple Integer or Relocatable Constant case 's': // Relocatable Constant case 'p': // Address. case 'X': // Allow ANY value. case 'I': // Target registers. case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case '<': case '>': return C_Other; } } if (S > 1 && Constraint[0] == '{' && Constraint[S - 1] == '}') { if (S == 8 && Constraint.substr(1, 6) == "memory") // "{memory}" return C_Memory; return C_Register; } return C_Unknown; } /// Try to replace an X constraint, which matches anything, with another that /// has more specific requirements based on the type of the corresponding /// operand. const char *TargetLowering::LowerXConstraint(EVT ConstraintVT) const { if (ConstraintVT.isInteger()) return "r"; if (ConstraintVT.isFloatingPoint()) return "f"; // works for many targets return nullptr; } SDValue TargetLowering::LowerAsmOutputForConstraint( SDValue &Chain, SDValue &Flag, SDLoc DL, const AsmOperandInfo &OpInfo, SelectionDAG &DAG) const { return SDValue(); } /// Lower the specified operand into the Ops vector. /// If it is invalid, don't add anything to Ops. void TargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector &Ops, SelectionDAG &DAG) const { if (Constraint.length() > 1) return; char ConstraintLetter = Constraint[0]; switch (ConstraintLetter) { default: break; case 'X': // Allows any operand; labels (basic block) use this. if (Op.getOpcode() == ISD::BasicBlock || Op.getOpcode() == ISD::TargetBlockAddress) { Ops.push_back(Op); return; } LLVM_FALLTHROUGH; case 'i': // Simple Integer or Relocatable Constant case 'n': // Simple Integer case 's': { // Relocatable Constant GlobalAddressSDNode *GA; ConstantSDNode *C; BlockAddressSDNode *BA; uint64_t Offset = 0; // Match (GA) or (C) or (GA+C) or (GA-C) or ((GA+C)+C) or (((GA+C)+C)+C), // etc., since getelementpointer is variadic. We can't use // SelectionDAG::FoldSymbolOffset because it expects the GA to be accessible // while in this case the GA may be furthest from the root node which is // likely an ISD::ADD. while (1) { if ((GA = dyn_cast(Op)) && ConstraintLetter != 'n') { Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(Op), GA->getValueType(0), Offset + GA->getOffset())); return; } else if ((C = dyn_cast(Op)) && ConstraintLetter != 's') { // gcc prints these as sign extended. Sign extend value to 64 bits // now; without this it would get ZExt'd later in // ScheduleDAGSDNodes::EmitNode, which is very generic. bool IsBool = C->getConstantIntValue()->getBitWidth() == 1; BooleanContent BCont = getBooleanContents(MVT::i64); ISD::NodeType ExtOpc = IsBool ? getExtendForContent(BCont) : ISD::SIGN_EXTEND; int64_t ExtVal = ExtOpc == ISD::ZERO_EXTEND ? C->getZExtValue() : C->getSExtValue(); Ops.push_back(DAG.getTargetConstant(Offset + ExtVal, SDLoc(C), MVT::i64)); return; } else if ((BA = dyn_cast(Op)) && ConstraintLetter != 'n') { Ops.push_back(DAG.getTargetBlockAddress( BA->getBlockAddress(), BA->getValueType(0), Offset + BA->getOffset(), BA->getTargetFlags())); return; } else { const unsigned OpCode = Op.getOpcode(); if (OpCode == ISD::ADD || OpCode == ISD::SUB) { if ((C = dyn_cast(Op.getOperand(0)))) Op = Op.getOperand(1); // Subtraction is not commutative. else if (OpCode == ISD::ADD && (C = dyn_cast(Op.getOperand(1)))) Op = Op.getOperand(0); else return; Offset += (OpCode == ISD::ADD ? 1 : -1) * C->getSExtValue(); continue; } } return; } break; } } } std::pair TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *RI, StringRef Constraint, MVT VT) const { if (Constraint.empty() || Constraint[0] != '{') return std::make_pair(0u, static_cast(nullptr)); assert(*(Constraint.end() - 1) == '}' && "Not a brace enclosed constraint?"); // Remove the braces from around the name. StringRef RegName(Constraint.data() + 1, Constraint.size() - 2); std::pair R = std::make_pair(0u, static_cast(nullptr)); // Figure out which register class contains this reg. for (const TargetRegisterClass *RC : RI->regclasses()) { // If none of the value types for this register class are valid, we // can't use it. For example, 64-bit reg classes on 32-bit targets. if (!isLegalRC(*RI, *RC)) continue; for (TargetRegisterClass::iterator I = RC->begin(), E = RC->end(); I != E; ++I) { if (RegName.equals_lower(RI->getRegAsmName(*I))) { std::pair S = std::make_pair(*I, RC); // If this register class has the requested value type, return it, // otherwise keep searching and return the first class found // if no other is found which explicitly has the requested type. if (RI->isTypeLegalForClass(*RC, VT)) return S; if (!R.second) R = S; } } } return R; } //===----------------------------------------------------------------------===// // Constraint Selection. /// Return true of this is an input operand that is a matching constraint like /// "4". bool TargetLowering::AsmOperandInfo::isMatchingInputConstraint() const { assert(!ConstraintCode.empty() && "No known constraint!"); return isdigit(static_cast(ConstraintCode[0])); } /// If this is an input matching constraint, this method returns the output /// operand it matches. unsigned TargetLowering::AsmOperandInfo::getMatchedOperand() const { assert(!ConstraintCode.empty() && "No known constraint!"); return atoi(ConstraintCode.c_str()); } /// Split up the constraint string from the inline assembly value into the /// specific constraints and their prefixes, and also tie in the associated /// operand values. /// If this returns an empty vector, and if the constraint string itself /// isn't empty, there was an error parsing. TargetLowering::AsmOperandInfoVector TargetLowering::ParseConstraints(const DataLayout &DL, const TargetRegisterInfo *TRI, ImmutableCallSite CS) const { /// Information about all of the constraints. AsmOperandInfoVector ConstraintOperands; const InlineAsm *IA = cast(CS.getCalledValue()); unsigned maCount = 0; // Largest number of multiple alternative constraints. // Do a prepass over the constraints, canonicalizing them, and building up the // ConstraintOperands list. unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. unsigned ResNo = 0; // ResNo - The result number of the next output. for (InlineAsm::ConstraintInfo &CI : IA->ParseConstraints()) { ConstraintOperands.emplace_back(std::move(CI)); AsmOperandInfo &OpInfo = ConstraintOperands.back(); // Update multiple alternative constraint count. if (OpInfo.multipleAlternatives.size() > maCount) maCount = OpInfo.multipleAlternatives.size(); OpInfo.ConstraintVT = MVT::Other; // Compute the value type for each operand. switch (OpInfo.Type) { case InlineAsm::isOutput: // Indirect outputs just consume an argument. if (OpInfo.isIndirect) { OpInfo.CallOperandVal = const_cast(CS.getArgument(ArgNo++)); break; } // The return value of the call is this value. As such, there is no // corresponding argument. assert(!CS.getType()->isVoidTy() && "Bad inline asm!"); if (StructType *STy = dyn_cast(CS.getType())) { OpInfo.ConstraintVT = getSimpleValueType(DL, STy->getElementType(ResNo)); } else { assert(ResNo == 0 && "Asm only has one result!"); OpInfo.ConstraintVT = getSimpleValueType(DL, CS.getType()); } ++ResNo; break; case InlineAsm::isInput: OpInfo.CallOperandVal = const_cast(CS.getArgument(ArgNo++)); break; case InlineAsm::isClobber: // Nothing to do. break; } if (OpInfo.CallOperandVal) { llvm::Type *OpTy = OpInfo.CallOperandVal->getType(); if (OpInfo.isIndirect) { llvm::PointerType *PtrTy = dyn_cast(OpTy); if (!PtrTy) report_fatal_error("Indirect operand for inline asm not a pointer!"); OpTy = PtrTy->getElementType(); } // Look for vector wrapped in a struct. e.g. { <16 x i8> }. if (StructType *STy = dyn_cast(OpTy)) if (STy->getNumElements() == 1) OpTy = STy->getElementType(0); // If OpTy is not a single value, it may be a struct/union that we // can tile with integers. if (!OpTy->isSingleValueType() && OpTy->isSized()) { unsigned BitSize = DL.getTypeSizeInBits(OpTy); switch (BitSize) { default: break; case 1: case 8: case 16: case 32: case 64: case 128: OpInfo.ConstraintVT = MVT::getVT(IntegerType::get(OpTy->getContext(), BitSize), true); break; } } else if (PointerType *PT = dyn_cast(OpTy)) { unsigned PtrSize = DL.getPointerSizeInBits(PT->getAddressSpace()); OpInfo.ConstraintVT = MVT::getIntegerVT(PtrSize); } else { OpInfo.ConstraintVT = MVT::getVT(OpTy, true); } } } // If we have multiple alternative constraints, select the best alternative. if (!ConstraintOperands.empty()) { if (maCount) { unsigned bestMAIndex = 0; int bestWeight = -1; // weight: -1 = invalid match, and 0 = so-so match to 5 = good match. int weight = -1; unsigned maIndex; // Compute the sums of the weights for each alternative, keeping track // of the best (highest weight) one so far. for (maIndex = 0; maIndex < maCount; ++maIndex) { int weightSum = 0; for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); cIndex != eIndex; ++cIndex) { AsmOperandInfo &OpInfo = ConstraintOperands[cIndex]; if (OpInfo.Type == InlineAsm::isClobber) continue; // If this is an output operand with a matching input operand, // look up the matching input. If their types mismatch, e.g. one // is an integer, the other is floating point, or their sizes are // different, flag it as an maCantMatch. if (OpInfo.hasMatchingInput()) { AsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; if (OpInfo.ConstraintVT != Input.ConstraintVT) { if ((OpInfo.ConstraintVT.isInteger() != Input.ConstraintVT.isInteger()) || (OpInfo.ConstraintVT.getSizeInBits() != Input.ConstraintVT.getSizeInBits())) { weightSum = -1; // Can't match. break; } } } weight = getMultipleConstraintMatchWeight(OpInfo, maIndex); if (weight == -1) { weightSum = -1; break; } weightSum += weight; } // Update best. if (weightSum > bestWeight) { bestWeight = weightSum; bestMAIndex = maIndex; } } // Now select chosen alternative in each constraint. for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); cIndex != eIndex; ++cIndex) { AsmOperandInfo &cInfo = ConstraintOperands[cIndex]; if (cInfo.Type == InlineAsm::isClobber) continue; cInfo.selectAlternative(bestMAIndex); } } } // Check and hook up tied operands, choose constraint code to use. for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); cIndex != eIndex; ++cIndex) { AsmOperandInfo &OpInfo = ConstraintOperands[cIndex]; // If this is an output operand with a matching input operand, look up the // matching input. If their types mismatch, e.g. one is an integer, the // other is floating point, or their sizes are different, flag it as an // error. if (OpInfo.hasMatchingInput()) { AsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; if (OpInfo.ConstraintVT != Input.ConstraintVT) { std::pair MatchRC = getRegForInlineAsmConstraint(TRI, OpInfo.ConstraintCode, OpInfo.ConstraintVT); std::pair InputRC = getRegForInlineAsmConstraint(TRI, Input.ConstraintCode, Input.ConstraintVT); if ((OpInfo.ConstraintVT.isInteger() != Input.ConstraintVT.isInteger()) || (MatchRC.second != InputRC.second)) { report_fatal_error("Unsupported asm: input constraint" " with a matching output constraint of" " incompatible type!"); } } } } return ConstraintOperands; } /// Return an integer indicating how general CT is. static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) { switch (CT) { case TargetLowering::C_Immediate: case TargetLowering::C_Other: case TargetLowering::C_Unknown: return 0; case TargetLowering::C_Register: return 1; case TargetLowering::C_RegisterClass: return 2; case TargetLowering::C_Memory: return 3; } llvm_unreachable("Invalid constraint type"); } /// Examine constraint type and operand type and determine a weight value. /// This object must already have been set up with the operand type /// and the current alternative constraint selected. TargetLowering::ConstraintWeight TargetLowering::getMultipleConstraintMatchWeight( AsmOperandInfo &info, int maIndex) const { InlineAsm::ConstraintCodeVector *rCodes; if (maIndex >= (int)info.multipleAlternatives.size()) rCodes = &info.Codes; else rCodes = &info.multipleAlternatives[maIndex].Codes; ConstraintWeight BestWeight = CW_Invalid; // Loop over the options, keeping track of the most general one. for (unsigned i = 0, e = rCodes->size(); i != e; ++i) { ConstraintWeight weight = getSingleConstraintMatchWeight(info, (*rCodes)[i].c_str()); if (weight > BestWeight) BestWeight = weight; } return BestWeight; } /// Examine constraint type and operand type and determine a weight value. /// This object must already have been set up with the operand type /// and the current alternative constraint selected. TargetLowering::ConstraintWeight TargetLowering::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. if (!CallOperandVal) return CW_Default; // Look at the constraint type. switch (*constraint) { case 'i': // immediate integer. case 'n': // immediate integer with a known value. if (isa(CallOperandVal)) weight = CW_Constant; break; case 's': // non-explicit intregal immediate. if (isa(CallOperandVal)) weight = CW_Constant; break; case 'E': // immediate float if host format. case 'F': // immediate float. if (isa(CallOperandVal)) weight = CW_Constant; break; case '<': // memory operand with autodecrement. case '>': // memory operand with autoincrement. case 'm': // memory operand. case 'o': // offsettable memory operand case 'V': // non-offsettable memory operand weight = CW_Memory; break; case 'r': // general register. case 'g': // general register, memory operand or immediate integer. // note: Clang converts "g" to "imr". if (CallOperandVal->getType()->isIntegerTy()) weight = CW_Register; break; case 'X': // any operand. default: weight = CW_Default; break; } return weight; } /// If there are multiple different constraints that we could pick for this /// operand (e.g. "imr") try to pick the 'best' one. /// This is somewhat tricky: constraints fall into four classes: /// Other -> immediates and magic values /// Register -> one specific register /// RegisterClass -> a group of regs /// Memory -> memory /// Ideally, we would pick the most specific constraint possible: if we have /// something that fits into a register, we would pick it. The problem here /// is that if we have something that could either be in a register or in /// memory that use of the register could cause selection of *other* /// operands to fail: they might only succeed if we pick memory. Because of /// this the heuristic we use is: /// /// 1) If there is an 'other' constraint, and if the operand is valid for /// that constraint, use it. This makes us take advantage of 'i' /// constraints when available. /// 2) Otherwise, pick the most general constraint present. This prefers /// 'm' over 'r', for example. /// static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo, const TargetLowering &TLI, SDValue Op, SelectionDAG *DAG) { assert(OpInfo.Codes.size() > 1 && "Doesn't have multiple constraint options"); unsigned BestIdx = 0; TargetLowering::ConstraintType BestType = TargetLowering::C_Unknown; int BestGenerality = -1; // Loop over the options, keeping track of the most general one. for (unsigned i = 0, e = OpInfo.Codes.size(); i != e; ++i) { TargetLowering::ConstraintType CType = TLI.getConstraintType(OpInfo.Codes[i]); // Indirect 'other' or 'immediate' constraints are not allowed. if (OpInfo.isIndirect && !(CType == TargetLowering::C_Memory || CType == TargetLowering::C_Register || CType == TargetLowering::C_RegisterClass)) continue; // If this is an 'other' or 'immediate' constraint, see if the operand is // valid for it. For example, on X86 we might have an 'rI' constraint. If // the operand is an integer in the range [0..31] we want to use I (saving a // load of a register), otherwise we must use 'r'. if ((CType == TargetLowering::C_Other || CType == TargetLowering::C_Immediate) && Op.getNode()) { assert(OpInfo.Codes[i].size() == 1 && "Unhandled multi-letter 'other' constraint"); std::vector ResultOps; TLI.LowerAsmOperandForConstraint(Op, OpInfo.Codes[i], ResultOps, *DAG); if (!ResultOps.empty()) { BestType = CType; BestIdx = i; break; } } // Things with matching constraints can only be registers, per gcc // documentation. This mainly affects "g" constraints. if (CType == TargetLowering::C_Memory && OpInfo.hasMatchingInput()) continue; // This constraint letter is more general than the previous one, use it. int Generality = getConstraintGenerality(CType); if (Generality > BestGenerality) { BestType = CType; BestIdx = i; BestGenerality = Generality; } } OpInfo.ConstraintCode = OpInfo.Codes[BestIdx]; OpInfo.ConstraintType = BestType; } /// Determines the constraint code and constraint type to use for the specific /// AsmOperandInfo, setting OpInfo.ConstraintCode and OpInfo.ConstraintType. void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo, SDValue Op, SelectionDAG *DAG) const { assert(!OpInfo.Codes.empty() && "Must have at least one constraint"); // Single-letter constraints ('r') are very common. if (OpInfo.Codes.size() == 1) { OpInfo.ConstraintCode = OpInfo.Codes[0]; OpInfo.ConstraintType = getConstraintType(OpInfo.ConstraintCode); } else { ChooseConstraint(OpInfo, *this, Op, DAG); } // 'X' matches anything. if (OpInfo.ConstraintCode == "X" && OpInfo.CallOperandVal) { // Labels and constants are handled elsewhere ('X' is the only thing // that matches labels). For Functions, the type here is the type of // the result, which is not what we want to look at; leave them alone. Value *v = OpInfo.CallOperandVal; if (isa(v) || isa(v) || isa(v)) { OpInfo.CallOperandVal = v; return; } if (Op.getNode() && Op.getOpcode() == ISD::TargetBlockAddress) return; // Otherwise, try to resolve it to something we know about by looking at // the actual operand type. if (const char *Repl = LowerXConstraint(OpInfo.ConstraintVT)) { OpInfo.ConstraintCode = Repl; OpInfo.ConstraintType = getConstraintType(OpInfo.ConstraintCode); } } } /// Given an exact SDIV by a constant, create a multiplication /// with the multiplicative inverse of the constant. static SDValue BuildExactSDIV(const TargetLowering &TLI, SDNode *N, const SDLoc &dl, SelectionDAG &DAG, SmallVectorImpl &Created) { SDValue Op0 = N->getOperand(0); SDValue Op1 = N->getOperand(1); EVT VT = N->getValueType(0); EVT SVT = VT.getScalarType(); EVT ShVT = TLI.getShiftAmountTy(VT, DAG.getDataLayout()); EVT ShSVT = ShVT.getScalarType(); bool UseSRA = false; SmallVector Shifts, Factors; auto BuildSDIVPattern = [&](ConstantSDNode *C) { if (C->isNullValue()) return false; APInt Divisor = C->getAPIntValue(); unsigned Shift = Divisor.countTrailingZeros(); if (Shift) { Divisor.ashrInPlace(Shift); UseSRA = true; } // Calculate the multiplicative inverse, using Newton's method. APInt t; APInt Factor = Divisor; while ((t = Divisor * Factor) != 1) Factor *= APInt(Divisor.getBitWidth(), 2) - t; Shifts.push_back(DAG.getConstant(Shift, dl, ShSVT)); Factors.push_back(DAG.getConstant(Factor, dl, SVT)); return true; }; // Collect all magic values from the build vector. if (!ISD::matchUnaryPredicate(Op1, BuildSDIVPattern)) return SDValue(); SDValue Shift, Factor; if (VT.isVector()) { Shift = DAG.getBuildVector(ShVT, dl, Shifts); Factor = DAG.getBuildVector(VT, dl, Factors); } else { Shift = Shifts[0]; Factor = Factors[0]; } SDValue Res = Op0; // Shift the value upfront if it is even, so the LSB is one. if (UseSRA) { // TODO: For UDIV use SRL instead of SRA. SDNodeFlags Flags; Flags.setExact(true); Res = DAG.getNode(ISD::SRA, dl, VT, Res, Shift, Flags); Created.push_back(Res.getNode()); } return DAG.getNode(ISD::MUL, dl, VT, Res, Factor); } SDValue TargetLowering::BuildSDIVPow2(SDNode *N, const APInt &Divisor, SelectionDAG &DAG, SmallVectorImpl &Created) const { AttributeList Attr = DAG.getMachineFunction().getFunction().getAttributes(); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); if (TLI.isIntDivCheap(N->getValueType(0), Attr)) return SDValue(N, 0); // Lower SDIV as SDIV return SDValue(); } /// Given an ISD::SDIV node expressing a divide by constant, /// return a DAG expression to select that will generate the same value by /// multiplying by a magic number. /// Ref: "Hacker's Delight" or "The PowerPC Compiler Writer's Guide". SDValue TargetLowering::BuildSDIV(SDNode *N, SelectionDAG &DAG, bool IsAfterLegalization, SmallVectorImpl &Created) const { SDLoc dl(N); EVT VT = N->getValueType(0); EVT SVT = VT.getScalarType(); EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout()); EVT ShSVT = ShVT.getScalarType(); unsigned EltBits = VT.getScalarSizeInBits(); // Check to see if we can do this. // FIXME: We should be more aggressive here. if (!isTypeLegal(VT)) return SDValue(); // If the sdiv has an 'exact' bit we can use a simpler lowering. if (N->getFlags().hasExact()) return BuildExactSDIV(*this, N, dl, DAG, Created); SmallVector MagicFactors, Factors, Shifts, ShiftMasks; auto BuildSDIVPattern = [&](ConstantSDNode *C) { if (C->isNullValue()) return false; const APInt &Divisor = C->getAPIntValue(); APInt::ms magics = Divisor.magic(); int NumeratorFactor = 0; int ShiftMask = -1; if (Divisor.isOneValue() || Divisor.isAllOnesValue()) { // If d is +1/-1, we just multiply the numerator by +1/-1. NumeratorFactor = Divisor.getSExtValue(); magics.m = 0; magics.s = 0; ShiftMask = 0; } else if (Divisor.isStrictlyPositive() && magics.m.isNegative()) { // If d > 0 and m < 0, add the numerator. NumeratorFactor = 1; } else if (Divisor.isNegative() && magics.m.isStrictlyPositive()) { // If d < 0 and m > 0, subtract the numerator. NumeratorFactor = -1; } MagicFactors.push_back(DAG.getConstant(magics.m, dl, SVT)); Factors.push_back(DAG.getConstant(NumeratorFactor, dl, SVT)); Shifts.push_back(DAG.getConstant(magics.s, dl, ShSVT)); ShiftMasks.push_back(DAG.getConstant(ShiftMask, dl, SVT)); return true; }; SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); // Collect the shifts / magic values from each element. if (!ISD::matchUnaryPredicate(N1, BuildSDIVPattern)) return SDValue(); SDValue MagicFactor, Factor, Shift, ShiftMask; if (VT.isVector()) { MagicFactor = DAG.getBuildVector(VT, dl, MagicFactors); Factor = DAG.getBuildVector(VT, dl, Factors); Shift = DAG.getBuildVector(ShVT, dl, Shifts); ShiftMask = DAG.getBuildVector(VT, dl, ShiftMasks); } else { MagicFactor = MagicFactors[0]; Factor = Factors[0]; Shift = Shifts[0]; ShiftMask = ShiftMasks[0]; } // Multiply the numerator (operand 0) by the magic value. // FIXME: We should support doing a MUL in a wider type. SDValue Q; if (IsAfterLegalization ? isOperationLegal(ISD::MULHS, VT) : isOperationLegalOrCustom(ISD::MULHS, VT)) Q = DAG.getNode(ISD::MULHS, dl, VT, N0, MagicFactor); else if (IsAfterLegalization ? isOperationLegal(ISD::SMUL_LOHI, VT) : isOperationLegalOrCustom(ISD::SMUL_LOHI, VT)) { SDValue LoHi = DAG.getNode(ISD::SMUL_LOHI, dl, DAG.getVTList(VT, VT), N0, MagicFactor); Q = SDValue(LoHi.getNode(), 1); } else return SDValue(); // No mulhs or equivalent. Created.push_back(Q.getNode()); // (Optionally) Add/subtract the numerator using Factor. Factor = DAG.getNode(ISD::MUL, dl, VT, N0, Factor); Created.push_back(Factor.getNode()); Q = DAG.getNode(ISD::ADD, dl, VT, Q, Factor); Created.push_back(Q.getNode()); // Shift right algebraic by shift value. Q = DAG.getNode(ISD::SRA, dl, VT, Q, Shift); Created.push_back(Q.getNode()); // Extract the sign bit, mask it and add it to the quotient. SDValue SignShift = DAG.getConstant(EltBits - 1, dl, ShVT); SDValue T = DAG.getNode(ISD::SRL, dl, VT, Q, SignShift); Created.push_back(T.getNode()); T = DAG.getNode(ISD::AND, dl, VT, T, ShiftMask); Created.push_back(T.getNode()); return DAG.getNode(ISD::ADD, dl, VT, Q, T); } /// Given an ISD::UDIV node expressing a divide by constant, /// return a DAG expression to select that will generate the same value by /// multiplying by a magic number. /// Ref: "Hacker's Delight" or "The PowerPC Compiler Writer's Guide". SDValue TargetLowering::BuildUDIV(SDNode *N, SelectionDAG &DAG, bool IsAfterLegalization, SmallVectorImpl &Created) const { SDLoc dl(N); EVT VT = N->getValueType(0); EVT SVT = VT.getScalarType(); EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout()); EVT ShSVT = ShVT.getScalarType(); unsigned EltBits = VT.getScalarSizeInBits(); // Check to see if we can do this. // FIXME: We should be more aggressive here. if (!isTypeLegal(VT)) return SDValue(); bool UseNPQ = false; SmallVector PreShifts, PostShifts, MagicFactors, NPQFactors; auto BuildUDIVPattern = [&](ConstantSDNode *C) { if (C->isNullValue()) return false; // FIXME: We should use a narrower constant when the upper // bits are known to be zero. APInt Divisor = C->getAPIntValue(); APInt::mu magics = Divisor.magicu(); unsigned PreShift = 0, PostShift = 0; // If the divisor is even, we can avoid using the expensive fixup by // shifting the divided value upfront. if (magics.a != 0 && !Divisor[0]) { PreShift = Divisor.countTrailingZeros(); // Get magic number for the shifted divisor. magics = Divisor.lshr(PreShift).magicu(PreShift); assert(magics.a == 0 && "Should use cheap fixup now"); } APInt Magic = magics.m; unsigned SelNPQ; if (magics.a == 0 || Divisor.isOneValue()) { assert(magics.s < Divisor.getBitWidth() && "We shouldn't generate an undefined shift!"); PostShift = magics.s; SelNPQ = false; } else { PostShift = magics.s - 1; SelNPQ = true; } PreShifts.push_back(DAG.getConstant(PreShift, dl, ShSVT)); MagicFactors.push_back(DAG.getConstant(Magic, dl, SVT)); NPQFactors.push_back( DAG.getConstant(SelNPQ ? APInt::getOneBitSet(EltBits, EltBits - 1) : APInt::getNullValue(EltBits), dl, SVT)); PostShifts.push_back(DAG.getConstant(PostShift, dl, ShSVT)); UseNPQ |= SelNPQ; return true; }; SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); // Collect the shifts/magic values from each element. if (!ISD::matchUnaryPredicate(N1, BuildUDIVPattern)) return SDValue(); SDValue PreShift, PostShift, MagicFactor, NPQFactor; if (VT.isVector()) { PreShift = DAG.getBuildVector(ShVT, dl, PreShifts); MagicFactor = DAG.getBuildVector(VT, dl, MagicFactors); NPQFactor = DAG.getBuildVector(VT, dl, NPQFactors); PostShift = DAG.getBuildVector(ShVT, dl, PostShifts); } else { PreShift = PreShifts[0]; MagicFactor = MagicFactors[0]; PostShift = PostShifts[0]; } SDValue Q = N0; Q = DAG.getNode(ISD::SRL, dl, VT, Q, PreShift); Created.push_back(Q.getNode()); // FIXME: We should support doing a MUL in a wider type. auto GetMULHU = [&](SDValue X, SDValue Y) { if (IsAfterLegalization ? isOperationLegal(ISD::MULHU, VT) : isOperationLegalOrCustom(ISD::MULHU, VT)) return DAG.getNode(ISD::MULHU, dl, VT, X, Y); if (IsAfterLegalization ? isOperationLegal(ISD::UMUL_LOHI, VT) : isOperationLegalOrCustom(ISD::UMUL_LOHI, VT)) { SDValue LoHi = DAG.getNode(ISD::UMUL_LOHI, dl, DAG.getVTList(VT, VT), X, Y); return SDValue(LoHi.getNode(), 1); } return SDValue(); // No mulhu or equivalent }; // Multiply the numerator (operand 0) by the magic value. Q = GetMULHU(Q, MagicFactor); if (!Q) return SDValue(); Created.push_back(Q.getNode()); if (UseNPQ) { SDValue NPQ = DAG.getNode(ISD::SUB, dl, VT, N0, Q); Created.push_back(NPQ.getNode()); // For vectors we might have a mix of non-NPQ/NPQ paths, so use // MULHU to act as a SRL-by-1 for NPQ, else multiply by zero. if (VT.isVector()) NPQ = GetMULHU(NPQ, NPQFactor); else NPQ = DAG.getNode(ISD::SRL, dl, VT, NPQ, DAG.getConstant(1, dl, ShVT)); Created.push_back(NPQ.getNode()); Q = DAG.getNode(ISD::ADD, dl, VT, NPQ, Q); Created.push_back(Q.getNode()); } Q = DAG.getNode(ISD::SRL, dl, VT, Q, PostShift); Created.push_back(Q.getNode()); SDValue One = DAG.getConstant(1, dl, VT); SDValue IsOne = DAG.getSetCC(dl, VT, N1, One, ISD::SETEQ); return DAG.getSelect(dl, VT, IsOne, N0, Q); } /// If all values in Values that *don't* match the predicate are same 'splat' /// value, then replace all values with that splat value. /// Else, if AlternativeReplacement was provided, then replace all values that /// do match predicate with AlternativeReplacement value. static void turnVectorIntoSplatVector(MutableArrayRef Values, std::function Predicate, SDValue AlternativeReplacement = SDValue()) { SDValue Replacement; // Is there a value for which the Predicate does *NOT* match? What is it? auto SplatValue = llvm::find_if_not(Values, Predicate); if (SplatValue != Values.end()) { // Does Values consist only of SplatValue's and values matching Predicate? if (llvm::all_of(Values, [Predicate, SplatValue](SDValue Value) { return Value == *SplatValue || Predicate(Value); })) // Then we shall replace values matching predicate with SplatValue. Replacement = *SplatValue; } if (!Replacement) { // Oops, we did not find the "baseline" splat value. if (!AlternativeReplacement) return; // Nothing to do. // Let's replace with provided value then. Replacement = AlternativeReplacement; } std::replace_if(Values.begin(), Values.end(), Predicate, Replacement); } /// Given an ISD::UREM used only by an ISD::SETEQ or ISD::SETNE /// where the divisor is constant and the comparison target is zero, /// return a DAG expression that will generate the same comparison result /// using only multiplications, additions and shifts/rotations. /// Ref: "Hacker's Delight" 10-17. SDValue TargetLowering::buildUREMEqFold(EVT SETCCVT, SDValue REMNode, SDValue CompTargetNode, ISD::CondCode Cond, DAGCombinerInfo &DCI, const SDLoc &DL) const { SmallVector Built; if (SDValue Folded = prepareUREMEqFold(SETCCVT, REMNode, CompTargetNode, Cond, DCI, DL, Built)) { for (SDNode *N : Built) DCI.AddToWorklist(N); return Folded; } return SDValue(); } SDValue TargetLowering::prepareUREMEqFold(EVT SETCCVT, SDValue REMNode, SDValue CompTargetNode, ISD::CondCode Cond, DAGCombinerInfo &DCI, const SDLoc &DL, SmallVectorImpl &Created) const { // fold (seteq/ne (urem N, D), 0) -> (setule/ugt (rotr (mul N, P), K), Q) // - D must be constant, with D = D0 * 2^K where D0 is odd // - P is the multiplicative inverse of D0 modulo 2^W // - Q = floor(((2^W) - 1) / D) // where W is the width of the common type of N and D. assert((Cond == ISD::SETEQ || Cond == ISD::SETNE) && "Only applicable for (in)equality comparisons."); SelectionDAG &DAG = DCI.DAG; EVT VT = REMNode.getValueType(); EVT SVT = VT.getScalarType(); EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout()); EVT ShSVT = ShVT.getScalarType(); // If MUL is unavailable, we cannot proceed in any case. if (!isOperationLegalOrCustom(ISD::MUL, VT)) return SDValue(); bool ComparingWithAllZeros = true; bool AllComparisonsWithNonZerosAreTautological = true; bool HadTautologicalLanes = false; bool AllLanesAreTautological = true; bool HadEvenDivisor = false; bool AllDivisorsArePowerOfTwo = true; bool HadTautologicalInvertedLanes = false; SmallVector PAmts, KAmts, QAmts, IAmts; auto BuildUREMPattern = [&](ConstantSDNode *CDiv, ConstantSDNode *CCmp) { // Division by 0 is UB. Leave it to be constant-folded elsewhere. if (CDiv->isNullValue()) return false; const APInt &D = CDiv->getAPIntValue(); const APInt &Cmp = CCmp->getAPIntValue(); ComparingWithAllZeros &= Cmp.isNullValue(); // x u% C1` is *always* less than C1. So given `x u% C1 == C2`, // if C2 is not less than C1, the comparison is always false. // But we will only be able to produce the comparison that will give the // opposive tautological answer. So this lane would need to be fixed up. bool TautologicalInvertedLane = D.ule(Cmp); HadTautologicalInvertedLanes |= TautologicalInvertedLane; // If all lanes are tautological (either all divisors are ones, or divisor // is not greater than the constant we are comparing with), // we will prefer to avoid the fold. bool TautologicalLane = D.isOneValue() || TautologicalInvertedLane; HadTautologicalLanes |= TautologicalLane; AllLanesAreTautological &= TautologicalLane; // If we are comparing with non-zero, we need'll need to subtract said // comparison value from the LHS. But there is no point in doing that if // every lane where we are comparing with non-zero is tautological.. if (!Cmp.isNullValue()) AllComparisonsWithNonZerosAreTautological &= TautologicalLane; // Decompose D into D0 * 2^K unsigned K = D.countTrailingZeros(); assert((!D.isOneValue() || (K == 0)) && "For divisor '1' we won't rotate."); APInt D0 = D.lshr(K); // D is even if it has trailing zeros. HadEvenDivisor |= (K != 0); // D is a power-of-two if D0 is one. // If all divisors are power-of-two, we will prefer to avoid the fold. AllDivisorsArePowerOfTwo &= D0.isOneValue(); // P = inv(D0, 2^W) // 2^W requires W + 1 bits, so we have to extend and then truncate. unsigned W = D.getBitWidth(); APInt P = D0.zext(W + 1) .multiplicativeInverse(APInt::getSignedMinValue(W + 1)) .trunc(W); assert(!P.isNullValue() && "No multiplicative inverse!"); // unreachable assert((D0 * P).isOneValue() && "Multiplicative inverse sanity check."); // Q = floor((2^W - 1) u/ D) // R = ((2^W - 1) u% D) APInt Q, R; APInt::udivrem(APInt::getAllOnesValue(W), D, Q, R); // If we are comparing with zero, then that comparison constant is okay, // else it may need to be one less than that. if (Cmp.ugt(R)) Q -= 1; assert(APInt::getAllOnesValue(ShSVT.getSizeInBits()).ugt(K) && "We are expecting that K is always less than all-ones for ShSVT"); // If the lane is tautological the result can be constant-folded. if (TautologicalLane) { // Set P and K amount to a bogus values so we can try to splat them. P = 0; K = -1; // And ensure that comparison constant is tautological, // it will always compare true/false. Q = -1; } PAmts.push_back(DAG.getConstant(P, DL, SVT)); KAmts.push_back( DAG.getConstant(APInt(ShSVT.getSizeInBits(), K), DL, ShSVT)); QAmts.push_back(DAG.getConstant(Q, DL, SVT)); return true; }; SDValue N = REMNode.getOperand(0); SDValue D = REMNode.getOperand(1); // Collect the values from each element. if (!ISD::matchBinaryPredicate(D, CompTargetNode, BuildUREMPattern)) return SDValue(); // If all lanes are tautological, the result can be constant-folded. if (AllLanesAreTautological) return SDValue(); // If this is a urem by a powers-of-two, avoid the fold since it can be // best implemented as a bit test. if (AllDivisorsArePowerOfTwo) return SDValue(); SDValue PVal, KVal, QVal; if (VT.isVector()) { if (HadTautologicalLanes) { // Try to turn PAmts into a splat, since we don't care about the values // that are currently '0'. If we can't, just keep '0'`s. turnVectorIntoSplatVector(PAmts, isNullConstant); // Try to turn KAmts into a splat, since we don't care about the values // that are currently '-1'. If we can't, change them to '0'`s. turnVectorIntoSplatVector(KAmts, isAllOnesConstant, DAG.getConstant(0, DL, ShSVT)); } PVal = DAG.getBuildVector(VT, DL, PAmts); KVal = DAG.getBuildVector(ShVT, DL, KAmts); QVal = DAG.getBuildVector(VT, DL, QAmts); } else { PVal = PAmts[0]; KVal = KAmts[0]; QVal = QAmts[0]; } if (!ComparingWithAllZeros && !AllComparisonsWithNonZerosAreTautological) { if (!isOperationLegalOrCustom(ISD::SUB, VT)) return SDValue(); // FIXME: Could/should use `ISD::ADD`? assert(CompTargetNode.getValueType() == N.getValueType() && "Expecting that the types on LHS and RHS of comparisons match."); N = DAG.getNode(ISD::SUB, DL, VT, N, CompTargetNode); } // (mul N, P) SDValue Op0 = DAG.getNode(ISD::MUL, DL, VT, N, PVal); Created.push_back(Op0.getNode()); // Rotate right only if any divisor was even. We avoid rotates for all-odd // divisors as a performance improvement, since rotating by 0 is a no-op. if (HadEvenDivisor) { // We need ROTR to do this. if (!isOperationLegalOrCustom(ISD::ROTR, VT)) return SDValue(); SDNodeFlags Flags; Flags.setExact(true); // UREM: (rotr (mul N, P), K) Op0 = DAG.getNode(ISD::ROTR, DL, VT, Op0, KVal, Flags); Created.push_back(Op0.getNode()); } // UREM: (setule/setugt (rotr (mul N, P), K), Q) SDValue NewCC = DAG.getSetCC(DL, SETCCVT, Op0, QVal, ((Cond == ISD::SETEQ) ? ISD::SETULE : ISD::SETUGT)); if (!HadTautologicalInvertedLanes) return NewCC; // If any lanes previously compared always-false, the NewCC will give // always-true result for them, so we need to fixup those lanes. // Or the other way around for inequality predicate. assert(VT.isVector() && "Can/should only get here for vectors."); Created.push_back(NewCC.getNode()); // x u% C1` is *always* less than C1. So given `x u% C1 == C2`, // if C2 is not less than C1, the comparison is always false. // But we have produced the comparison that will give the // opposive tautological answer. So these lanes would need to be fixed up. SDValue TautologicalInvertedChannels = DAG.getSetCC(DL, SETCCVT, D, CompTargetNode, ISD::SETULE); Created.push_back(TautologicalInvertedChannels.getNode()); if (isOperationLegalOrCustom(ISD::VSELECT, SETCCVT)) { // If we have a vector select, let's replace the comparison results in the // affected lanes with the correct tautological result. SDValue Replacement = DAG.getBoolConstant(Cond == ISD::SETEQ ? false : true, DL, SETCCVT, SETCCVT); return DAG.getNode(ISD::VSELECT, DL, SETCCVT, TautologicalInvertedChannels, Replacement, NewCC); } // Else, we can just invert the comparison result in the appropriate lanes. if (isOperationLegalOrCustom(ISD::XOR, SETCCVT)) return DAG.getNode(ISD::XOR, DL, SETCCVT, NewCC, TautologicalInvertedChannels); return SDValue(); // Don't know how to lower. } /// Given an ISD::SREM used only by an ISD::SETEQ or ISD::SETNE /// where the divisor is constant and the comparison target is zero, /// return a DAG expression that will generate the same comparison result /// using only multiplications, additions and shifts/rotations. /// Ref: "Hacker's Delight" 10-17. SDValue TargetLowering::buildSREMEqFold(EVT SETCCVT, SDValue REMNode, SDValue CompTargetNode, ISD::CondCode Cond, DAGCombinerInfo &DCI, const SDLoc &DL) const { SmallVector Built; if (SDValue Folded = prepareSREMEqFold(SETCCVT, REMNode, CompTargetNode, Cond, DCI, DL, Built)) { assert(Built.size() <= 7 && "Max size prediction failed."); for (SDNode *N : Built) DCI.AddToWorklist(N); return Folded; } return SDValue(); } SDValue TargetLowering::prepareSREMEqFold(EVT SETCCVT, SDValue REMNode, SDValue CompTargetNode, ISD::CondCode Cond, DAGCombinerInfo &DCI, const SDLoc &DL, SmallVectorImpl &Created) const { // Fold: // (seteq/ne (srem N, D), 0) // To: // (setule/ugt (rotr (add (mul N, P), A), K), Q) // // - D must be constant, with D = D0 * 2^K where D0 is odd // - P is the multiplicative inverse of D0 modulo 2^W // - A = bitwiseand(floor((2^(W - 1) - 1) / D0), (-(2^k))) // - Q = floor((2 * A) / (2^K)) // where W is the width of the common type of N and D. assert((Cond == ISD::SETEQ || Cond == ISD::SETNE) && "Only applicable for (in)equality comparisons."); SelectionDAG &DAG = DCI.DAG; EVT VT = REMNode.getValueType(); EVT SVT = VT.getScalarType(); EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout()); EVT ShSVT = ShVT.getScalarType(); // If MUL is unavailable, we cannot proceed in any case. if (!isOperationLegalOrCustom(ISD::MUL, VT)) return SDValue(); // TODO: Could support comparing with non-zero too. ConstantSDNode *CompTarget = isConstOrConstSplat(CompTargetNode); if (!CompTarget || !CompTarget->isNullValue()) return SDValue(); bool HadIntMinDivisor = false; bool HadOneDivisor = false; bool AllDivisorsAreOnes = true; bool HadEvenDivisor = false; bool NeedToApplyOffset = false; bool AllDivisorsArePowerOfTwo = true; SmallVector PAmts, AAmts, KAmts, QAmts; auto BuildSREMPattern = [&](ConstantSDNode *C) { // Division by 0 is UB. Leave it to be constant-folded elsewhere. if (C->isNullValue()) return false; // FIXME: we don't fold `rem %X, -C` to `rem %X, C` in DAGCombine. // WARNING: this fold is only valid for positive divisors! APInt D = C->getAPIntValue(); if (D.isNegative()) D.negate(); // `rem %X, -C` is equivalent to `rem %X, C` HadIntMinDivisor |= D.isMinSignedValue(); // If all divisors are ones, we will prefer to avoid the fold. HadOneDivisor |= D.isOneValue(); AllDivisorsAreOnes &= D.isOneValue(); // Decompose D into D0 * 2^K unsigned K = D.countTrailingZeros(); assert((!D.isOneValue() || (K == 0)) && "For divisor '1' we won't rotate."); APInt D0 = D.lshr(K); if (!D.isMinSignedValue()) { // D is even if it has trailing zeros; unless it's INT_MIN, in which case // we don't care about this lane in this fold, we'll special-handle it. HadEvenDivisor |= (K != 0); } // D is a power-of-two if D0 is one. This includes INT_MIN. // If all divisors are power-of-two, we will prefer to avoid the fold. AllDivisorsArePowerOfTwo &= D0.isOneValue(); // P = inv(D0, 2^W) // 2^W requires W + 1 bits, so we have to extend and then truncate. unsigned W = D.getBitWidth(); APInt P = D0.zext(W + 1) .multiplicativeInverse(APInt::getSignedMinValue(W + 1)) .trunc(W); assert(!P.isNullValue() && "No multiplicative inverse!"); // unreachable assert((D0 * P).isOneValue() && "Multiplicative inverse sanity check."); // A = floor((2^(W - 1) - 1) / D0) & -2^K APInt A = APInt::getSignedMaxValue(W).udiv(D0); A.clearLowBits(K); if (!D.isMinSignedValue()) { // If divisor INT_MIN, then we don't care about this lane in this fold, // we'll special-handle it. NeedToApplyOffset |= A != 0; } // Q = floor((2 * A) / (2^K)) APInt Q = (2 * A).udiv(APInt::getOneBitSet(W, K)); assert(APInt::getAllOnesValue(SVT.getSizeInBits()).ugt(A) && "We are expecting that A is always less than all-ones for SVT"); assert(APInt::getAllOnesValue(ShSVT.getSizeInBits()).ugt(K) && "We are expecting that K is always less than all-ones for ShSVT"); // If the divisor is 1 the result can be constant-folded. Likewise, we // don't care about INT_MIN lanes, those can be set to undef if appropriate. if (D.isOneValue()) { // Set P, A and K to a bogus values so we can try to splat them. P = 0; A = -1; K = -1; // x ?% 1 == 0 <--> true <--> x u<= -1 Q = -1; } PAmts.push_back(DAG.getConstant(P, DL, SVT)); AAmts.push_back(DAG.getConstant(A, DL, SVT)); KAmts.push_back( DAG.getConstant(APInt(ShSVT.getSizeInBits(), K), DL, ShSVT)); QAmts.push_back(DAG.getConstant(Q, DL, SVT)); return true; }; SDValue N = REMNode.getOperand(0); SDValue D = REMNode.getOperand(1); // Collect the values from each element. if (!ISD::matchUnaryPredicate(D, BuildSREMPattern)) return SDValue(); // If this is a srem by a one, avoid the fold since it can be constant-folded. if (AllDivisorsAreOnes) return SDValue(); // If this is a srem by a powers-of-two (including INT_MIN), avoid the fold // since it can be best implemented as a bit test. if (AllDivisorsArePowerOfTwo) return SDValue(); SDValue PVal, AVal, KVal, QVal; if (VT.isVector()) { if (HadOneDivisor) { // Try to turn PAmts into a splat, since we don't care about the values // that are currently '0'. If we can't, just keep '0'`s. turnVectorIntoSplatVector(PAmts, isNullConstant); // Try to turn AAmts into a splat, since we don't care about the // values that are currently '-1'. If we can't, change them to '0'`s. turnVectorIntoSplatVector(AAmts, isAllOnesConstant, DAG.getConstant(0, DL, SVT)); // Try to turn KAmts into a splat, since we don't care about the values // that are currently '-1'. If we can't, change them to '0'`s. turnVectorIntoSplatVector(KAmts, isAllOnesConstant, DAG.getConstant(0, DL, ShSVT)); } PVal = DAG.getBuildVector(VT, DL, PAmts); AVal = DAG.getBuildVector(VT, DL, AAmts); KVal = DAG.getBuildVector(ShVT, DL, KAmts); QVal = DAG.getBuildVector(VT, DL, QAmts); } else { PVal = PAmts[0]; AVal = AAmts[0]; KVal = KAmts[0]; QVal = QAmts[0]; } // (mul N, P) SDValue Op0 = DAG.getNode(ISD::MUL, DL, VT, N, PVal); Created.push_back(Op0.getNode()); if (NeedToApplyOffset) { // We need ADD to do this. if (!isOperationLegalOrCustom(ISD::ADD, VT)) return SDValue(); // (add (mul N, P), A) Op0 = DAG.getNode(ISD::ADD, DL, VT, Op0, AVal); Created.push_back(Op0.getNode()); } // Rotate right only if any divisor was even. We avoid rotates for all-odd // divisors as a performance improvement, since rotating by 0 is a no-op. if (HadEvenDivisor) { // We need ROTR to do this. if (!isOperationLegalOrCustom(ISD::ROTR, VT)) return SDValue(); SDNodeFlags Flags; Flags.setExact(true); // SREM: (rotr (add (mul N, P), A), K) Op0 = DAG.getNode(ISD::ROTR, DL, VT, Op0, KVal, Flags); Created.push_back(Op0.getNode()); } // SREM: (setule/setugt (rotr (add (mul N, P), A), K), Q) SDValue Fold = DAG.getSetCC(DL, SETCCVT, Op0, QVal, ((Cond == ISD::SETEQ) ? ISD::SETULE : ISD::SETUGT)); // If we didn't have lanes with INT_MIN divisor, then we're done. if (!HadIntMinDivisor) return Fold; // That fold is only valid for positive divisors. Which effectively means, // it is invalid for INT_MIN divisors. So if we have such a lane, // we must fix-up results for said lanes. assert(VT.isVector() && "Can/should only get here for vectors."); if (!isOperationLegalOrCustom(ISD::SETEQ, VT) || !isOperationLegalOrCustom(ISD::AND, VT) || !isOperationLegalOrCustom(Cond, VT) || !isOperationLegalOrCustom(ISD::VSELECT, VT)) return SDValue(); Created.push_back(Fold.getNode()); SDValue IntMin = DAG.getConstant( APInt::getSignedMinValue(SVT.getScalarSizeInBits()), DL, VT); SDValue IntMax = DAG.getConstant( APInt::getSignedMaxValue(SVT.getScalarSizeInBits()), DL, VT); SDValue Zero = DAG.getConstant(APInt::getNullValue(SVT.getScalarSizeInBits()), DL, VT); // Which lanes had INT_MIN divisors? Divisor is constant, so const-folded. SDValue DivisorIsIntMin = DAG.getSetCC(DL, SETCCVT, D, IntMin, ISD::SETEQ); Created.push_back(DivisorIsIntMin.getNode()); // (N s% INT_MIN) ==/!= 0 <--> (N & INT_MAX) ==/!= 0 SDValue Masked = DAG.getNode(ISD::AND, DL, VT, N, IntMax); Created.push_back(Masked.getNode()); SDValue MaskedIsZero = DAG.getSetCC(DL, SETCCVT, Masked, Zero, Cond); Created.push_back(MaskedIsZero.getNode()); // To produce final result we need to blend 2 vectors: 'SetCC' and // 'MaskedIsZero'. If the divisor for channel was *NOT* INT_MIN, we pick // from 'Fold', else pick from 'MaskedIsZero'. Since 'DivisorIsIntMin' is // constant-folded, select can get lowered to a shuffle with constant mask. SDValue Blended = DAG.getNode(ISD::VSELECT, DL, VT, DivisorIsIntMin, MaskedIsZero, Fold); return Blended; } bool TargetLowering:: verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const { if (!isa(Op.getOperand(0))) { DAG.getContext()->emitError("argument to '__builtin_return_address' must " "be a constant integer"); return true; } return false; } char TargetLowering::isNegatibleForFree(SDValue Op, SelectionDAG &DAG, bool LegalOperations, bool ForCodeSize, unsigned Depth) const { // fneg is removable even if it has multiple uses. if (Op.getOpcode() == ISD::FNEG) return 2; // Don't allow anything with multiple uses unless we know it is free. EVT VT = Op.getValueType(); const SDNodeFlags Flags = Op->getFlags(); const TargetOptions &Options = DAG.getTarget().Options; - if (!Op.hasOneUse() && !(Op.getOpcode() == ISD::FP_EXTEND && - isFPExtFree(VT, Op.getOperand(0).getValueType()))) - return 0; + if (!Op.hasOneUse()) { + bool IsFreeExtend = Op.getOpcode() == ISD::FP_EXTEND && + isFPExtFree(VT, Op.getOperand(0).getValueType()); + // If we already have the use of the negated floating constant, it is free + // to negate it even it has multiple uses. + bool IsFreeConstant = + Op.getOpcode() == ISD::ConstantFP && + !getNegatedExpression(Op, DAG, LegalOperations, ForCodeSize) + .use_empty(); + + if (!IsFreeExtend && !IsFreeConstant) + return 0; + } + // Don't recurse exponentially. if (Depth > SelectionDAG::MaxRecursionDepth) return 0; switch (Op.getOpcode()) { case ISD::ConstantFP: { if (!LegalOperations) return 1; // Don't invert constant FP values after legalization unless the target says // the negated constant is legal. return isOperationLegal(ISD::ConstantFP, VT) || isFPImmLegal(neg(cast(Op)->getValueAPF()), VT, ForCodeSize); } case ISD::BUILD_VECTOR: { // Only permit BUILD_VECTOR of constants. if (llvm::any_of(Op->op_values(), [&](SDValue N) { return !N.isUndef() && !isa(N); })) return 0; if (!LegalOperations) return 1; if (isOperationLegal(ISD::ConstantFP, VT) && isOperationLegal(ISD::BUILD_VECTOR, VT)) return 1; return llvm::all_of(Op->op_values(), [&](SDValue N) { return N.isUndef() || isFPImmLegal(neg(cast(N)->getValueAPF()), VT, ForCodeSize); }); } case ISD::FADD: if (!Options.NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) return 0; // After operation legalization, it might not be legal to create new FSUBs. if (LegalOperations && !isOperationLegalOrCustom(ISD::FSUB, VT)) return 0; // fold (fneg (fadd A, B)) -> (fsub (fneg A), B) if (char V = isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1)) return V; // fold (fneg (fadd A, B)) -> (fsub (fneg B), A) return isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, ForCodeSize, Depth + 1); case ISD::FSUB: // We can't turn -(A-B) into B-A when we honor signed zeros. if (!Options.NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) return 0; // fold (fneg (fsub A, B)) -> (fsub B, A) return 1; case ISD::FMUL: case ISD::FDIV: // fold (fneg (fmul X, Y)) -> (fmul (fneg X), Y) or (fmul X, (fneg Y)) if (char V = isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1)) return V; // Ignore X * 2.0 because that is expected to be canonicalized to X + X. if (auto *C = isConstOrConstSplatFP(Op.getOperand(1))) if (C->isExactlyValue(2.0) && Op.getOpcode() == ISD::FMUL) return 0; return isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, ForCodeSize, Depth + 1); case ISD::FMA: case ISD::FMAD: { if (!Options.NoSignedZerosFPMath && !Flags.hasNoSignedZeros()) return 0; // fold (fneg (fma X, Y, Z)) -> (fma (fneg X), Y, (fneg Z)) // fold (fneg (fma X, Y, Z)) -> (fma X, (fneg Y), (fneg Z)) char V2 = isNegatibleForFree(Op.getOperand(2), DAG, LegalOperations, ForCodeSize, Depth + 1); if (!V2) return 0; // One of Op0/Op1 must be cheaply negatible, then select the cheapest. char V0 = isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1); char V1 = isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, ForCodeSize, Depth + 1); char V01 = std::max(V0, V1); return V01 ? std::max(V01, V2) : 0; } case ISD::FP_EXTEND: case ISD::FP_ROUND: case ISD::FSIN: return isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1); } return 0; } SDValue TargetLowering::getNegatedExpression(SDValue Op, SelectionDAG &DAG, bool LegalOperations, bool ForCodeSize, unsigned Depth) const { // fneg is removable even if it has multiple uses. if (Op.getOpcode() == ISD::FNEG) return Op.getOperand(0); assert(Depth <= SelectionDAG::MaxRecursionDepth && "getNegatedExpression doesn't match isNegatibleForFree"); const SDNodeFlags Flags = Op->getFlags(); switch (Op.getOpcode()) { case ISD::ConstantFP: { APFloat V = cast(Op)->getValueAPF(); V.changeSign(); return DAG.getConstantFP(V, SDLoc(Op), Op.getValueType()); } case ISD::BUILD_VECTOR: { SmallVector Ops; for (SDValue C : Op->op_values()) { if (C.isUndef()) { Ops.push_back(C); continue; } APFloat V = cast(C)->getValueAPF(); V.changeSign(); Ops.push_back(DAG.getConstantFP(V, SDLoc(Op), C.getValueType())); } return DAG.getBuildVector(Op.getValueType(), SDLoc(Op), Ops); } case ISD::FADD: assert((DAG.getTarget().Options.NoSignedZerosFPMath || Flags.hasNoSignedZeros()) && "Expected NSZ fp-flag"); // fold (fneg (fadd A, B)) -> (fsub (fneg A), B) if (isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1)) return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), getNegatedExpression(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1), Op.getOperand(1), Flags); // fold (fneg (fadd A, B)) -> (fsub (fneg B), A) return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), getNegatedExpression(Op.getOperand(1), DAG, LegalOperations, ForCodeSize, Depth + 1), Op.getOperand(0), Flags); case ISD::FSUB: // fold (fneg (fsub 0, B)) -> B if (ConstantFPSDNode *N0CFP = isConstOrConstSplatFP(Op.getOperand(0), /*AllowUndefs*/ true)) if (N0CFP->isZero()) return Op.getOperand(1); // fold (fneg (fsub A, B)) -> (fsub B, A) return DAG.getNode(ISD::FSUB, SDLoc(Op), Op.getValueType(), Op.getOperand(1), Op.getOperand(0), Flags); case ISD::FMUL: case ISD::FDIV: // fold (fneg (fmul X, Y)) -> (fmul (fneg X), Y) if (isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1)) return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), getNegatedExpression(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1), Op.getOperand(1), Flags); // fold (fneg (fmul X, Y)) -> (fmul X, (fneg Y)) return DAG.getNode( Op.getOpcode(), SDLoc(Op), Op.getValueType(), Op.getOperand(0), getNegatedExpression(Op.getOperand(1), DAG, LegalOperations, ForCodeSize, Depth + 1), Flags); case ISD::FMA: case ISD::FMAD: { assert((DAG.getTarget().Options.NoSignedZerosFPMath || Flags.hasNoSignedZeros()) && "Expected NSZ fp-flag"); SDValue Neg2 = getNegatedExpression(Op.getOperand(2), DAG, LegalOperations, ForCodeSize, Depth + 1); char V0 = isNegatibleForFree(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1); char V1 = isNegatibleForFree(Op.getOperand(1), DAG, LegalOperations, ForCodeSize, Depth + 1); - // TODO: This is a hack. It is possible that costs have changed between now - // and the initial calls to isNegatibleForFree(). That is because we - // are rewriting the expression, and that may change the number of - // uses (and therefore the cost) of values. If the negation costs are - // equal, only negate this value if it is a constant. Otherwise, try - // operand 1. A better fix would eliminate uses as a cost factor or - // track the change in uses as we rewrite the expression. - if (V0 > V1 || (V0 == V1 && isa(Op.getOperand(0)))) { + if (V0 > V1) { // fold (fneg (fma X, Y, Z)) -> (fma (fneg X), Y, (fneg Z)) SDValue Neg0 = getNegatedExpression( Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1); return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Neg0, Op.getOperand(1), Neg2, Flags); } // fold (fneg (fma X, Y, Z)) -> (fma X, (fneg Y), (fneg Z)) SDValue Neg1 = getNegatedExpression(Op.getOperand(1), DAG, LegalOperations, ForCodeSize, Depth + 1); return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), Op.getOperand(0), Neg1, Neg2, Flags); } case ISD::FP_EXTEND: case ISD::FSIN: return DAG.getNode(Op.getOpcode(), SDLoc(Op), Op.getValueType(), getNegatedExpression(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1)); case ISD::FP_ROUND: return DAG.getNode(ISD::FP_ROUND, SDLoc(Op), Op.getValueType(), getNegatedExpression(Op.getOperand(0), DAG, LegalOperations, ForCodeSize, Depth + 1), Op.getOperand(1)); } llvm_unreachable("Unknown code"); } //===----------------------------------------------------------------------===// // Legalization Utilities //===----------------------------------------------------------------------===// bool TargetLowering::expandMUL_LOHI(unsigned Opcode, EVT VT, SDLoc dl, SDValue LHS, SDValue RHS, SmallVectorImpl &Result, EVT HiLoVT, SelectionDAG &DAG, MulExpansionKind Kind, SDValue LL, SDValue LH, SDValue RL, SDValue RH) const { assert(Opcode == ISD::MUL || Opcode == ISD::UMUL_LOHI || Opcode == ISD::SMUL_LOHI); bool HasMULHS = (Kind == MulExpansionKind::Always) || isOperationLegalOrCustom(ISD::MULHS, HiLoVT); bool HasMULHU = (Kind == MulExpansionKind::Always) || isOperationLegalOrCustom(ISD::MULHU, HiLoVT); bool HasSMUL_LOHI = (Kind == MulExpansionKind::Always) || isOperationLegalOrCustom(ISD::SMUL_LOHI, HiLoVT); bool HasUMUL_LOHI = (Kind == MulExpansionKind::Always) || isOperationLegalOrCustom(ISD::UMUL_LOHI, HiLoVT); if (!HasMULHU && !HasMULHS && !HasUMUL_LOHI && !HasSMUL_LOHI) return false; unsigned OuterBitSize = VT.getScalarSizeInBits(); unsigned InnerBitSize = HiLoVT.getScalarSizeInBits(); unsigned LHSSB = DAG.ComputeNumSignBits(LHS); unsigned RHSSB = DAG.ComputeNumSignBits(RHS); // LL, LH, RL, and RH must be either all NULL or all set to a value. assert((LL.getNode() && LH.getNode() && RL.getNode() && RH.getNode()) || (!LL.getNode() && !LH.getNode() && !RL.getNode() && !RH.getNode())); SDVTList VTs = DAG.getVTList(HiLoVT, HiLoVT); auto MakeMUL_LOHI = [&](SDValue L, SDValue R, SDValue &Lo, SDValue &Hi, bool Signed) -> bool { if ((Signed && HasSMUL_LOHI) || (!Signed && HasUMUL_LOHI)) { Lo = DAG.getNode(Signed ? ISD::SMUL_LOHI : ISD::UMUL_LOHI, dl, VTs, L, R); Hi = SDValue(Lo.getNode(), 1); return true; } if ((Signed && HasMULHS) || (!Signed && HasMULHU)) { Lo = DAG.getNode(ISD::MUL, dl, HiLoVT, L, R); Hi = DAG.getNode(Signed ? ISD::MULHS : ISD::MULHU, dl, HiLoVT, L, R); return true; } return false; }; SDValue Lo, Hi; if (!LL.getNode() && !RL.getNode() && isOperationLegalOrCustom(ISD::TRUNCATE, HiLoVT)) { LL = DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, LHS); RL = DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, RHS); } if (!LL.getNode()) return false; APInt HighMask = APInt::getHighBitsSet(OuterBitSize, InnerBitSize); if (DAG.MaskedValueIsZero(LHS, HighMask) && DAG.MaskedValueIsZero(RHS, HighMask)) { // The inputs are both zero-extended. if (MakeMUL_LOHI(LL, RL, Lo, Hi, false)) { Result.push_back(Lo); Result.push_back(Hi); if (Opcode != ISD::MUL) { SDValue Zero = DAG.getConstant(0, dl, HiLoVT); Result.push_back(Zero); Result.push_back(Zero); } return true; } } if (!VT.isVector() && Opcode == ISD::MUL && LHSSB > InnerBitSize && RHSSB > InnerBitSize) { // The input values are both sign-extended. // TODO non-MUL case? if (MakeMUL_LOHI(LL, RL, Lo, Hi, true)) { Result.push_back(Lo); Result.push_back(Hi); return true; } } unsigned ShiftAmount = OuterBitSize - InnerBitSize; EVT ShiftAmountTy = getShiftAmountTy(VT, DAG.getDataLayout()); if (APInt::getMaxValue(ShiftAmountTy.getSizeInBits()).ult(ShiftAmount)) { // FIXME getShiftAmountTy does not always return a sensible result when VT // is an illegal type, and so the type may be too small to fit the shift // amount. Override it with i32. The shift will have to be legalized. ShiftAmountTy = MVT::i32; } SDValue Shift = DAG.getConstant(ShiftAmount, dl, ShiftAmountTy); if (!LH.getNode() && !RH.getNode() && isOperationLegalOrCustom(ISD::SRL, VT) && isOperationLegalOrCustom(ISD::TRUNCATE, HiLoVT)) { LH = DAG.getNode(ISD::SRL, dl, VT, LHS, Shift); LH = DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, LH); RH = DAG.getNode(ISD::SRL, dl, VT, RHS, Shift); RH = DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, RH); } if (!LH.getNode()) return false; if (!MakeMUL_LOHI(LL, RL, Lo, Hi, false)) return false; Result.push_back(Lo); if (Opcode == ISD::MUL) { RH = DAG.getNode(ISD::MUL, dl, HiLoVT, LL, RH); LH = DAG.getNode(ISD::MUL, dl, HiLoVT, LH, RL); Hi = DAG.getNode(ISD::ADD, dl, HiLoVT, Hi, RH); Hi = DAG.getNode(ISD::ADD, dl, HiLoVT, Hi, LH); Result.push_back(Hi); return true; } // Compute the full width result. auto Merge = [&](SDValue Lo, SDValue Hi) -> SDValue { Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Lo); Hi = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Hi); Hi = DAG.getNode(ISD::SHL, dl, VT, Hi, Shift); return DAG.getNode(ISD::OR, dl, VT, Lo, Hi); }; SDValue Next = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Hi); if (!MakeMUL_LOHI(LL, RH, Lo, Hi, false)) return false; // This is effectively the add part of a multiply-add of half-sized operands, // so it cannot overflow. Next = DAG.getNode(ISD::ADD, dl, VT, Next, Merge(Lo, Hi)); if (!MakeMUL_LOHI(LH, RL, Lo, Hi, false)) return false; SDValue Zero = DAG.getConstant(0, dl, HiLoVT); EVT BoolType = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); bool UseGlue = (isOperationLegalOrCustom(ISD::ADDC, VT) && isOperationLegalOrCustom(ISD::ADDE, VT)); if (UseGlue) Next = DAG.getNode(ISD::ADDC, dl, DAG.getVTList(VT, MVT::Glue), Next, Merge(Lo, Hi)); else Next = DAG.getNode(ISD::ADDCARRY, dl, DAG.getVTList(VT, BoolType), Next, Merge(Lo, Hi), DAG.getConstant(0, dl, BoolType)); SDValue Carry = Next.getValue(1); Result.push_back(DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, Next)); Next = DAG.getNode(ISD::SRL, dl, VT, Next, Shift); if (!MakeMUL_LOHI(LH, RH, Lo, Hi, Opcode == ISD::SMUL_LOHI)) return false; if (UseGlue) Hi = DAG.getNode(ISD::ADDE, dl, DAG.getVTList(HiLoVT, MVT::Glue), Hi, Zero, Carry); else Hi = DAG.getNode(ISD::ADDCARRY, dl, DAG.getVTList(HiLoVT, BoolType), Hi, Zero, Carry); Next = DAG.getNode(ISD::ADD, dl, VT, Next, Merge(Lo, Hi)); if (Opcode == ISD::SMUL_LOHI) { SDValue NextSub = DAG.getNode(ISD::SUB, dl, VT, Next, DAG.getNode(ISD::ZERO_EXTEND, dl, VT, RL)); Next = DAG.getSelectCC(dl, LH, Zero, NextSub, Next, ISD::SETLT); NextSub = DAG.getNode(ISD::SUB, dl, VT, Next, DAG.getNode(ISD::ZERO_EXTEND, dl, VT, LL)); Next = DAG.getSelectCC(dl, RH, Zero, NextSub, Next, ISD::SETLT); } Result.push_back(DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, Next)); Next = DAG.getNode(ISD::SRL, dl, VT, Next, Shift); Result.push_back(DAG.getNode(ISD::TRUNCATE, dl, HiLoVT, Next)); return true; } bool TargetLowering::expandMUL(SDNode *N, SDValue &Lo, SDValue &Hi, EVT HiLoVT, SelectionDAG &DAG, MulExpansionKind Kind, SDValue LL, SDValue LH, SDValue RL, SDValue RH) const { SmallVector Result; bool Ok = expandMUL_LOHI(N->getOpcode(), N->getValueType(0), N, N->getOperand(0), N->getOperand(1), Result, HiLoVT, DAG, Kind, LL, LH, RL, RH); if (Ok) { assert(Result.size() == 2); Lo = Result[0]; Hi = Result[1]; } return Ok; } bool TargetLowering::expandFunnelShift(SDNode *Node, SDValue &Result, SelectionDAG &DAG) const { EVT VT = Node->getValueType(0); if (VT.isVector() && (!isOperationLegalOrCustom(ISD::SHL, VT) || !isOperationLegalOrCustom(ISD::SRL, VT) || !isOperationLegalOrCustom(ISD::SUB, VT) || !isOperationLegalOrCustomOrPromote(ISD::OR, VT))) return false; // fshl: (X << (Z % BW)) | (Y >> (BW - (Z % BW))) // fshr: (X << (BW - (Z % BW))) | (Y >> (Z % BW)) SDValue X = Node->getOperand(0); SDValue Y = Node->getOperand(1); SDValue Z = Node->getOperand(2); unsigned EltSizeInBits = VT.getScalarSizeInBits(); bool IsFSHL = Node->getOpcode() == ISD::FSHL; SDLoc DL(SDValue(Node, 0)); EVT ShVT = Z.getValueType(); SDValue BitWidthC = DAG.getConstant(EltSizeInBits, DL, ShVT); SDValue Zero = DAG.getConstant(0, DL, ShVT); SDValue ShAmt; if (isPowerOf2_32(EltSizeInBits)) { SDValue Mask = DAG.getConstant(EltSizeInBits - 1, DL, ShVT); ShAmt = DAG.getNode(ISD::AND, DL, ShVT, Z, Mask); } else { ShAmt = DAG.getNode(ISD::UREM, DL, ShVT, Z, BitWidthC); } SDValue InvShAmt = DAG.getNode(ISD::SUB, DL, ShVT, BitWidthC, ShAmt); SDValue ShX = DAG.getNode(ISD::SHL, DL, VT, X, IsFSHL ? ShAmt : InvShAmt); SDValue ShY = DAG.getNode(ISD::SRL, DL, VT, Y, IsFSHL ? InvShAmt : ShAmt); SDValue Or = DAG.getNode(ISD::OR, DL, VT, ShX, ShY); // If (Z % BW == 0), then the opposite direction shift is shift-by-bitwidth, // and that is undefined. We must compare and select to avoid UB. EVT CCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), ShVT); // For fshl, 0-shift returns the 1st arg (X). // For fshr, 0-shift returns the 2nd arg (Y). SDValue IsZeroShift = DAG.getSetCC(DL, CCVT, ShAmt, Zero, ISD::SETEQ); Result = DAG.getSelect(DL, VT, IsZeroShift, IsFSHL ? X : Y, Or); return true; } // TODO: Merge with expandFunnelShift. bool TargetLowering::expandROT(SDNode *Node, SDValue &Result, SelectionDAG &DAG) const { EVT VT = Node->getValueType(0); unsigned EltSizeInBits = VT.getScalarSizeInBits(); bool IsLeft = Node->getOpcode() == ISD::ROTL; SDValue Op0 = Node->getOperand(0); SDValue Op1 = Node->getOperand(1); SDLoc DL(SDValue(Node, 0)); EVT ShVT = Op1.getValueType(); SDValue BitWidthC = DAG.getConstant(EltSizeInBits, DL, ShVT); // If a rotate in the other direction is legal, use it. unsigned RevRot = IsLeft ? ISD::ROTR : ISD::ROTL; if (isOperationLegal(RevRot, VT)) { SDValue Sub = DAG.getNode(ISD::SUB, DL, ShVT, BitWidthC, Op1); Result = DAG.getNode(RevRot, DL, VT, Op0, Sub); return true; } if (VT.isVector() && (!isOperationLegalOrCustom(ISD::SHL, VT) || !isOperationLegalOrCustom(ISD::SRL, VT) || !isOperationLegalOrCustom(ISD::SUB, VT) || !isOperationLegalOrCustomOrPromote(ISD::OR, VT) || !isOperationLegalOrCustomOrPromote(ISD::AND, VT))) return false; // Otherwise, // (rotl x, c) -> (or (shl x, (and c, w-1)), (srl x, (and w-c, w-1))) // (rotr x, c) -> (or (srl x, (and c, w-1)), (shl x, (and w-c, w-1))) // assert(isPowerOf2_32(EltSizeInBits) && EltSizeInBits > 1 && "Expecting the type bitwidth to be a power of 2"); unsigned ShOpc = IsLeft ? ISD::SHL : ISD::SRL; unsigned HsOpc = IsLeft ? ISD::SRL : ISD::SHL; SDValue BitWidthMinusOneC = DAG.getConstant(EltSizeInBits - 1, DL, ShVT); SDValue NegOp1 = DAG.getNode(ISD::SUB, DL, ShVT, BitWidthC, Op1); SDValue And0 = DAG.getNode(ISD::AND, DL, ShVT, Op1, BitWidthMinusOneC); SDValue And1 = DAG.getNode(ISD::AND, DL, ShVT, NegOp1, BitWidthMinusOneC); Result = DAG.getNode(ISD::OR, DL, VT, DAG.getNode(ShOpc, DL, VT, Op0, And0), DAG.getNode(HsOpc, DL, VT, Op0, And1)); return true; } bool TargetLowering::expandFP_TO_SINT(SDNode *Node, SDValue &Result, SelectionDAG &DAG) const { unsigned OpNo = Node->isStrictFPOpcode() ? 1 : 0; SDValue Src = Node->getOperand(OpNo); EVT SrcVT = Src.getValueType(); EVT DstVT = Node->getValueType(0); SDLoc dl(SDValue(Node, 0)); // FIXME: Only f32 to i64 conversions are supported. if (SrcVT != MVT::f32 || DstVT != MVT::i64) return false; if (Node->isStrictFPOpcode()) // When a NaN is converted to an integer a trap is allowed. We can't // use this expansion here because it would eliminate that trap. Other // traps are also allowed and cannot be eliminated. See // IEEE 754-2008 sec 5.8. return false; // Expand f32 -> i64 conversion // This algorithm comes from compiler-rt's implementation of fixsfdi: // https://github.com/llvm/llvm-project/blob/master/compiler-rt/lib/builtins/fixsfdi.c unsigned SrcEltBits = SrcVT.getScalarSizeInBits(); EVT IntVT = SrcVT.changeTypeToInteger(); EVT IntShVT = getShiftAmountTy(IntVT, DAG.getDataLayout()); SDValue ExponentMask = DAG.getConstant(0x7F800000, dl, IntVT); SDValue ExponentLoBit = DAG.getConstant(23, dl, IntVT); SDValue Bias = DAG.getConstant(127, dl, IntVT); SDValue SignMask = DAG.getConstant(APInt::getSignMask(SrcEltBits), dl, IntVT); SDValue SignLowBit = DAG.getConstant(SrcEltBits - 1, dl, IntVT); SDValue MantissaMask = DAG.getConstant(0x007FFFFF, dl, IntVT); SDValue Bits = DAG.getNode(ISD::BITCAST, dl, IntVT, Src); SDValue ExponentBits = DAG.getNode( ISD::SRL, dl, IntVT, DAG.getNode(ISD::AND, dl, IntVT, Bits, ExponentMask), DAG.getZExtOrTrunc(ExponentLoBit, dl, IntShVT)); SDValue Exponent = DAG.getNode(ISD::SUB, dl, IntVT, ExponentBits, Bias); SDValue Sign = DAG.getNode(ISD::SRA, dl, IntVT, DAG.getNode(ISD::AND, dl, IntVT, Bits, SignMask), DAG.getZExtOrTrunc(SignLowBit, dl, IntShVT)); Sign = DAG.getSExtOrTrunc(Sign, dl, DstVT); SDValue R = DAG.getNode(ISD::OR, dl, IntVT, DAG.getNode(ISD::AND, dl, IntVT, Bits, MantissaMask), DAG.getConstant(0x00800000, dl, IntVT)); R = DAG.getZExtOrTrunc(R, dl, DstVT); R = DAG.getSelectCC( dl, Exponent, ExponentLoBit, DAG.getNode(ISD::SHL, dl, DstVT, R, DAG.getZExtOrTrunc( DAG.getNode(ISD::SUB, dl, IntVT, Exponent, ExponentLoBit), dl, IntShVT)), DAG.getNode(ISD::SRL, dl, DstVT, R, DAG.getZExtOrTrunc( DAG.getNode(ISD::SUB, dl, IntVT, ExponentLoBit, Exponent), dl, IntShVT)), ISD::SETGT); SDValue Ret = DAG.getNode(ISD::SUB, dl, DstVT, DAG.getNode(ISD::XOR, dl, DstVT, R, Sign), Sign); Result = DAG.getSelectCC(dl, Exponent, DAG.getConstant(0, dl, IntVT), DAG.getConstant(0, dl, DstVT), Ret, ISD::SETLT); return true; } bool TargetLowering::expandFP_TO_UINT(SDNode *Node, SDValue &Result, SDValue &Chain, SelectionDAG &DAG) const { SDLoc dl(SDValue(Node, 0)); unsigned OpNo = Node->isStrictFPOpcode() ? 1 : 0; SDValue Src = Node->getOperand(OpNo); EVT SrcVT = Src.getValueType(); EVT DstVT = Node->getValueType(0); EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), SrcVT); EVT DstSetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), DstVT); // Only expand vector types if we have the appropriate vector bit operations. unsigned SIntOpcode = Node->isStrictFPOpcode() ? ISD::STRICT_FP_TO_SINT : ISD::FP_TO_SINT; if (DstVT.isVector() && (!isOperationLegalOrCustom(SIntOpcode, DstVT) || !isOperationLegalOrCustomOrPromote(ISD::XOR, SrcVT))) return false; // If the maximum float value is smaller then the signed integer range, // the destination signmask can't be represented by the float, so we can // just use FP_TO_SINT directly. const fltSemantics &APFSem = DAG.EVTToAPFloatSemantics(SrcVT); APFloat APF(APFSem, APInt::getNullValue(SrcVT.getScalarSizeInBits())); APInt SignMask = APInt::getSignMask(DstVT.getScalarSizeInBits()); if (APFloat::opOverflow & APF.convertFromAPInt(SignMask, false, APFloat::rmNearestTiesToEven)) { if (Node->isStrictFPOpcode()) { Result = DAG.getNode(ISD::STRICT_FP_TO_SINT, dl, { DstVT, MVT::Other }, { Node->getOperand(0), Src }); Chain = Result.getValue(1); } else Result = DAG.getNode(ISD::FP_TO_SINT, dl, DstVT, Src); return true; } SDValue Cst = DAG.getConstantFP(APF, dl, SrcVT); SDValue Sel; if (Node->isStrictFPOpcode()) { Sel = DAG.getSetCC(dl, SetCCVT, Src, Cst, ISD::SETLT, Node->getOperand(0), /*IsSignaling*/ true); Chain = Sel.getValue(1); } else { Sel = DAG.getSetCC(dl, SetCCVT, Src, Cst, ISD::SETLT); } bool Strict = Node->isStrictFPOpcode() || shouldUseStrictFP_TO_INT(SrcVT, DstVT, /*IsSigned*/ false); if (Strict) { // Expand based on maximum range of FP_TO_SINT, if the value exceeds the // signmask then offset (the result of which should be fully representable). // Sel = Src < 0x8000000000000000 // FltOfs = select Sel, 0, 0x8000000000000000 // IntOfs = select Sel, 0, 0x8000000000000000 // Result = fp_to_sint(Src - FltOfs) ^ IntOfs // TODO: Should any fast-math-flags be set for the FSUB? SDValue FltOfs = DAG.getSelect(dl, SrcVT, Sel, DAG.getConstantFP(0.0, dl, SrcVT), Cst); Sel = DAG.getBoolExtOrTrunc(Sel, dl, DstSetCCVT, DstVT); SDValue IntOfs = DAG.getSelect(dl, DstVT, Sel, DAG.getConstant(0, dl, DstVT), DAG.getConstant(SignMask, dl, DstVT)); SDValue SInt; if (Node->isStrictFPOpcode()) { SDValue Val = DAG.getNode(ISD::STRICT_FSUB, dl, { SrcVT, MVT::Other }, { Chain, Src, FltOfs }); SInt = DAG.getNode(ISD::STRICT_FP_TO_SINT, dl, { DstVT, MVT::Other }, { Val.getValue(1), Val }); Chain = SInt.getValue(1); } else { SDValue Val = DAG.getNode(ISD::FSUB, dl, SrcVT, Src, FltOfs); SInt = DAG.getNode(ISD::FP_TO_SINT, dl, DstVT, Val); } Result = DAG.getNode(ISD::XOR, dl, DstVT, SInt, IntOfs); } else { // Expand based on maximum range of FP_TO_SINT: // True = fp_to_sint(Src) // False = 0x8000000000000000 + fp_to_sint(Src - 0x8000000000000000) // Result = select (Src < 0x8000000000000000), True, False SDValue True = DAG.getNode(ISD::FP_TO_SINT, dl, DstVT, Src); // TODO: Should any fast-math-flags be set for the FSUB? SDValue False = DAG.getNode(ISD::FP_TO_SINT, dl, DstVT, DAG.getNode(ISD::FSUB, dl, SrcVT, Src, Cst)); False = DAG.getNode(ISD::XOR, dl, DstVT, False, DAG.getConstant(SignMask, dl, DstVT)); Sel = DAG.getBoolExtOrTrunc(Sel, dl, DstSetCCVT, DstVT); Result = DAG.getSelect(dl, DstVT, Sel, True, False); } return true; } bool TargetLowering::expandUINT_TO_FP(SDNode *Node, SDValue &Result, SDValue &Chain, SelectionDAG &DAG) const { unsigned OpNo = Node->isStrictFPOpcode() ? 1 : 0; SDValue Src = Node->getOperand(OpNo); EVT SrcVT = Src.getValueType(); EVT DstVT = Node->getValueType(0); if (SrcVT.getScalarType() != MVT::i64) return false; SDLoc dl(SDValue(Node, 0)); EVT ShiftVT = getShiftAmountTy(SrcVT, DAG.getDataLayout()); if (DstVT.getScalarType() == MVT::f32) { // Only expand vector types if we have the appropriate vector bit // operations. if (SrcVT.isVector() && (!isOperationLegalOrCustom(ISD::SRL, SrcVT) || !isOperationLegalOrCustom(ISD::FADD, DstVT) || !isOperationLegalOrCustom(ISD::SINT_TO_FP, SrcVT) || !isOperationLegalOrCustomOrPromote(ISD::OR, SrcVT) || !isOperationLegalOrCustomOrPromote(ISD::AND, SrcVT))) return false; // For unsigned conversions, convert them to signed conversions using the // algorithm from the x86_64 __floatundisf in compiler_rt. // TODO: This really should be implemented using a branch rather than a // select. We happen to get lucky and machinesink does the right // thing most of the time. This would be a good candidate for a // pseudo-op, or, even better, for whole-function isel. EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), SrcVT); SDValue SignBitTest = DAG.getSetCC( dl, SetCCVT, Src, DAG.getConstant(0, dl, SrcVT), ISD::SETLT); SDValue ShiftConst = DAG.getConstant(1, dl, ShiftVT); SDValue Shr = DAG.getNode(ISD::SRL, dl, SrcVT, Src, ShiftConst); SDValue AndConst = DAG.getConstant(1, dl, SrcVT); SDValue And = DAG.getNode(ISD::AND, dl, SrcVT, Src, AndConst); SDValue Or = DAG.getNode(ISD::OR, dl, SrcVT, And, Shr); SDValue Slow, Fast; if (Node->isStrictFPOpcode()) { // In strict mode, we must avoid spurious exceptions, and therefore // must make sure to only emit a single STRICT_SINT_TO_FP. SDValue InCvt = DAG.getSelect(dl, SrcVT, SignBitTest, Or, Src); Fast = DAG.getNode(ISD::STRICT_SINT_TO_FP, dl, { DstVT, MVT::Other }, { Node->getOperand(0), InCvt }); Slow = DAG.getNode(ISD::STRICT_FADD, dl, { DstVT, MVT::Other }, { Fast.getValue(1), Fast, Fast }); Chain = Slow.getValue(1); // The STRICT_SINT_TO_FP inherits the exception mode from the // incoming STRICT_UINT_TO_FP node; the STRICT_FADD node can // never raise any exception. SDNodeFlags Flags; Flags.setNoFPExcept(Node->getFlags().hasNoFPExcept()); Fast->setFlags(Flags); Flags.setNoFPExcept(true); Slow->setFlags(Flags); } else { SDValue SignCvt = DAG.getNode(ISD::SINT_TO_FP, dl, DstVT, Or); Slow = DAG.getNode(ISD::FADD, dl, DstVT, SignCvt, SignCvt); Fast = DAG.getNode(ISD::SINT_TO_FP, dl, DstVT, Src); } Result = DAG.getSelect(dl, DstVT, SignBitTest, Slow, Fast); return true; } if (DstVT.getScalarType() == MVT::f64) { // Only expand vector types if we have the appropriate vector bit // operations. if (SrcVT.isVector() && (!isOperationLegalOrCustom(ISD::SRL, SrcVT) || !isOperationLegalOrCustom(ISD::FADD, DstVT) || !isOperationLegalOrCustom(ISD::FSUB, DstVT) || !isOperationLegalOrCustomOrPromote(ISD::OR, SrcVT) || !isOperationLegalOrCustomOrPromote(ISD::AND, SrcVT))) return false; // Implementation of unsigned i64 to f64 following the algorithm in // __floatundidf in compiler_rt. This implementation has the advantage // of performing rounding correctly, both in the default rounding mode // and in all alternate rounding modes. SDValue TwoP52 = DAG.getConstant(UINT64_C(0x4330000000000000), dl, SrcVT); SDValue TwoP84PlusTwoP52 = DAG.getConstantFP( BitsToDouble(UINT64_C(0x4530000000100000)), dl, DstVT); SDValue TwoP84 = DAG.getConstant(UINT64_C(0x4530000000000000), dl, SrcVT); SDValue LoMask = DAG.getConstant(UINT64_C(0x00000000FFFFFFFF), dl, SrcVT); SDValue HiShift = DAG.getConstant(32, dl, ShiftVT); SDValue Lo = DAG.getNode(ISD::AND, dl, SrcVT, Src, LoMask); SDValue Hi = DAG.getNode(ISD::SRL, dl, SrcVT, Src, HiShift); SDValue LoOr = DAG.getNode(ISD::OR, dl, SrcVT, Lo, TwoP52); SDValue HiOr = DAG.getNode(ISD::OR, dl, SrcVT, Hi, TwoP84); SDValue LoFlt = DAG.getBitcast(DstVT, LoOr); SDValue HiFlt = DAG.getBitcast(DstVT, HiOr); if (Node->isStrictFPOpcode()) { SDValue HiSub = DAG.getNode(ISD::STRICT_FSUB, dl, {DstVT, MVT::Other}, {Node->getOperand(0), HiFlt, TwoP84PlusTwoP52}); Result = DAG.getNode(ISD::STRICT_FADD, dl, {DstVT, MVT::Other}, {HiSub.getValue(1), LoFlt, HiSub}); Chain = Result.getValue(1); } else { SDValue HiSub = DAG.getNode(ISD::FSUB, dl, DstVT, HiFlt, TwoP84PlusTwoP52); Result = DAG.getNode(ISD::FADD, dl, DstVT, LoFlt, HiSub); } return true; } return false; } SDValue TargetLowering::expandFMINNUM_FMAXNUM(SDNode *Node, SelectionDAG &DAG) const { SDLoc dl(Node); unsigned NewOp = Node->getOpcode() == ISD::FMINNUM ? ISD::FMINNUM_IEEE : ISD::FMAXNUM_IEEE; EVT VT = Node->getValueType(0); if (isOperationLegalOrCustom(NewOp, VT)) { SDValue Quiet0 = Node->getOperand(0); SDValue Quiet1 = Node->getOperand(1); if (!Node->getFlags().hasNoNaNs()) { // Insert canonicalizes if it's possible we need to quiet to get correct // sNaN behavior. if (!DAG.isKnownNeverSNaN(Quiet0)) { Quiet0 = DAG.getNode(ISD::FCANONICALIZE, dl, VT, Quiet0, Node->getFlags()); } if (!DAG.isKnownNeverSNaN(Quiet1)) { Quiet1 = DAG.getNode(ISD::FCANONICALIZE, dl, VT, Quiet1, Node->getFlags()); } } return DAG.getNode(NewOp, dl, VT, Quiet0, Quiet1, Node->getFlags()); } // If the target has FMINIMUM/FMAXIMUM but not FMINNUM/FMAXNUM use that // instead if there are no NaNs. if (Node->getFlags().hasNoNaNs()) { unsigned IEEE2018Op = Node->getOpcode() == ISD::FMINNUM ? ISD::FMINIMUM : ISD::FMAXIMUM; if (isOperationLegalOrCustom(IEEE2018Op, VT)) { return DAG.getNode(IEEE2018Op, dl, VT, Node->getOperand(0), Node->getOperand(1), Node->getFlags()); } } // If none of the above worked, but there are no NaNs, then expand to // a compare/select sequence. This is required for correctness since // InstCombine might have canonicalized a fcmp+select sequence to a // FMINNUM/FMAXNUM node. If we were to fall through to the default // expansion to libcall, we might introduce a link-time dependency // on libm into a file that originally did not have one. if (Node->getFlags().hasNoNaNs()) { ISD::CondCode Pred = Node->getOpcode() == ISD::FMINNUM ? ISD::SETLT : ISD::SETGT; SDValue Op1 = Node->getOperand(0); SDValue Op2 = Node->getOperand(1); SDValue SelCC = DAG.getSelectCC(dl, Op1, Op2, Op1, Op2, Pred); // Copy FMF flags, but always set the no-signed-zeros flag // as this is implied by the FMINNUM/FMAXNUM semantics. SDNodeFlags Flags = Node->getFlags(); Flags.setNoSignedZeros(true); SelCC->setFlags(Flags); return SelCC; } return SDValue(); } bool TargetLowering::expandCTPOP(SDNode *Node, SDValue &Result, SelectionDAG &DAG) const { SDLoc dl(Node); EVT VT = Node->getValueType(0); EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout()); SDValue Op = Node->getOperand(0); unsigned Len = VT.getScalarSizeInBits(); assert(VT.isInteger() && "CTPOP not implemented for this type."); // TODO: Add support for irregular type lengths. if (!(Len <= 128 && Len % 8 == 0)) return false; // Only expand vector types if we have the appropriate vector bit operations. if (VT.isVector() && (!isOperationLegalOrCustom(ISD::ADD, VT) || !isOperationLegalOrCustom(ISD::SUB, VT) || !isOperationLegalOrCustom(ISD::SRL, VT) || (Len != 8 && !isOperationLegalOrCustom(ISD::MUL, VT)) || !isOperationLegalOrCustomOrPromote(ISD::AND, VT))) return false; // This is the "best" algorithm from // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel SDValue Mask55 = DAG.getConstant(APInt::getSplat(Len, APInt(8, 0x55)), dl, VT); SDValue Mask33 = DAG.getConstant(APInt::getSplat(Len, APInt(8, 0x33)), dl, VT); SDValue Mask0F = DAG.getConstant(APInt::getSplat(Len, APInt(8, 0x0F)), dl, VT); SDValue Mask01 = DAG.getConstant(APInt::getSplat(Len, APInt(8, 0x01)), dl, VT); // v = v - ((v >> 1) & 0x55555555...) Op = DAG.getNode(ISD::SUB, dl, VT, Op, DAG.getNode(ISD::AND, dl, VT, DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(1, dl, ShVT)), Mask55)); // v = (v & 0x33333333...) + ((v >> 2) & 0x33333333...) Op = DAG.getNode(ISD::ADD, dl, VT, DAG.getNode(ISD::AND, dl, VT, Op, Mask33), DAG.getNode(ISD::AND, dl, VT, DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(2, dl, ShVT)), Mask33)); // v = (v + (v >> 4)) & 0x0F0F0F0F... Op = DAG.getNode(ISD::AND, dl, VT, DAG.getNode(ISD::ADD, dl, VT, Op, DAG.getNode(ISD::SRL, dl, VT, Op, DAG.getConstant(4, dl, ShVT))), Mask0F); // v = (v * 0x01010101...) >> (Len - 8) if (Len > 8) Op = DAG.getNode(ISD::SRL, dl, VT, DAG.getNode(ISD::MUL, dl, VT, Op, Mask01), DAG.getConstant(Len - 8, dl, ShVT)); Result = Op; return true; } bool TargetLowering::expandCTLZ(SDNode *Node, SDValue &Result, SelectionDAG &DAG) const { SDLoc dl(Node); EVT VT = Node->getValueType(0); EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout()); SDValue Op = Node->getOperand(0); unsigned NumBitsPerElt = VT.getScalarSizeInBits(); // If the non-ZERO_UNDEF version is supported we can use that instead. if (Node->getOpcode() == ISD::CTLZ_ZERO_UNDEF && isOperationLegalOrCustom(ISD::CTLZ, VT)) { Result = DAG.getNode(ISD::CTLZ, dl, VT, Op); return true; } // If the ZERO_UNDEF version is supported use that and handle the zero case. if (isOperationLegalOrCustom(ISD::CTLZ_ZERO_UNDEF, VT)) { EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); SDValue CTLZ = DAG.getNode(ISD::CTLZ_ZERO_UNDEF, dl, VT, Op); SDValue Zero = DAG.getConstant(0, dl, VT); SDValue SrcIsZero = DAG.getSetCC(dl, SetCCVT, Op, Zero, ISD::SETEQ); Result = DAG.getNode(ISD::SELECT, dl, VT, SrcIsZero, DAG.getConstant(NumBitsPerElt, dl, VT), CTLZ); return true; } // Only expand vector types if we have the appropriate vector bit operations. if (VT.isVector() && (!isPowerOf2_32(NumBitsPerElt) || !isOperationLegalOrCustom(ISD::CTPOP, VT) || !isOperationLegalOrCustom(ISD::SRL, VT) || !isOperationLegalOrCustomOrPromote(ISD::OR, VT))) return false; // for now, we do this: // x = x | (x >> 1); // x = x | (x >> 2); // ... // x = x | (x >>16); // x = x | (x >>32); // for 64-bit input // return popcount(~x); // // Ref: "Hacker's Delight" by Henry Warren for (unsigned i = 0; (1U << i) <= (NumBitsPerElt / 2); ++i) { SDValue Tmp = DAG.getConstant(1ULL << i, dl, ShVT); Op = DAG.getNode(ISD::OR, dl, VT, Op, DAG.getNode(ISD::SRL, dl, VT, Op, Tmp)); } Op = DAG.getNOT(dl, Op, VT); Result = DAG.getNode(ISD::CTPOP, dl, VT, Op); return true; } bool TargetLowering::expandCTTZ(SDNode *Node, SDValue &Result, SelectionDAG &DAG) const { SDLoc dl(Node); EVT VT = Node->getValueType(0); SDValue Op = Node->getOperand(0); unsigned NumBitsPerElt = VT.getScalarSizeInBits(); // If the non-ZERO_UNDEF version is supported we can use that instead. if (Node->getOpcode() == ISD::CTTZ_ZERO_UNDEF && isOperationLegalOrCustom(ISD::CTTZ, VT)) { Result = DAG.getNode(ISD::CTTZ, dl, VT, Op); return true; } // If the ZERO_UNDEF version is supported use that and handle the zero case. if (isOperationLegalOrCustom(ISD::CTTZ_ZERO_UNDEF, VT)) { EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); SDValue CTTZ = DAG.getNode(ISD::CTTZ_ZERO_UNDEF, dl, VT, Op); SDValue Zero = DAG.getConstant(0, dl, VT); SDValue SrcIsZero = DAG.getSetCC(dl, SetCCVT, Op, Zero, ISD::SETEQ); Result = DAG.getNode(ISD::SELECT, dl, VT, SrcIsZero, DAG.getConstant(NumBitsPerElt, dl, VT), CTTZ); return true; } // Only expand vector types if we have the appropriate vector bit operations. if (VT.isVector() && (!isPowerOf2_32(NumBitsPerElt) || (!isOperationLegalOrCustom(ISD::CTPOP, VT) && !isOperationLegalOrCustom(ISD::CTLZ, VT)) || !isOperationLegalOrCustom(ISD::SUB, VT) || !isOperationLegalOrCustomOrPromote(ISD::AND, VT) || !isOperationLegalOrCustomOrPromote(ISD::XOR, VT))) return false; // for now, we use: { return popcount(~x & (x - 1)); } // unless the target has ctlz but not ctpop, in which case we use: // { return 32 - nlz(~x & (x-1)); } // Ref: "Hacker's Delight" by Henry Warren SDValue Tmp = DAG.getNode( ISD::AND, dl, VT, DAG.getNOT(dl, Op, VT), DAG.getNode(ISD::SUB, dl, VT, Op, DAG.getConstant(1, dl, VT))); // If ISD::CTLZ is legal and CTPOP isn't, then do that instead. if (isOperationLegal(ISD::CTLZ, VT) && !isOperationLegal(ISD::CTPOP, VT)) { Result = DAG.getNode(ISD::SUB, dl, VT, DAG.getConstant(NumBitsPerElt, dl, VT), DAG.getNode(ISD::CTLZ, dl, VT, Tmp)); return true; } Result = DAG.getNode(ISD::CTPOP, dl, VT, Tmp); return true; } bool TargetLowering::expandABS(SDNode *N, SDValue &Result, SelectionDAG &DAG) const { SDLoc dl(N); EVT VT = N->getValueType(0); EVT ShVT = getShiftAmountTy(VT, DAG.getDataLayout()); SDValue Op = N->getOperand(0); // Only expand vector types if we have the appropriate vector operations. if (VT.isVector() && (!isOperationLegalOrCustom(ISD::SRA, VT) || !isOperationLegalOrCustom(ISD::ADD, VT) || !isOperationLegalOrCustomOrPromote(ISD::XOR, VT))) return false; SDValue Shift = DAG.getNode(ISD::SRA, dl, VT, Op, DAG.getConstant(VT.getScalarSizeInBits() - 1, dl, ShVT)); SDValue Add = DAG.getNode(ISD::ADD, dl, VT, Op, Shift); Result = DAG.getNode(ISD::XOR, dl, VT, Add, Shift); return true; } std::pair TargetLowering::scalarizeVectorLoad(LoadSDNode *LD, SelectionDAG &DAG) const { SDLoc SL(LD); SDValue Chain = LD->getChain(); SDValue BasePTR = LD->getBasePtr(); EVT SrcVT = LD->getMemoryVT(); ISD::LoadExtType ExtType = LD->getExtensionType(); unsigned NumElem = SrcVT.getVectorNumElements(); EVT SrcEltVT = SrcVT.getScalarType(); EVT DstEltVT = LD->getValueType(0).getScalarType(); unsigned Stride = SrcEltVT.getSizeInBits() / 8; assert(SrcEltVT.isByteSized()); SmallVector Vals; SmallVector LoadChains; for (unsigned Idx = 0; Idx < NumElem; ++Idx) { SDValue ScalarLoad = DAG.getExtLoad(ExtType, SL, DstEltVT, Chain, BasePTR, LD->getPointerInfo().getWithOffset(Idx * Stride), SrcEltVT, MinAlign(LD->getAlignment(), Idx * Stride), LD->getMemOperand()->getFlags(), LD->getAAInfo()); BasePTR = DAG.getObjectPtrOffset(SL, BasePTR, Stride); Vals.push_back(ScalarLoad.getValue(0)); LoadChains.push_back(ScalarLoad.getValue(1)); } SDValue NewChain = DAG.getNode(ISD::TokenFactor, SL, MVT::Other, LoadChains); SDValue Value = DAG.getBuildVector(LD->getValueType(0), SL, Vals); return std::make_pair(Value, NewChain); } SDValue TargetLowering::scalarizeVectorStore(StoreSDNode *ST, SelectionDAG &DAG) const { SDLoc SL(ST); SDValue Chain = ST->getChain(); SDValue BasePtr = ST->getBasePtr(); SDValue Value = ST->getValue(); EVT StVT = ST->getMemoryVT(); // The type of the data we want to save EVT RegVT = Value.getValueType(); EVT RegSclVT = RegVT.getScalarType(); // The type of data as saved in memory. EVT MemSclVT = StVT.getScalarType(); EVT IdxVT = getVectorIdxTy(DAG.getDataLayout()); unsigned NumElem = StVT.getVectorNumElements(); // A vector must always be stored in memory as-is, i.e. without any padding // between the elements, since various code depend on it, e.g. in the // handling of a bitcast of a vector type to int, which may be done with a // vector store followed by an integer load. A vector that does not have // elements that are byte-sized must therefore be stored as an integer // built out of the extracted vector elements. if (!MemSclVT.isByteSized()) { unsigned NumBits = StVT.getSizeInBits(); EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), NumBits); SDValue CurrVal = DAG.getConstant(0, SL, IntVT); for (unsigned Idx = 0; Idx < NumElem; ++Idx) { SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, RegSclVT, Value, DAG.getConstant(Idx, SL, IdxVT)); SDValue Trunc = DAG.getNode(ISD::TRUNCATE, SL, MemSclVT, Elt); SDValue ExtElt = DAG.getNode(ISD::ZERO_EXTEND, SL, IntVT, Trunc); unsigned ShiftIntoIdx = (DAG.getDataLayout().isBigEndian() ? (NumElem - 1) - Idx : Idx); SDValue ShiftAmount = DAG.getConstant(ShiftIntoIdx * MemSclVT.getSizeInBits(), SL, IntVT); SDValue ShiftedElt = DAG.getNode(ISD::SHL, SL, IntVT, ExtElt, ShiftAmount); CurrVal = DAG.getNode(ISD::OR, SL, IntVT, CurrVal, ShiftedElt); } return DAG.getStore(Chain, SL, CurrVal, BasePtr, ST->getPointerInfo(), ST->getAlignment(), ST->getMemOperand()->getFlags(), ST->getAAInfo()); } // Store Stride in bytes unsigned Stride = MemSclVT.getSizeInBits() / 8; assert(Stride && "Zero stride!"); // Extract each of the elements from the original vector and save them into // memory individually. SmallVector Stores; for (unsigned Idx = 0; Idx < NumElem; ++Idx) { SDValue Elt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, SL, RegSclVT, Value, DAG.getConstant(Idx, SL, IdxVT)); SDValue Ptr = DAG.getObjectPtrOffset(SL, BasePtr, Idx * Stride); // This scalar TruncStore may be illegal, but we legalize it later. SDValue Store = DAG.getTruncStore( Chain, SL, Elt, Ptr, ST->getPointerInfo().getWithOffset(Idx * Stride), MemSclVT, MinAlign(ST->getAlignment(), Idx * Stride), ST->getMemOperand()->getFlags(), ST->getAAInfo()); Stores.push_back(Store); } return DAG.getNode(ISD::TokenFactor, SL, MVT::Other, Stores); } std::pair TargetLowering::expandUnalignedLoad(LoadSDNode *LD, SelectionDAG &DAG) const { assert(LD->getAddressingMode() == ISD::UNINDEXED && "unaligned indexed loads not implemented!"); SDValue Chain = LD->getChain(); SDValue Ptr = LD->getBasePtr(); EVT VT = LD->getValueType(0); EVT LoadedVT = LD->getMemoryVT(); SDLoc dl(LD); auto &MF = DAG.getMachineFunction(); if (VT.isFloatingPoint() || VT.isVector()) { EVT intVT = EVT::getIntegerVT(*DAG.getContext(), LoadedVT.getSizeInBits()); if (isTypeLegal(intVT) && isTypeLegal(LoadedVT)) { if (!isOperationLegalOrCustom(ISD::LOAD, intVT) && LoadedVT.isVector()) { // Scalarize the load and let the individual components be handled. return scalarizeVectorLoad(LD, DAG); } // Expand to a (misaligned) integer load of the same size, // then bitconvert to floating point or vector. SDValue newLoad = DAG.getLoad(intVT, dl, Chain, Ptr, LD->getMemOperand()); SDValue Result = DAG.getNode(ISD::BITCAST, dl, LoadedVT, newLoad); if (LoadedVT != VT) Result = DAG.getNode(VT.isFloatingPoint() ? ISD::FP_EXTEND : ISD::ANY_EXTEND, dl, VT, Result); return std::make_pair(Result, newLoad.getValue(1)); } // Copy the value to a (aligned) stack slot using (unaligned) integer // loads and stores, then do a (aligned) load from the stack slot. MVT RegVT = getRegisterType(*DAG.getContext(), intVT); unsigned LoadedBytes = LoadedVT.getStoreSize(); unsigned RegBytes = RegVT.getSizeInBits() / 8; unsigned NumRegs = (LoadedBytes + RegBytes - 1) / RegBytes; // Make sure the stack slot is also aligned for the register type. SDValue StackBase = DAG.CreateStackTemporary(LoadedVT, RegVT); auto FrameIndex = cast(StackBase.getNode())->getIndex(); SmallVector Stores; SDValue StackPtr = StackBase; unsigned Offset = 0; EVT PtrVT = Ptr.getValueType(); EVT StackPtrVT = StackPtr.getValueType(); SDValue PtrIncrement = DAG.getConstant(RegBytes, dl, PtrVT); SDValue StackPtrIncrement = DAG.getConstant(RegBytes, dl, StackPtrVT); // Do all but one copies using the full register width. for (unsigned i = 1; i < NumRegs; i++) { // Load one integer register's worth from the original location. SDValue Load = DAG.getLoad( RegVT, dl, Chain, Ptr, LD->getPointerInfo().getWithOffset(Offset), MinAlign(LD->getAlignment(), Offset), LD->getMemOperand()->getFlags(), LD->getAAInfo()); // Follow the load with a store to the stack slot. Remember the store. Stores.push_back(DAG.getStore( Load.getValue(1), dl, Load, StackPtr, MachinePointerInfo::getFixedStack(MF, FrameIndex, Offset))); // Increment the pointers. Offset += RegBytes; Ptr = DAG.getObjectPtrOffset(dl, Ptr, PtrIncrement); StackPtr = DAG.getObjectPtrOffset(dl, StackPtr, StackPtrIncrement); } // The last copy may be partial. Do an extending load. EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), 8 * (LoadedBytes - Offset)); SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, dl, RegVT, Chain, Ptr, LD->getPointerInfo().getWithOffset(Offset), MemVT, MinAlign(LD->getAlignment(), Offset), LD->getMemOperand()->getFlags(), LD->getAAInfo()); // Follow the load with a store to the stack slot. Remember the store. // On big-endian machines this requires a truncating store to ensure // that the bits end up in the right place. Stores.push_back(DAG.getTruncStore( Load.getValue(1), dl, Load, StackPtr, MachinePointerInfo::getFixedStack(MF, FrameIndex, Offset), MemVT)); // The order of the stores doesn't matter - say it with a TokenFactor. SDValue TF = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Stores); // Finally, perform the original load only redirected to the stack slot. Load = DAG.getExtLoad(LD->getExtensionType(), dl, VT, TF, StackBase, MachinePointerInfo::getFixedStack(MF, FrameIndex, 0), LoadedVT); // Callers expect a MERGE_VALUES node. return std::make_pair(Load, TF); } assert(LoadedVT.isInteger() && !LoadedVT.isVector() && "Unaligned load of unsupported type."); // Compute the new VT that is half the size of the old one. This is an // integer MVT. unsigned NumBits = LoadedVT.getSizeInBits(); EVT NewLoadedVT; NewLoadedVT = EVT::getIntegerVT(*DAG.getContext(), NumBits/2); NumBits >>= 1; unsigned Alignment = LD->getAlignment(); unsigned IncrementSize = NumBits / 8; ISD::LoadExtType HiExtType = LD->getExtensionType(); // If the original load is NON_EXTLOAD, the hi part load must be ZEXTLOAD. if (HiExtType == ISD::NON_EXTLOAD) HiExtType = ISD::ZEXTLOAD; // Load the value in two parts SDValue Lo, Hi; if (DAG.getDataLayout().isLittleEndian()) { Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, VT, Chain, Ptr, LD->getPointerInfo(), NewLoadedVT, Alignment, LD->getMemOperand()->getFlags(), LD->getAAInfo()); Ptr = DAG.getObjectPtrOffset(dl, Ptr, IncrementSize); Hi = DAG.getExtLoad(HiExtType, dl, VT, Chain, Ptr, LD->getPointerInfo().getWithOffset(IncrementSize), NewLoadedVT, MinAlign(Alignment, IncrementSize), LD->getMemOperand()->getFlags(), LD->getAAInfo()); } else { Hi = DAG.getExtLoad(HiExtType, dl, VT, Chain, Ptr, LD->getPointerInfo(), NewLoadedVT, Alignment, LD->getMemOperand()->getFlags(), LD->getAAInfo()); Ptr = DAG.getObjectPtrOffset(dl, Ptr, IncrementSize); Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, VT, Chain, Ptr, LD->getPointerInfo().getWithOffset(IncrementSize), NewLoadedVT, MinAlign(Alignment, IncrementSize), LD->getMemOperand()->getFlags(), LD->getAAInfo()); } // aggregate the two parts SDValue ShiftAmount = DAG.getConstant(NumBits, dl, getShiftAmountTy(Hi.getValueType(), DAG.getDataLayout())); SDValue Result = DAG.getNode(ISD::SHL, dl, VT, Hi, ShiftAmount); Result = DAG.getNode(ISD::OR, dl, VT, Result, Lo); SDValue TF = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), Hi.getValue(1)); return std::make_pair(Result, TF); } SDValue TargetLowering::expandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG) const { assert(ST->getAddressingMode() == ISD::UNINDEXED && "unaligned indexed stores not implemented!"); SDValue Chain = ST->getChain(); SDValue Ptr = ST->getBasePtr(); SDValue Val = ST->getValue(); EVT VT = Val.getValueType(); int Alignment = ST->getAlignment(); auto &MF = DAG.getMachineFunction(); EVT StoreMemVT = ST->getMemoryVT(); SDLoc dl(ST); if (StoreMemVT.isFloatingPoint() || StoreMemVT.isVector()) { EVT intVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits()); if (isTypeLegal(intVT)) { if (!isOperationLegalOrCustom(ISD::STORE, intVT) && StoreMemVT.isVector()) { // Scalarize the store and let the individual components be handled. SDValue Result = scalarizeVectorStore(ST, DAG); return Result; } // Expand to a bitconvert of the value to the integer type of the // same size, then a (misaligned) int store. // FIXME: Does not handle truncating floating point stores! SDValue Result = DAG.getNode(ISD::BITCAST, dl, intVT, Val); Result = DAG.getStore(Chain, dl, Result, Ptr, ST->getPointerInfo(), Alignment, ST->getMemOperand()->getFlags()); return Result; } // Do a (aligned) store to a stack slot, then copy from the stack slot // to the final destination using (unaligned) integer loads and stores. MVT RegVT = getRegisterType( *DAG.getContext(), EVT::getIntegerVT(*DAG.getContext(), StoreMemVT.getSizeInBits())); EVT PtrVT = Ptr.getValueType(); unsigned StoredBytes = StoreMemVT.getStoreSize(); unsigned RegBytes = RegVT.getSizeInBits() / 8; unsigned NumRegs = (StoredBytes + RegBytes - 1) / RegBytes; // Make sure the stack slot is also aligned for the register type. SDValue StackPtr = DAG.CreateStackTemporary(StoreMemVT, RegVT); auto FrameIndex = cast(StackPtr.getNode())->getIndex(); // Perform the original store, only redirected to the stack slot. SDValue Store = DAG.getTruncStore( Chain, dl, Val, StackPtr, MachinePointerInfo::getFixedStack(MF, FrameIndex, 0), StoreMemVT); EVT StackPtrVT = StackPtr.getValueType(); SDValue PtrIncrement = DAG.getConstant(RegBytes, dl, PtrVT); SDValue StackPtrIncrement = DAG.getConstant(RegBytes, dl, StackPtrVT); SmallVector Stores; unsigned Offset = 0; // Do all but one copies using the full register width. for (unsigned i = 1; i < NumRegs; i++) { // Load one integer register's worth from the stack slot. SDValue Load = DAG.getLoad( RegVT, dl, Store, StackPtr, MachinePointerInfo::getFixedStack(MF, FrameIndex, Offset)); // Store it to the final location. Remember the store. Stores.push_back(DAG.getStore(Load.getValue(1), dl, Load, Ptr, ST->getPointerInfo().getWithOffset(Offset), MinAlign(ST->getAlignment(), Offset), ST->getMemOperand()->getFlags())); // Increment the pointers. Offset += RegBytes; StackPtr = DAG.getObjectPtrOffset(dl, StackPtr, StackPtrIncrement); Ptr = DAG.getObjectPtrOffset(dl, Ptr, PtrIncrement); } // The last store may be partial. Do a truncating store. On big-endian // machines this requires an extending load from the stack slot to ensure // that the bits are in the right place. EVT LoadMemVT = EVT::getIntegerVT(*DAG.getContext(), 8 * (StoredBytes - Offset)); // Load from the stack slot. SDValue Load = DAG.getExtLoad( ISD::EXTLOAD, dl, RegVT, Store, StackPtr, MachinePointerInfo::getFixedStack(MF, FrameIndex, Offset), LoadMemVT); Stores.push_back( DAG.getTruncStore(Load.getValue(1), dl, Load, Ptr, ST->getPointerInfo().getWithOffset(Offset), LoadMemVT, MinAlign(ST->getAlignment(), Offset), ST->getMemOperand()->getFlags(), ST->getAAInfo())); // The order of the stores doesn't matter - say it with a TokenFactor. SDValue Result = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Stores); return Result; } assert(StoreMemVT.isInteger() && !StoreMemVT.isVector() && "Unaligned store of unknown type."); // Get the half-size VT EVT NewStoredVT = StoreMemVT.getHalfSizedIntegerVT(*DAG.getContext()); int NumBits = NewStoredVT.getSizeInBits(); int IncrementSize = NumBits / 8; // Divide the stored value in two parts. SDValue ShiftAmount = DAG.getConstant( NumBits, dl, getShiftAmountTy(Val.getValueType(), DAG.getDataLayout())); SDValue Lo = Val; SDValue Hi = DAG.getNode(ISD::SRL, dl, VT, Val, ShiftAmount); // Store the two parts SDValue Store1, Store2; Store1 = DAG.getTruncStore(Chain, dl, DAG.getDataLayout().isLittleEndian() ? Lo : Hi, Ptr, ST->getPointerInfo(), NewStoredVT, Alignment, ST->getMemOperand()->getFlags()); Ptr = DAG.getObjectPtrOffset(dl, Ptr, IncrementSize); Alignment = MinAlign(Alignment, IncrementSize); Store2 = DAG.getTruncStore( Chain, dl, DAG.getDataLayout().isLittleEndian() ? Hi : Lo, Ptr, ST->getPointerInfo().getWithOffset(IncrementSize), NewStoredVT, Alignment, ST->getMemOperand()->getFlags(), ST->getAAInfo()); SDValue Result = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Store1, Store2); return Result; } SDValue TargetLowering::IncrementMemoryAddress(SDValue Addr, SDValue Mask, const SDLoc &DL, EVT DataVT, SelectionDAG &DAG, bool IsCompressedMemory) const { SDValue Increment; EVT AddrVT = Addr.getValueType(); EVT MaskVT = Mask.getValueType(); assert(DataVT.getVectorNumElements() == MaskVT.getVectorNumElements() && "Incompatible types of Data and Mask"); if (IsCompressedMemory) { // Incrementing the pointer according to number of '1's in the mask. EVT MaskIntVT = EVT::getIntegerVT(*DAG.getContext(), MaskVT.getSizeInBits()); SDValue MaskInIntReg = DAG.getBitcast(MaskIntVT, Mask); if (MaskIntVT.getSizeInBits() < 32) { MaskInIntReg = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i32, MaskInIntReg); MaskIntVT = MVT::i32; } // Count '1's with POPCNT. Increment = DAG.getNode(ISD::CTPOP, DL, MaskIntVT, MaskInIntReg); Increment = DAG.getZExtOrTrunc(Increment, DL, AddrVT); // Scale is an element size in bytes. SDValue Scale = DAG.getConstant(DataVT.getScalarSizeInBits() / 8, DL, AddrVT); Increment = DAG.getNode(ISD::MUL, DL, AddrVT, Increment, Scale); } else Increment = DAG.getConstant(DataVT.getStoreSize(), DL, AddrVT); return DAG.getNode(ISD::ADD, DL, AddrVT, Addr, Increment); } static SDValue clampDynamicVectorIndex(SelectionDAG &DAG, SDValue Idx, EVT VecVT, const SDLoc &dl) { if (isa(Idx)) return Idx; EVT IdxVT = Idx.getValueType(); unsigned NElts = VecVT.getVectorNumElements(); if (isPowerOf2_32(NElts)) { APInt Imm = APInt::getLowBitsSet(IdxVT.getSizeInBits(), Log2_32(NElts)); return DAG.getNode(ISD::AND, dl, IdxVT, Idx, DAG.getConstant(Imm, dl, IdxVT)); } return DAG.getNode(ISD::UMIN, dl, IdxVT, Idx, DAG.getConstant(NElts - 1, dl, IdxVT)); } SDValue TargetLowering::getVectorElementPointer(SelectionDAG &DAG, SDValue VecPtr, EVT VecVT, SDValue Index) const { SDLoc dl(Index); // Make sure the index type is big enough to compute in. Index = DAG.getZExtOrTrunc(Index, dl, VecPtr.getValueType()); EVT EltVT = VecVT.getVectorElementType(); // Calculate the element offset and add it to the pointer. unsigned EltSize = EltVT.getSizeInBits() / 8; // FIXME: should be ABI size. assert(EltSize * 8 == EltVT.getSizeInBits() && "Converting bits to bytes lost precision"); Index = clampDynamicVectorIndex(DAG, Index, VecVT, dl); EVT IdxVT = Index.getValueType(); Index = DAG.getNode(ISD::MUL, dl, IdxVT, Index, DAG.getConstant(EltSize, dl, IdxVT)); return DAG.getMemBasePlusOffset(VecPtr, Index, dl); } //===----------------------------------------------------------------------===// // Implementation of Emulated TLS Model //===----------------------------------------------------------------------===// SDValue TargetLowering::LowerToTLSEmulatedModel(const GlobalAddressSDNode *GA, SelectionDAG &DAG) const { // Access to address of TLS varialbe xyz is lowered to a function call: // __emutls_get_address( address of global variable named "__emutls_v.xyz" ) EVT PtrVT = getPointerTy(DAG.getDataLayout()); PointerType *VoidPtrType = Type::getInt8PtrTy(*DAG.getContext()); SDLoc dl(GA); ArgListTy Args; ArgListEntry Entry; std::string NameString = ("__emutls_v." + GA->getGlobal()->getName()).str(); Module *VariableModule = const_cast(GA->getGlobal()->getParent()); StringRef EmuTlsVarName(NameString); GlobalVariable *EmuTlsVar = VariableModule->getNamedGlobal(EmuTlsVarName); assert(EmuTlsVar && "Cannot find EmuTlsVar "); Entry.Node = DAG.getGlobalAddress(EmuTlsVar, dl, PtrVT); Entry.Ty = VoidPtrType; Args.push_back(Entry); SDValue EmuTlsGetAddr = DAG.getExternalSymbol("__emutls_get_address", PtrVT); TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl).setChain(DAG.getEntryNode()); CLI.setLibCallee(CallingConv::C, VoidPtrType, EmuTlsGetAddr, std::move(Args)); std::pair CallResult = LowerCallTo(CLI); // TLSADDR will be codegen'ed as call. Inform MFI that function has calls. // At last for X86 targets, maybe good for other targets too? MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo(); MFI.setAdjustsStack(true); // Is this only for X86 target? MFI.setHasCalls(true); assert((GA->getOffset() == 0) && "Emulated TLS must have zero offset in GlobalAddressSDNode"); return CallResult.first; } SDValue TargetLowering::lowerCmpEqZeroToCtlzSrl(SDValue Op, SelectionDAG &DAG) const { assert((Op->getOpcode() == ISD::SETCC) && "Input has to be a SETCC node."); if (!isCtlzFast()) return SDValue(); ISD::CondCode CC = cast(Op.getOperand(2))->get(); SDLoc dl(Op); if (ConstantSDNode *C = dyn_cast(Op.getOperand(1))) { if (C->isNullValue() && CC == ISD::SETEQ) { EVT VT = Op.getOperand(0).getValueType(); SDValue Zext = Op.getOperand(0); if (VT.bitsLT(MVT::i32)) { VT = MVT::i32; Zext = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Op.getOperand(0)); } unsigned Log2b = Log2_32(VT.getSizeInBits()); SDValue Clz = DAG.getNode(ISD::CTLZ, dl, VT, Zext); SDValue Scc = DAG.getNode(ISD::SRL, dl, VT, Clz, DAG.getConstant(Log2b, dl, MVT::i32)); return DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Scc); } } return SDValue(); } SDValue TargetLowering::expandAddSubSat(SDNode *Node, SelectionDAG &DAG) const { unsigned Opcode = Node->getOpcode(); SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); EVT VT = LHS.getValueType(); SDLoc dl(Node); assert(VT == RHS.getValueType() && "Expected operands to be the same type"); assert(VT.isInteger() && "Expected operands to be integers"); // usub.sat(a, b) -> umax(a, b) - b if (Opcode == ISD::USUBSAT && isOperationLegalOrCustom(ISD::UMAX, VT)) { SDValue Max = DAG.getNode(ISD::UMAX, dl, VT, LHS, RHS); return DAG.getNode(ISD::SUB, dl, VT, Max, RHS); } if (Opcode == ISD::UADDSAT && isOperationLegalOrCustom(ISD::UMIN, VT)) { SDValue InvRHS = DAG.getNOT(dl, RHS, VT); SDValue Min = DAG.getNode(ISD::UMIN, dl, VT, LHS, InvRHS); return DAG.getNode(ISD::ADD, dl, VT, Min, RHS); } unsigned OverflowOp; switch (Opcode) { case ISD::SADDSAT: OverflowOp = ISD::SADDO; break; case ISD::UADDSAT: OverflowOp = ISD::UADDO; break; case ISD::SSUBSAT: OverflowOp = ISD::SSUBO; break; case ISD::USUBSAT: OverflowOp = ISD::USUBO; break; default: llvm_unreachable("Expected method to receive signed or unsigned saturation " "addition or subtraction node."); } unsigned BitWidth = LHS.getScalarValueSizeInBits(); EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); SDValue Result = DAG.getNode(OverflowOp, dl, DAG.getVTList(VT, BoolVT), LHS, RHS); SDValue SumDiff = Result.getValue(0); SDValue Overflow = Result.getValue(1); SDValue Zero = DAG.getConstant(0, dl, VT); SDValue AllOnes = DAG.getAllOnesConstant(dl, VT); if (Opcode == ISD::UADDSAT) { if (getBooleanContents(VT) == ZeroOrNegativeOneBooleanContent) { // (LHS + RHS) | OverflowMask SDValue OverflowMask = DAG.getSExtOrTrunc(Overflow, dl, VT); return DAG.getNode(ISD::OR, dl, VT, SumDiff, OverflowMask); } // Overflow ? 0xffff.... : (LHS + RHS) return DAG.getSelect(dl, VT, Overflow, AllOnes, SumDiff); } else if (Opcode == ISD::USUBSAT) { if (getBooleanContents(VT) == ZeroOrNegativeOneBooleanContent) { // (LHS - RHS) & ~OverflowMask SDValue OverflowMask = DAG.getSExtOrTrunc(Overflow, dl, VT); SDValue Not = DAG.getNOT(dl, OverflowMask, VT); return DAG.getNode(ISD::AND, dl, VT, SumDiff, Not); } // Overflow ? 0 : (LHS - RHS) return DAG.getSelect(dl, VT, Overflow, Zero, SumDiff); } else { // SatMax -> Overflow && SumDiff < 0 // SatMin -> Overflow && SumDiff >= 0 APInt MinVal = APInt::getSignedMinValue(BitWidth); APInt MaxVal = APInt::getSignedMaxValue(BitWidth); SDValue SatMin = DAG.getConstant(MinVal, dl, VT); SDValue SatMax = DAG.getConstant(MaxVal, dl, VT); SDValue SumNeg = DAG.getSetCC(dl, BoolVT, SumDiff, Zero, ISD::SETLT); Result = DAG.getSelect(dl, VT, SumNeg, SatMax, SatMin); return DAG.getSelect(dl, VT, Overflow, Result, SumDiff); } } SDValue TargetLowering::expandFixedPointMul(SDNode *Node, SelectionDAG &DAG) const { assert((Node->getOpcode() == ISD::SMULFIX || Node->getOpcode() == ISD::UMULFIX || Node->getOpcode() == ISD::SMULFIXSAT || Node->getOpcode() == ISD::UMULFIXSAT) && "Expected a fixed point multiplication opcode"); SDLoc dl(Node); SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); EVT VT = LHS.getValueType(); unsigned Scale = Node->getConstantOperandVal(2); bool Saturating = (Node->getOpcode() == ISD::SMULFIXSAT || Node->getOpcode() == ISD::UMULFIXSAT); bool Signed = (Node->getOpcode() == ISD::SMULFIX || Node->getOpcode() == ISD::SMULFIXSAT); EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); unsigned VTSize = VT.getScalarSizeInBits(); if (!Scale) { // [us]mul.fix(a, b, 0) -> mul(a, b) if (!Saturating) { if (isOperationLegalOrCustom(ISD::MUL, VT)) return DAG.getNode(ISD::MUL, dl, VT, LHS, RHS); } else if (Signed && isOperationLegalOrCustom(ISD::SMULO, VT)) { SDValue Result = DAG.getNode(ISD::SMULO, dl, DAG.getVTList(VT, BoolVT), LHS, RHS); SDValue Product = Result.getValue(0); SDValue Overflow = Result.getValue(1); SDValue Zero = DAG.getConstant(0, dl, VT); APInt MinVal = APInt::getSignedMinValue(VTSize); APInt MaxVal = APInt::getSignedMaxValue(VTSize); SDValue SatMin = DAG.getConstant(MinVal, dl, VT); SDValue SatMax = DAG.getConstant(MaxVal, dl, VT); SDValue ProdNeg = DAG.getSetCC(dl, BoolVT, Product, Zero, ISD::SETLT); Result = DAG.getSelect(dl, VT, ProdNeg, SatMax, SatMin); return DAG.getSelect(dl, VT, Overflow, Result, Product); } else if (!Signed && isOperationLegalOrCustom(ISD::UMULO, VT)) { SDValue Result = DAG.getNode(ISD::UMULO, dl, DAG.getVTList(VT, BoolVT), LHS, RHS); SDValue Product = Result.getValue(0); SDValue Overflow = Result.getValue(1); APInt MaxVal = APInt::getMaxValue(VTSize); SDValue SatMax = DAG.getConstant(MaxVal, dl, VT); return DAG.getSelect(dl, VT, Overflow, SatMax, Product); } } assert(((Signed && Scale < VTSize) || (!Signed && Scale <= VTSize)) && "Expected scale to be less than the number of bits if signed or at " "most the number of bits if unsigned."); assert(LHS.getValueType() == RHS.getValueType() && "Expected both operands to be the same type"); // Get the upper and lower bits of the result. SDValue Lo, Hi; unsigned LoHiOp = Signed ? ISD::SMUL_LOHI : ISD::UMUL_LOHI; unsigned HiOp = Signed ? ISD::MULHS : ISD::MULHU; if (isOperationLegalOrCustom(LoHiOp, VT)) { SDValue Result = DAG.getNode(LoHiOp, dl, DAG.getVTList(VT, VT), LHS, RHS); Lo = Result.getValue(0); Hi = Result.getValue(1); } else if (isOperationLegalOrCustom(HiOp, VT)) { Lo = DAG.getNode(ISD::MUL, dl, VT, LHS, RHS); Hi = DAG.getNode(HiOp, dl, VT, LHS, RHS); } else if (VT.isVector()) { return SDValue(); } else { report_fatal_error("Unable to expand fixed point multiplication."); } if (Scale == VTSize) // Result is just the top half since we'd be shifting by the width of the // operand. Overflow impossible so this works for both UMULFIX and // UMULFIXSAT. return Hi; // The result will need to be shifted right by the scale since both operands // are scaled. The result is given to us in 2 halves, so we only want part of // both in the result. EVT ShiftTy = getShiftAmountTy(VT, DAG.getDataLayout()); SDValue Result = DAG.getNode(ISD::FSHR, dl, VT, Hi, Lo, DAG.getConstant(Scale, dl, ShiftTy)); if (!Saturating) return Result; if (!Signed) { // Unsigned overflow happened if the upper (VTSize - Scale) bits (of the // widened multiplication) aren't all zeroes. // Saturate to max if ((Hi >> Scale) != 0), // which is the same as if (Hi > ((1 << Scale) - 1)) APInt MaxVal = APInt::getMaxValue(VTSize); SDValue LowMask = DAG.getConstant(APInt::getLowBitsSet(VTSize, Scale), dl, VT); Result = DAG.getSelectCC(dl, Hi, LowMask, DAG.getConstant(MaxVal, dl, VT), Result, ISD::SETUGT); return Result; } // Signed overflow happened if the upper (VTSize - Scale + 1) bits (of the // widened multiplication) aren't all ones or all zeroes. SDValue SatMin = DAG.getConstant(APInt::getSignedMinValue(VTSize), dl, VT); SDValue SatMax = DAG.getConstant(APInt::getSignedMaxValue(VTSize), dl, VT); if (Scale == 0) { SDValue Sign = DAG.getNode(ISD::SRA, dl, VT, Lo, DAG.getConstant(VTSize - 1, dl, ShiftTy)); SDValue Overflow = DAG.getSetCC(dl, BoolVT, Hi, Sign, ISD::SETNE); // Saturated to SatMin if wide product is negative, and SatMax if wide // product is positive ... SDValue Zero = DAG.getConstant(0, dl, VT); SDValue ResultIfOverflow = DAG.getSelectCC(dl, Hi, Zero, SatMin, SatMax, ISD::SETLT); // ... but only if we overflowed. return DAG.getSelect(dl, VT, Overflow, ResultIfOverflow, Result); } // We handled Scale==0 above so all the bits to examine is in Hi. // Saturate to max if ((Hi >> (Scale - 1)) > 0), // which is the same as if (Hi > (1 << (Scale - 1)) - 1) SDValue LowMask = DAG.getConstant(APInt::getLowBitsSet(VTSize, Scale - 1), dl, VT); Result = DAG.getSelectCC(dl, Hi, LowMask, SatMax, Result, ISD::SETGT); // Saturate to min if (Hi >> (Scale - 1)) < -1), // which is the same as if (HI < (-1 << (Scale - 1)) SDValue HighMask = DAG.getConstant(APInt::getHighBitsSet(VTSize, VTSize - Scale + 1), dl, VT); Result = DAG.getSelectCC(dl, Hi, HighMask, SatMin, Result, ISD::SETLT); return Result; } SDValue TargetLowering::expandFixedPointDiv(unsigned Opcode, const SDLoc &dl, SDValue LHS, SDValue RHS, unsigned Scale, SelectionDAG &DAG) const { assert((Opcode == ISD::SDIVFIX || Opcode == ISD::UDIVFIX) && "Expected a fixed point division opcode"); EVT VT = LHS.getValueType(); bool Signed = Opcode == ISD::SDIVFIX; EVT BoolVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); // If there is enough room in the type to upscale the LHS or downscale the // RHS before the division, we can perform it in this type without having to // resize. For signed operations, the LHS headroom is the number of // redundant sign bits, and for unsigned ones it is the number of zeroes. // The headroom for the RHS is the number of trailing zeroes. unsigned LHSLead = Signed ? DAG.ComputeNumSignBits(LHS) - 1 : DAG.computeKnownBits(LHS).countMinLeadingZeros(); unsigned RHSTrail = DAG.computeKnownBits(RHS).countMinTrailingZeros(); if (LHSLead + RHSTrail < Scale) return SDValue(); unsigned LHSShift = std::min(LHSLead, Scale); unsigned RHSShift = Scale - LHSShift; // At this point, we know that if we shift the LHS up by LHSShift and the // RHS down by RHSShift, we can emit a regular division with a final scaling // factor of Scale. EVT ShiftTy = getShiftAmountTy(VT, DAG.getDataLayout()); if (LHSShift) LHS = DAG.getNode(ISD::SHL, dl, VT, LHS, DAG.getConstant(LHSShift, dl, ShiftTy)); if (RHSShift) RHS = DAG.getNode(Signed ? ISD::SRA : ISD::SRL, dl, VT, RHS, DAG.getConstant(RHSShift, dl, ShiftTy)); SDValue Quot; if (Signed) { // For signed operations, if the resulting quotient is negative and the // remainder is nonzero, subtract 1 from the quotient to round towards // negative infinity. SDValue Rem; // FIXME: Ideally we would always produce an SDIVREM here, but if the // type isn't legal, SDIVREM cannot be expanded. There is no reason why // we couldn't just form a libcall, but the type legalizer doesn't do it. if (isTypeLegal(VT) && isOperationLegalOrCustom(ISD::SDIVREM, VT)) { Quot = DAG.getNode(ISD::SDIVREM, dl, DAG.getVTList(VT, VT), LHS, RHS); Rem = Quot.getValue(1); Quot = Quot.getValue(0); } else { Quot = DAG.getNode(ISD::SDIV, dl, VT, LHS, RHS); Rem = DAG.getNode(ISD::SREM, dl, VT, LHS, RHS); } SDValue Zero = DAG.getConstant(0, dl, VT); SDValue RemNonZero = DAG.getSetCC(dl, BoolVT, Rem, Zero, ISD::SETNE); SDValue LHSNeg = DAG.getSetCC(dl, BoolVT, LHS, Zero, ISD::SETLT); SDValue RHSNeg = DAG.getSetCC(dl, BoolVT, RHS, Zero, ISD::SETLT); SDValue QuotNeg = DAG.getNode(ISD::XOR, dl, BoolVT, LHSNeg, RHSNeg); SDValue Sub1 = DAG.getNode(ISD::SUB, dl, VT, Quot, DAG.getConstant(1, dl, VT)); Quot = DAG.getSelect(dl, VT, DAG.getNode(ISD::AND, dl, BoolVT, RemNonZero, QuotNeg), Sub1, Quot); } else Quot = DAG.getNode(ISD::UDIV, dl, VT, LHS, RHS); // TODO: Saturation. return Quot; } void TargetLowering::expandUADDSUBO( SDNode *Node, SDValue &Result, SDValue &Overflow, SelectionDAG &DAG) const { SDLoc dl(Node); SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); bool IsAdd = Node->getOpcode() == ISD::UADDO; // If ADD/SUBCARRY is legal, use that instead. unsigned OpcCarry = IsAdd ? ISD::ADDCARRY : ISD::SUBCARRY; if (isOperationLegalOrCustom(OpcCarry, Node->getValueType(0))) { SDValue CarryIn = DAG.getConstant(0, dl, Node->getValueType(1)); SDValue NodeCarry = DAG.getNode(OpcCarry, dl, Node->getVTList(), { LHS, RHS, CarryIn }); Result = SDValue(NodeCarry.getNode(), 0); Overflow = SDValue(NodeCarry.getNode(), 1); return; } Result = DAG.getNode(IsAdd ? ISD::ADD : ISD::SUB, dl, LHS.getValueType(), LHS, RHS); EVT ResultType = Node->getValueType(1); EVT SetCCType = getSetCCResultType( DAG.getDataLayout(), *DAG.getContext(), Node->getValueType(0)); ISD::CondCode CC = IsAdd ? ISD::SETULT : ISD::SETUGT; SDValue SetCC = DAG.getSetCC(dl, SetCCType, Result, LHS, CC); Overflow = DAG.getBoolExtOrTrunc(SetCC, dl, ResultType, ResultType); } void TargetLowering::expandSADDSUBO( SDNode *Node, SDValue &Result, SDValue &Overflow, SelectionDAG &DAG) const { SDLoc dl(Node); SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); bool IsAdd = Node->getOpcode() == ISD::SADDO; Result = DAG.getNode(IsAdd ? ISD::ADD : ISD::SUB, dl, LHS.getValueType(), LHS, RHS); EVT ResultType = Node->getValueType(1); EVT OType = getSetCCResultType( DAG.getDataLayout(), *DAG.getContext(), Node->getValueType(0)); // If SADDSAT/SSUBSAT is legal, compare results to detect overflow. unsigned OpcSat = IsAdd ? ISD::SADDSAT : ISD::SSUBSAT; if (isOperationLegalOrCustom(OpcSat, LHS.getValueType())) { SDValue Sat = DAG.getNode(OpcSat, dl, LHS.getValueType(), LHS, RHS); SDValue SetCC = DAG.getSetCC(dl, OType, Result, Sat, ISD::SETNE); Overflow = DAG.getBoolExtOrTrunc(SetCC, dl, ResultType, ResultType); return; } SDValue Zero = DAG.getConstant(0, dl, LHS.getValueType()); // For an addition, the result should be less than one of the operands (LHS) // if and only if the other operand (RHS) is negative, otherwise there will // be overflow. // For a subtraction, the result should be less than one of the operands // (LHS) if and only if the other operand (RHS) is (non-zero) positive, // otherwise there will be overflow. SDValue ResultLowerThanLHS = DAG.getSetCC(dl, OType, Result, LHS, ISD::SETLT); SDValue ConditionRHS = DAG.getSetCC(dl, OType, RHS, Zero, IsAdd ? ISD::SETLT : ISD::SETGT); Overflow = DAG.getBoolExtOrTrunc( DAG.getNode(ISD::XOR, dl, OType, ConditionRHS, ResultLowerThanLHS), dl, ResultType, ResultType); } bool TargetLowering::expandMULO(SDNode *Node, SDValue &Result, SDValue &Overflow, SelectionDAG &DAG) const { SDLoc dl(Node); EVT VT = Node->getValueType(0); EVT SetCCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT); SDValue LHS = Node->getOperand(0); SDValue RHS = Node->getOperand(1); bool isSigned = Node->getOpcode() == ISD::SMULO; // For power-of-two multiplications we can use a simpler shift expansion. if (ConstantSDNode *RHSC = isConstOrConstSplat(RHS)) { const APInt &C = RHSC->getAPIntValue(); // mulo(X, 1 << S) -> { X << S, (X << S) >> S != X } if (C.isPowerOf2()) { // smulo(x, signed_min) is same as umulo(x, signed_min). bool UseArithShift = isSigned && !C.isMinSignedValue(); EVT ShiftAmtTy = getShiftAmountTy(VT, DAG.getDataLayout()); SDValue ShiftAmt = DAG.getConstant(C.logBase2(), dl, ShiftAmtTy); Result = DAG.getNode(ISD::SHL, dl, VT, LHS, ShiftAmt); Overflow = DAG.getSetCC(dl, SetCCVT, DAG.getNode(UseArithShift ? ISD::SRA : ISD::SRL, dl, VT, Result, ShiftAmt), LHS, ISD::SETNE); return true; } } EVT WideVT = EVT::getIntegerVT(*DAG.getContext(), VT.getScalarSizeInBits() * 2); if (VT.isVector()) WideVT = EVT::getVectorVT(*DAG.getContext(), WideVT, VT.getVectorNumElements()); SDValue BottomHalf; SDValue TopHalf; static const unsigned Ops[2][3] = { { ISD::MULHU, ISD::UMUL_LOHI, ISD::ZERO_EXTEND }, { ISD::MULHS, ISD::SMUL_LOHI, ISD::SIGN_EXTEND }}; if (isOperationLegalOrCustom(Ops[isSigned][0], VT)) { BottomHalf = DAG.getNode(ISD::MUL, dl, VT, LHS, RHS); TopHalf = DAG.getNode(Ops[isSigned][0], dl, VT, LHS, RHS); } else if (isOperationLegalOrCustom(Ops[isSigned][1], VT)) { BottomHalf = DAG.getNode(Ops[isSigned][1], dl, DAG.getVTList(VT, VT), LHS, RHS); TopHalf = BottomHalf.getValue(1); } else if (isTypeLegal(WideVT)) { LHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, LHS); RHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, RHS); SDValue Mul = DAG.getNode(ISD::MUL, dl, WideVT, LHS, RHS); BottomHalf = DAG.getNode(ISD::TRUNCATE, dl, VT, Mul); SDValue ShiftAmt = DAG.getConstant(VT.getScalarSizeInBits(), dl, getShiftAmountTy(WideVT, DAG.getDataLayout())); TopHalf = DAG.getNode(ISD::TRUNCATE, dl, VT, DAG.getNode(ISD::SRL, dl, WideVT, Mul, ShiftAmt)); } else { if (VT.isVector()) return false; // We can fall back to a libcall with an illegal type for the MUL if we // have a libcall big enough. // Also, we can fall back to a division in some cases, but that's a big // performance hit in the general case. RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; if (WideVT == MVT::i16) LC = RTLIB::MUL_I16; else if (WideVT == MVT::i32) LC = RTLIB::MUL_I32; else if (WideVT == MVT::i64) LC = RTLIB::MUL_I64; else if (WideVT == MVT::i128) LC = RTLIB::MUL_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Cannot expand this operation!"); SDValue HiLHS; SDValue HiRHS; if (isSigned) { // The high part is obtained by SRA'ing all but one of the bits of low // part. unsigned LoSize = VT.getSizeInBits(); HiLHS = DAG.getNode(ISD::SRA, dl, VT, LHS, DAG.getConstant(LoSize - 1, dl, getPointerTy(DAG.getDataLayout()))); HiRHS = DAG.getNode(ISD::SRA, dl, VT, RHS, DAG.getConstant(LoSize - 1, dl, getPointerTy(DAG.getDataLayout()))); } else { HiLHS = DAG.getConstant(0, dl, VT); HiRHS = DAG.getConstant(0, dl, VT); } // Here we're passing the 2 arguments explicitly as 4 arguments that are // pre-lowered to the correct types. This all depends upon WideVT not // being a legal type for the architecture and thus has to be split to // two arguments. SDValue Ret; TargetLowering::MakeLibCallOptions CallOptions; CallOptions.setSExt(isSigned); CallOptions.setIsPostTypeLegalization(true); if (shouldSplitFunctionArgumentsAsLittleEndian(DAG.getDataLayout())) { // Halves of WideVT are packed into registers in different order // depending on platform endianness. This is usually handled by // the C calling convention, but we can't defer to it in // the legalizer. SDValue Args[] = { LHS, HiLHS, RHS, HiRHS }; Ret = makeLibCall(DAG, LC, WideVT, Args, CallOptions, dl).first; } else { SDValue Args[] = { HiLHS, LHS, HiRHS, RHS }; Ret = makeLibCall(DAG, LC, WideVT, Args, CallOptions, dl).first; } assert(Ret.getOpcode() == ISD::MERGE_VALUES && "Ret value is a collection of constituent nodes holding result."); if (DAG.getDataLayout().isLittleEndian()) { // Same as above. BottomHalf = Ret.getOperand(0); TopHalf = Ret.getOperand(1); } else { BottomHalf = Ret.getOperand(1); TopHalf = Ret.getOperand(0); } } Result = BottomHalf; if (isSigned) { SDValue ShiftAmt = DAG.getConstant( VT.getScalarSizeInBits() - 1, dl, getShiftAmountTy(BottomHalf.getValueType(), DAG.getDataLayout())); SDValue Sign = DAG.getNode(ISD::SRA, dl, VT, BottomHalf, ShiftAmt); Overflow = DAG.getSetCC(dl, SetCCVT, TopHalf, Sign, ISD::SETNE); } else { Overflow = DAG.getSetCC(dl, SetCCVT, TopHalf, DAG.getConstant(0, dl, VT), ISD::SETNE); } // Truncate the result if SetCC returns a larger type than needed. EVT RType = Node->getValueType(1); if (RType.getSizeInBits() < Overflow.getValueSizeInBits()) Overflow = DAG.getNode(ISD::TRUNCATE, dl, RType, Overflow); assert(RType.getSizeInBits() == Overflow.getValueSizeInBits() && "Unexpected result type for S/UMULO legalization"); return true; } SDValue TargetLowering::expandVecReduce(SDNode *Node, SelectionDAG &DAG) const { SDLoc dl(Node); bool NoNaN = Node->getFlags().hasNoNaNs(); unsigned BaseOpcode = 0; switch (Node->getOpcode()) { default: llvm_unreachable("Expected VECREDUCE opcode"); case ISD::VECREDUCE_FADD: BaseOpcode = ISD::FADD; break; case ISD::VECREDUCE_FMUL: BaseOpcode = ISD::FMUL; break; case ISD::VECREDUCE_ADD: BaseOpcode = ISD::ADD; break; case ISD::VECREDUCE_MUL: BaseOpcode = ISD::MUL; break; case ISD::VECREDUCE_AND: BaseOpcode = ISD::AND; break; case ISD::VECREDUCE_OR: BaseOpcode = ISD::OR; break; case ISD::VECREDUCE_XOR: BaseOpcode = ISD::XOR; break; case ISD::VECREDUCE_SMAX: BaseOpcode = ISD::SMAX; break; case ISD::VECREDUCE_SMIN: BaseOpcode = ISD::SMIN; break; case ISD::VECREDUCE_UMAX: BaseOpcode = ISD::UMAX; break; case ISD::VECREDUCE_UMIN: BaseOpcode = ISD::UMIN; break; case ISD::VECREDUCE_FMAX: BaseOpcode = NoNaN ? ISD::FMAXNUM : ISD::FMAXIMUM; break; case ISD::VECREDUCE_FMIN: BaseOpcode = NoNaN ? ISD::FMINNUM : ISD::FMINIMUM; break; } SDValue Op = Node->getOperand(0); EVT VT = Op.getValueType(); // Try to use a shuffle reduction for power of two vectors. if (VT.isPow2VectorType()) { while (VT.getVectorNumElements() > 1) { EVT HalfVT = VT.getHalfNumVectorElementsVT(*DAG.getContext()); if (!isOperationLegalOrCustom(BaseOpcode, HalfVT)) break; SDValue Lo, Hi; std::tie(Lo, Hi) = DAG.SplitVector(Op, dl); Op = DAG.getNode(BaseOpcode, dl, HalfVT, Lo, Hi); VT = HalfVT; } } EVT EltVT = VT.getVectorElementType(); unsigned NumElts = VT.getVectorNumElements(); SmallVector Ops; DAG.ExtractVectorElements(Op, Ops, 0, NumElts); SDValue Res = Ops[0]; for (unsigned i = 1; i < NumElts; i++) Res = DAG.getNode(BaseOpcode, dl, EltVT, Res, Ops[i], Node->getFlags()); // Result type may be wider than element type. if (EltVT != Node->getValueType(0)) Res = DAG.getNode(ISD::ANY_EXTEND, dl, Node->getValueType(0), Res); return Res; } Index: head/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- head/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (revision 362718) +++ head/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (revision 362719) @@ -1,2682 +1,2697 @@ //===- AArch64FrameLowering.cpp - AArch64 Frame Lowering -------*- C++ -*-====// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains the AArch64 implementation of TargetFrameLowering class. // // On AArch64, stack frames are structured as follows: // // The stack grows downward. // // All of the individual frame areas on the frame below are optional, i.e. it's // possible to create a function so that the particular area isn't present // in the frame. // // At function entry, the "frame" looks as follows: // // | | Higher address // |-----------------------------------| // | | // | arguments passed on the stack | // | | // |-----------------------------------| <- sp // | | Lower address // // // After the prologue has run, the frame has the following general structure. // Note that this doesn't depict the case where a red-zone is used. Also, // technically the last frame area (VLAs) doesn't get created until in the // main function body, after the prologue is run. However, it's depicted here // for completeness. // // | | Higher address // |-----------------------------------| // | | // | arguments passed on the stack | // | | // |-----------------------------------| // | | // | (Win64 only) varargs from reg | // | | // |-----------------------------------| // | | // | callee-saved gpr registers | <--. // | | | On Darwin platforms these // |- - - - - - - - - - - - - - - - - -| | callee saves are swapped, // | | | (frame record first) // | prev_fp, prev_lr | <--' // | (a.k.a. "frame record") | // |-----------------------------------| <- fp(=x29) // | | // | callee-saved fp/simd/SVE regs | // | | // |-----------------------------------| // | | // | SVE stack objects | // | | // |-----------------------------------| // |.empty.space.to.make.part.below....| // |.aligned.in.case.it.needs.more.than| (size of this area is unknown at // |.the.standard.16-byte.alignment....| compile time; if present) // |-----------------------------------| // | | // | local variables of fixed size | // | including spill slots | // |-----------------------------------| <- bp(not defined by ABI, // |.variable-sized.local.variables....| LLVM chooses X19) // |.(VLAs)............................| (size of this area is unknown at // |...................................| compile time) // |-----------------------------------| <- sp // | | Lower address // // // To access the data in a frame, at-compile time, a constant offset must be // computable from one of the pointers (fp, bp, sp) to access it. The size // of the areas with a dotted background cannot be computed at compile-time // if they are present, making it required to have all three of fp, bp and // sp to be set up to be able to access all contents in the frame areas, // assuming all of the frame areas are non-empty. // // For most functions, some of the frame areas are empty. For those functions, // it may not be necessary to set up fp or bp: // * A base pointer is definitely needed when there are both VLAs and local // variables with more-than-default alignment requirements. // * A frame pointer is definitely needed when there are local variables with // more-than-default alignment requirements. // // For Darwin platforms the frame-record (fp, lr) is stored at the top of the // callee-saved area, since the unwind encoding does not allow for encoding // this dynamically and existing tools depend on this layout. For other // platforms, the frame-record is stored at the bottom of the (gpr) callee-saved // area to allow SVE stack objects (allocated directly below the callee-saves, // if available) to be accessed directly from the framepointer. // The SVE spill/fill instructions have VL-scaled addressing modes such // as: // ldr z8, [fp, #-7 mul vl] // For SVE the size of the vector length (VL) is not known at compile-time, so // '#-7 mul vl' is an offset that can only be evaluated at runtime. With this // layout, we don't need to add an unscaled offset to the framepointer before // accessing the SVE object in the frame. // // In some cases when a base pointer is not strictly needed, it is generated // anyway when offsets from the frame pointer to access local variables become // so large that the offset can't be encoded in the immediate fields of loads // or stores. // // FIXME: also explain the redzone concept. // FIXME: also explain the concept of reserved call frames. // //===----------------------------------------------------------------------===// #include "AArch64FrameLowering.h" #include "AArch64InstrInfo.h" #include "AArch64MachineFunctionInfo.h" #include "AArch64RegisterInfo.h" #include "AArch64StackOffset.h" #include "AArch64Subtarget.h" #include "AArch64TargetMachine.h" #include "MCTargetDesc/AArch64AddressingModes.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/LivePhysRegs.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDwarf.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include #include #include #include using namespace llvm; #define DEBUG_TYPE "frame-info" static cl::opt EnableRedZone("aarch64-redzone", cl::desc("enable use of redzone on AArch64"), cl::init(false), cl::Hidden); static cl::opt ReverseCSRRestoreSeq("reverse-csr-restore-seq", cl::desc("reverse the CSR restore sequence"), cl::init(false), cl::Hidden); STATISTIC(NumRedZoneFunctions, "Number of functions using red zone"); /// This is the biggest offset to the stack pointer we can encode in aarch64 /// instructions (without using a separate calculation and a temp register). /// Note that the exception here are vector stores/loads which cannot encode any /// displacements (see estimateRSStackSizeLimit(), isAArch64FrameOffsetLegal()). static const unsigned DefaultSafeSPDisplacement = 255; /// Look at each instruction that references stack frames and return the stack /// size limit beyond which some of these instructions will require a scratch /// register during their expansion later. static unsigned estimateRSStackSizeLimit(MachineFunction &MF) { // FIXME: For now, just conservatively guestimate based on unscaled indexing // range. We'll end up allocating an unnecessary spill slot a lot, but // realistically that's not a big deal at this stage of the game. for (MachineBasicBlock &MBB : MF) { for (MachineInstr &MI : MBB) { if (MI.isDebugInstr() || MI.isPseudo() || MI.getOpcode() == AArch64::ADDXri || MI.getOpcode() == AArch64::ADDSXri) continue; for (const MachineOperand &MO : MI.operands()) { if (!MO.isFI()) continue; StackOffset Offset; if (isAArch64FrameOffsetLegal(MI, Offset, nullptr, nullptr, nullptr) == AArch64FrameOffsetCannotUpdate) return 0; } } } return DefaultSafeSPDisplacement; } TargetStackID::Value AArch64FrameLowering::getStackIDForScalableVectors() const { return TargetStackID::SVEVector; } +/// Returns the size of the fixed object area (allocated next to sp on entry) +/// On Win64 this may include a var args area and an UnwindHelp object for EH. +static unsigned getFixedObjectSize(const MachineFunction &MF, + const AArch64FunctionInfo *AFI, bool IsWin64, + bool IsFunclet) { + if (!IsWin64 || IsFunclet) { + // Only Win64 uses fixed objects, and then only for the function (not + // funclets) + return 0; + } else { + // Var args are stored here in the primary function. + const unsigned VarArgsArea = AFI->getVarArgsGPRSize(); + // To support EH funclets we allocate an UnwindHelp object + const unsigned UnwindHelpObject = (MF.hasEHFunclets() ? 8 : 0); + return alignTo(VarArgsArea + UnwindHelpObject, 16); + } +} + /// Returns the size of the entire SVE stackframe (calleesaves + spills). static StackOffset getSVEStackSize(const MachineFunction &MF) { const AArch64FunctionInfo *AFI = MF.getInfo(); return {(int64_t)AFI->getStackSizeSVE(), MVT::nxv1i8}; } bool AArch64FrameLowering::canUseRedZone(const MachineFunction &MF) const { if (!EnableRedZone) return false; // Don't use the red zone if the function explicitly asks us not to. // This is typically used for kernel code. if (MF.getFunction().hasFnAttribute(Attribute::NoRedZone)) return false; const MachineFrameInfo &MFI = MF.getFrameInfo(); const AArch64FunctionInfo *AFI = MF.getInfo(); uint64_t NumBytes = AFI->getLocalStackSize(); return !(MFI.hasCalls() || hasFP(MF) || NumBytes > 128 || getSVEStackSize(MF)); } /// hasFP - Return true if the specified function should have a dedicated frame /// pointer register. bool AArch64FrameLowering::hasFP(const MachineFunction &MF) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); // Win64 EH requires a frame pointer if funclets are present, as the locals // are accessed off the frame pointer in both the parent function and the // funclets. if (MF.hasEHFunclets()) return true; // Retain behavior of always omitting the FP for leaf functions when possible. if (MF.getTarget().Options.DisableFramePointerElim(MF)) return true; if (MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken() || MFI.hasStackMap() || MFI.hasPatchPoint() || RegInfo->needsStackRealignment(MF)) return true; // With large callframes around we may need to use FP to access the scavenging // emergency spillslot. // // Unfortunately some calls to hasFP() like machine verifier -> // getReservedReg() -> hasFP in the middle of global isel are too early // to know the max call frame size. Hopefully conservatively returning "true" // in those cases is fine. // DefaultSafeSPDisplacement is fine as we only emergency spill GP regs. if (!MFI.isMaxCallFrameSizeComputed() || MFI.getMaxCallFrameSize() > DefaultSafeSPDisplacement) return true; return false; } /// hasReservedCallFrame - Under normal circumstances, when a frame pointer is /// not required, we reserve argument space for call sites in the function /// immediately on entry to the current function. This eliminates the need for /// add/sub sp brackets around call sites. Returns true if the call frame is /// included as part of the stack frame. bool AArch64FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { return !MF.getFrameInfo().hasVarSizedObjects(); } MachineBasicBlock::iterator AArch64FrameLowering::eliminateCallFramePseudoInstr( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { const AArch64InstrInfo *TII = static_cast(MF.getSubtarget().getInstrInfo()); DebugLoc DL = I->getDebugLoc(); unsigned Opc = I->getOpcode(); bool IsDestroy = Opc == TII->getCallFrameDestroyOpcode(); uint64_t CalleePopAmount = IsDestroy ? I->getOperand(1).getImm() : 0; if (!hasReservedCallFrame(MF)) { unsigned Align = getStackAlignment(); int64_t Amount = I->getOperand(0).getImm(); Amount = alignTo(Amount, Align); if (!IsDestroy) Amount = -Amount; // N.b. if CalleePopAmount is valid but zero (i.e. callee would pop, but it // doesn't have to pop anything), then the first operand will be zero too so // this adjustment is a no-op. if (CalleePopAmount == 0) { // FIXME: in-function stack adjustment for calls is limited to 24-bits // because there's no guaranteed temporary register available. // // ADD/SUB (immediate) has only LSL #0 and LSL #12 available. // 1) For offset <= 12-bit, we use LSL #0 // 2) For 12-bit <= offset <= 24-bit, we use two instructions. One uses // LSL #0, and the other uses LSL #12. // // Most call frames will be allocated at the start of a function so // this is OK, but it is a limitation that needs dealing with. assert(Amount > -0xffffff && Amount < 0xffffff && "call frame too large"); emitFrameOffset(MBB, I, DL, AArch64::SP, AArch64::SP, {Amount, MVT::i8}, TII); } } else if (CalleePopAmount != 0) { // If the calling convention demands that the callee pops arguments from the // stack, we want to add it back if we have a reserved call frame. assert(CalleePopAmount < 0xffffff && "call frame too large"); emitFrameOffset(MBB, I, DL, AArch64::SP, AArch64::SP, {-(int64_t)CalleePopAmount, MVT::i8}, TII); } return MBB.erase(I); } static bool ShouldSignReturnAddress(MachineFunction &MF) { // The function should be signed in the following situations: // - sign-return-address=all // - sign-return-address=non-leaf and the functions spills the LR const Function &F = MF.getFunction(); if (!F.hasFnAttribute("sign-return-address")) return false; StringRef Scope = F.getFnAttribute("sign-return-address").getValueAsString(); if (Scope.equals("none")) return false; if (Scope.equals("all")) return true; assert(Scope.equals("non-leaf") && "Expected all, none or non-leaf"); for (const auto &Info : MF.getFrameInfo().getCalleeSavedInfo()) if (Info.getReg() == AArch64::LR) return true; return false; } void AArch64FrameLowering::emitCalleeSavedFrameMoves( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) const { MachineFunction &MF = *MBB.getParent(); MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetSubtargetInfo &STI = MF.getSubtarget(); const MCRegisterInfo *MRI = STI.getRegisterInfo(); const TargetInstrInfo *TII = STI.getInstrInfo(); DebugLoc DL = MBB.findDebugLoc(MBBI); // Add callee saved registers to move list. const std::vector &CSI = MFI.getCalleeSavedInfo(); if (CSI.empty()) return; for (const auto &Info : CSI) { unsigned Reg = Info.getReg(); int64_t Offset = MFI.getObjectOffset(Info.getFrameIdx()) - getOffsetOfLocalArea(); unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); unsigned CFIIndex = MF.addFrameInst( MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); } } // Find a scratch register that we can use at the start of the prologue to // re-align the stack pointer. We avoid using callee-save registers since they // may appear to be free when this is called from canUseAsPrologue (during // shrink wrapping), but then no longer be free when this is called from // emitPrologue. // // FIXME: This is a bit conservative, since in the above case we could use one // of the callee-save registers as a scratch temp to re-align the stack pointer, // but we would then have to make sure that we were in fact saving at least one // callee-save register in the prologue, which is additional complexity that // doesn't seem worth the benefit. static unsigned findScratchNonCalleeSaveRegister(MachineBasicBlock *MBB) { MachineFunction *MF = MBB->getParent(); // If MBB is an entry block, use X9 as the scratch register if (&MF->front() == MBB) return AArch64::X9; const AArch64Subtarget &Subtarget = MF->getSubtarget(); const AArch64RegisterInfo &TRI = *Subtarget.getRegisterInfo(); LivePhysRegs LiveRegs(TRI); LiveRegs.addLiveIns(*MBB); // Mark callee saved registers as used so we will not choose them. const MCPhysReg *CSRegs = MF->getRegInfo().getCalleeSavedRegs(); for (unsigned i = 0; CSRegs[i]; ++i) LiveRegs.addReg(CSRegs[i]); // Prefer X9 since it was historically used for the prologue scratch reg. const MachineRegisterInfo &MRI = MF->getRegInfo(); if (LiveRegs.available(MRI, AArch64::X9)) return AArch64::X9; for (unsigned Reg : AArch64::GPR64RegClass) { if (LiveRegs.available(MRI, Reg)) return Reg; } return AArch64::NoRegister; } bool AArch64FrameLowering::canUseAsPrologue( const MachineBasicBlock &MBB) const { const MachineFunction *MF = MBB.getParent(); MachineBasicBlock *TmpMBB = const_cast(&MBB); const AArch64Subtarget &Subtarget = MF->getSubtarget(); const AArch64RegisterInfo *RegInfo = Subtarget.getRegisterInfo(); // Don't need a scratch register if we're not going to re-align the stack. if (!RegInfo->needsStackRealignment(*MF)) return true; // Otherwise, we can use any block as long as it has a scratch register // available. return findScratchNonCalleeSaveRegister(TmpMBB) != AArch64::NoRegister; } static bool windowsRequiresStackProbe(MachineFunction &MF, uint64_t StackSizeInBytes) { const AArch64Subtarget &Subtarget = MF.getSubtarget(); if (!Subtarget.isTargetWindows()) return false; const Function &F = MF.getFunction(); // TODO: When implementing stack protectors, take that into account // for the probe threshold. unsigned StackProbeSize = 4096; if (F.hasFnAttribute("stack-probe-size")) F.getFnAttribute("stack-probe-size") .getValueAsString() .getAsInteger(0, StackProbeSize); return (StackSizeInBytes >= StackProbeSize) && !F.hasFnAttribute("no-stack-arg-probe"); } bool AArch64FrameLowering::shouldCombineCSRLocalStackBump( MachineFunction &MF, uint64_t StackBumpBytes) const { AArch64FunctionInfo *AFI = MF.getInfo(); const MachineFrameInfo &MFI = MF.getFrameInfo(); const AArch64Subtarget &Subtarget = MF.getSubtarget(); const AArch64RegisterInfo *RegInfo = Subtarget.getRegisterInfo(); if (AFI->getLocalStackSize() == 0) return false; // 512 is the maximum immediate for stp/ldp that will be used for // callee-save save/restores if (StackBumpBytes >= 512 || windowsRequiresStackProbe(MF, StackBumpBytes)) return false; if (MFI.hasVarSizedObjects()) return false; if (RegInfo->needsStackRealignment(MF)) return false; // This isn't strictly necessary, but it simplifies things a bit since the // current RedZone handling code assumes the SP is adjusted by the // callee-save save/restore code. if (canUseRedZone(MF)) return false; // When there is an SVE area on the stack, always allocate the // callee-saves and spills/locals separately. if (getSVEStackSize(MF)) return false; return true; } // Given a load or a store instruction, generate an appropriate unwinding SEH // code on Windows. static MachineBasicBlock::iterator InsertSEH(MachineBasicBlock::iterator MBBI, const TargetInstrInfo &TII, MachineInstr::MIFlag Flag) { unsigned Opc = MBBI->getOpcode(); MachineBasicBlock *MBB = MBBI->getParent(); MachineFunction &MF = *MBB->getParent(); DebugLoc DL = MBBI->getDebugLoc(); unsigned ImmIdx = MBBI->getNumOperands() - 1; int Imm = MBBI->getOperand(ImmIdx).getImm(); MachineInstrBuilder MIB; const AArch64Subtarget &Subtarget = MF.getSubtarget(); const AArch64RegisterInfo *RegInfo = Subtarget.getRegisterInfo(); switch (Opc) { default: llvm_unreachable("No SEH Opcode for this instruction"); case AArch64::LDPDpost: Imm = -Imm; LLVM_FALLTHROUGH; case AArch64::STPDpre: { unsigned Reg0 = RegInfo->getSEHRegNum(MBBI->getOperand(1).getReg()); unsigned Reg1 = RegInfo->getSEHRegNum(MBBI->getOperand(2).getReg()); MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveFRegP_X)) .addImm(Reg0) .addImm(Reg1) .addImm(Imm * 8) .setMIFlag(Flag); break; } case AArch64::LDPXpost: Imm = -Imm; LLVM_FALLTHROUGH; case AArch64::STPXpre: { Register Reg0 = MBBI->getOperand(1).getReg(); Register Reg1 = MBBI->getOperand(2).getReg(); if (Reg0 == AArch64::FP && Reg1 == AArch64::LR) MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveFPLR_X)) .addImm(Imm * 8) .setMIFlag(Flag); else MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveRegP_X)) .addImm(RegInfo->getSEHRegNum(Reg0)) .addImm(RegInfo->getSEHRegNum(Reg1)) .addImm(Imm * 8) .setMIFlag(Flag); break; } case AArch64::LDRDpost: Imm = -Imm; LLVM_FALLTHROUGH; case AArch64::STRDpre: { unsigned Reg = RegInfo->getSEHRegNum(MBBI->getOperand(1).getReg()); MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveFReg_X)) .addImm(Reg) .addImm(Imm) .setMIFlag(Flag); break; } case AArch64::LDRXpost: Imm = -Imm; LLVM_FALLTHROUGH; case AArch64::STRXpre: { unsigned Reg = RegInfo->getSEHRegNum(MBBI->getOperand(1).getReg()); MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveReg_X)) .addImm(Reg) .addImm(Imm) .setMIFlag(Flag); break; } case AArch64::STPDi: case AArch64::LDPDi: { unsigned Reg0 = RegInfo->getSEHRegNum(MBBI->getOperand(0).getReg()); unsigned Reg1 = RegInfo->getSEHRegNum(MBBI->getOperand(1).getReg()); MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveFRegP)) .addImm(Reg0) .addImm(Reg1) .addImm(Imm * 8) .setMIFlag(Flag); break; } case AArch64::STPXi: case AArch64::LDPXi: { Register Reg0 = MBBI->getOperand(0).getReg(); Register Reg1 = MBBI->getOperand(1).getReg(); if (Reg0 == AArch64::FP && Reg1 == AArch64::LR) MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveFPLR)) .addImm(Imm * 8) .setMIFlag(Flag); else MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveRegP)) .addImm(RegInfo->getSEHRegNum(Reg0)) .addImm(RegInfo->getSEHRegNum(Reg1)) .addImm(Imm * 8) .setMIFlag(Flag); break; } case AArch64::STRXui: case AArch64::LDRXui: { int Reg = RegInfo->getSEHRegNum(MBBI->getOperand(0).getReg()); MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveReg)) .addImm(Reg) .addImm(Imm * 8) .setMIFlag(Flag); break; } case AArch64::STRDui: case AArch64::LDRDui: { unsigned Reg = RegInfo->getSEHRegNum(MBBI->getOperand(0).getReg()); MIB = BuildMI(MF, DL, TII.get(AArch64::SEH_SaveFReg)) .addImm(Reg) .addImm(Imm * 8) .setMIFlag(Flag); break; } } auto I = MBB->insertAfter(MBBI, MIB); return I; } // Fix up the SEH opcode associated with the save/restore instruction. static void fixupSEHOpcode(MachineBasicBlock::iterator MBBI, unsigned LocalStackSize) { MachineOperand *ImmOpnd = nullptr; unsigned ImmIdx = MBBI->getNumOperands() - 1; switch (MBBI->getOpcode()) { default: llvm_unreachable("Fix the offset in the SEH instruction"); case AArch64::SEH_SaveFPLR: case AArch64::SEH_SaveRegP: case AArch64::SEH_SaveReg: case AArch64::SEH_SaveFRegP: case AArch64::SEH_SaveFReg: ImmOpnd = &MBBI->getOperand(ImmIdx); break; } if (ImmOpnd) ImmOpnd->setImm(ImmOpnd->getImm() + LocalStackSize); } // Convert callee-save register save/restore instruction to do stack pointer // decrement/increment to allocate/deallocate the callee-save stack area by // converting store/load to use pre/post increment version. static MachineBasicBlock::iterator convertCalleeSaveRestoreToSPPrePostIncDec( MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, const TargetInstrInfo *TII, int CSStackSizeInc, bool NeedsWinCFI, bool *HasWinCFI, bool InProlog = true) { // Ignore instructions that do not operate on SP, i.e. shadow call stack // instructions and associated CFI instruction. while (MBBI->getOpcode() == AArch64::STRXpost || MBBI->getOpcode() == AArch64::LDRXpre || MBBI->getOpcode() == AArch64::CFI_INSTRUCTION) { if (MBBI->getOpcode() != AArch64::CFI_INSTRUCTION) assert(MBBI->getOperand(0).getReg() != AArch64::SP); ++MBBI; } unsigned NewOpc; int Scale = 1; switch (MBBI->getOpcode()) { default: llvm_unreachable("Unexpected callee-save save/restore opcode!"); case AArch64::STPXi: NewOpc = AArch64::STPXpre; Scale = 8; break; case AArch64::STPDi: NewOpc = AArch64::STPDpre; Scale = 8; break; case AArch64::STPQi: NewOpc = AArch64::STPQpre; Scale = 16; break; case AArch64::STRXui: NewOpc = AArch64::STRXpre; break; case AArch64::STRDui: NewOpc = AArch64::STRDpre; break; case AArch64::STRQui: NewOpc = AArch64::STRQpre; break; case AArch64::LDPXi: NewOpc = AArch64::LDPXpost; Scale = 8; break; case AArch64::LDPDi: NewOpc = AArch64::LDPDpost; Scale = 8; break; case AArch64::LDPQi: NewOpc = AArch64::LDPQpost; Scale = 16; break; case AArch64::LDRXui: NewOpc = AArch64::LDRXpost; break; case AArch64::LDRDui: NewOpc = AArch64::LDRDpost; break; case AArch64::LDRQui: NewOpc = AArch64::LDRQpost; break; } // Get rid of the SEH code associated with the old instruction. if (NeedsWinCFI) { auto SEH = std::next(MBBI); if (AArch64InstrInfo::isSEHInstruction(*SEH)) SEH->eraseFromParent(); } MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(NewOpc)); MIB.addReg(AArch64::SP, RegState::Define); // Copy all operands other than the immediate offset. unsigned OpndIdx = 0; for (unsigned OpndEnd = MBBI->getNumOperands() - 1; OpndIdx < OpndEnd; ++OpndIdx) MIB.add(MBBI->getOperand(OpndIdx)); assert(MBBI->getOperand(OpndIdx).getImm() == 0 && "Unexpected immediate offset in first/last callee-save save/restore " "instruction!"); assert(MBBI->getOperand(OpndIdx - 1).getReg() == AArch64::SP && "Unexpected base register in callee-save save/restore instruction!"); assert(CSStackSizeInc % Scale == 0); MIB.addImm(CSStackSizeInc / Scale); MIB.setMIFlags(MBBI->getFlags()); MIB.setMemRefs(MBBI->memoperands()); // Generate a new SEH code that corresponds to the new instruction. if (NeedsWinCFI) { *HasWinCFI = true; InsertSEH(*MIB, *TII, InProlog ? MachineInstr::FrameSetup : MachineInstr::FrameDestroy); } return std::prev(MBB.erase(MBBI)); } // Fixup callee-save register save/restore instructions to take into account // combined SP bump by adding the local stack size to the stack offsets. static void fixupCalleeSaveRestoreStackOffset(MachineInstr &MI, uint64_t LocalStackSize, bool NeedsWinCFI, bool *HasWinCFI) { if (AArch64InstrInfo::isSEHInstruction(MI)) return; unsigned Opc = MI.getOpcode(); // Ignore instructions that do not operate on SP, i.e. shadow call stack // instructions and associated CFI instruction. if (Opc == AArch64::STRXpost || Opc == AArch64::LDRXpre || Opc == AArch64::CFI_INSTRUCTION) { if (Opc != AArch64::CFI_INSTRUCTION) assert(MI.getOperand(0).getReg() != AArch64::SP); return; } unsigned Scale; switch (Opc) { case AArch64::STPXi: case AArch64::STRXui: case AArch64::STPDi: case AArch64::STRDui: case AArch64::LDPXi: case AArch64::LDRXui: case AArch64::LDPDi: case AArch64::LDRDui: Scale = 8; break; case AArch64::STPQi: case AArch64::STRQui: case AArch64::LDPQi: case AArch64::LDRQui: Scale = 16; break; default: llvm_unreachable("Unexpected callee-save save/restore opcode!"); } unsigned OffsetIdx = MI.getNumExplicitOperands() - 1; assert(MI.getOperand(OffsetIdx - 1).getReg() == AArch64::SP && "Unexpected base register in callee-save save/restore instruction!"); // Last operand is immediate offset that needs fixing. MachineOperand &OffsetOpnd = MI.getOperand(OffsetIdx); // All generated opcodes have scaled offsets. assert(LocalStackSize % Scale == 0); OffsetOpnd.setImm(OffsetOpnd.getImm() + LocalStackSize / Scale); if (NeedsWinCFI) { *HasWinCFI = true; auto MBBI = std::next(MachineBasicBlock::iterator(MI)); assert(MBBI != MI.getParent()->end() && "Expecting a valid instruction"); assert(AArch64InstrInfo::isSEHInstruction(*MBBI) && "Expecting a SEH instruction"); fixupSEHOpcode(MBBI, LocalStackSize); } } static void adaptForLdStOpt(MachineBasicBlock &MBB, MachineBasicBlock::iterator FirstSPPopI, MachineBasicBlock::iterator LastPopI) { // Sometimes (when we restore in the same order as we save), we can end up // with code like this: // // ldp x26, x25, [sp] // ldp x24, x23, [sp, #16] // ldp x22, x21, [sp, #32] // ldp x20, x19, [sp, #48] // add sp, sp, #64 // // In this case, it is always better to put the first ldp at the end, so // that the load-store optimizer can run and merge the ldp and the add into // a post-index ldp. // If we managed to grab the first pop instruction, move it to the end. if (ReverseCSRRestoreSeq) MBB.splice(FirstSPPopI, &MBB, LastPopI); // We should end up with something like this now: // // ldp x24, x23, [sp, #16] // ldp x22, x21, [sp, #32] // ldp x20, x19, [sp, #48] // ldp x26, x25, [sp] // add sp, sp, #64 // // and the load-store optimizer can merge the last two instructions into: // // ldp x26, x25, [sp], #64 // } static bool ShouldSignWithAKey(MachineFunction &MF) { const Function &F = MF.getFunction(); if (!F.hasFnAttribute("sign-return-address-key")) return true; const StringRef Key = F.getFnAttribute("sign-return-address-key").getValueAsString(); assert(Key.equals_lower("a_key") || Key.equals_lower("b_key")); return Key.equals_lower("a_key"); } static bool needsWinCFI(const MachineFunction &MF) { const Function &F = MF.getFunction(); return MF.getTarget().getMCAsmInfo()->usesWindowsCFI() && F.needsUnwindTableEntry(); } static bool isTargetDarwin(const MachineFunction &MF) { return MF.getSubtarget().isTargetDarwin(); } static bool isTargetWindows(const MachineFunction &MF) { return MF.getSubtarget().isTargetWindows(); } // Convenience function to determine whether I is an SVE callee save. static bool IsSVECalleeSave(MachineBasicBlock::iterator I) { switch (I->getOpcode()) { default: return false; case AArch64::STR_ZXI: case AArch64::STR_PXI: case AArch64::LDR_ZXI: case AArch64::LDR_PXI: return I->getFlag(MachineInstr::FrameSetup) || I->getFlag(MachineInstr::FrameDestroy); } } void AArch64FrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { MachineBasicBlock::iterator MBBI = MBB.begin(); const MachineFrameInfo &MFI = MF.getFrameInfo(); const Function &F = MF.getFunction(); const AArch64Subtarget &Subtarget = MF.getSubtarget(); const AArch64RegisterInfo *RegInfo = Subtarget.getRegisterInfo(); const TargetInstrInfo *TII = Subtarget.getInstrInfo(); MachineModuleInfo &MMI = MF.getMMI(); AArch64FunctionInfo *AFI = MF.getInfo(); bool needsFrameMoves = MF.needsFrameMoves() && !MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); bool HasFP = hasFP(MF); bool NeedsWinCFI = needsWinCFI(MF); bool HasWinCFI = false; auto Cleanup = make_scope_exit([&]() { MF.setHasWinCFI(HasWinCFI); }); bool IsFunclet = MBB.isEHFuncletEntry(); // At this point, we're going to decide whether or not the function uses a // redzone. In most cases, the function doesn't have a redzone so let's // assume that's false and set it to true in the case that there's a redzone. AFI->setHasRedZone(false); // Debug location must be unknown since the first debug location is used // to determine the end of the prologue. DebugLoc DL; if (ShouldSignReturnAddress(MF)) { if (ShouldSignWithAKey(MF)) BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP)) .setMIFlag(MachineInstr::FrameSetup); else { BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY)) .setMIFlag(MachineInstr::FrameSetup); BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIBSP)) .setMIFlag(MachineInstr::FrameSetup); } unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr)); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); } // All calls are tail calls in GHC calling conv, and functions have no // prologue/epilogue. if (MF.getFunction().getCallingConv() == CallingConv::GHC) return; // Set tagged base pointer to the bottom of the stack frame. // Ideally it should match SP value after prologue. AFI->setTaggedBasePointerOffset(MFI.getStackSize()); const StackOffset &SVEStackSize = getSVEStackSize(MF); // getStackSize() includes all the locals in its size calculation. We don't // include these locals when computing the stack size of a funclet, as they // are allocated in the parent's stack frame and accessed via the frame // pointer from the funclet. We only save the callee saved registers in the // funclet, which are really the callee saved registers of the parent // function, including the funclet. int64_t NumBytes = IsFunclet ? getWinEHFuncletFrameSize(MF) : MFI.getStackSize(); if (!AFI->hasStackFrame() && !windowsRequiresStackProbe(MF, NumBytes)) { assert(!HasFP && "unexpected function without stack frame but with FP"); assert(!SVEStackSize && "unexpected function without stack frame but with SVE objects"); // All of the stack allocation is for locals. AFI->setLocalStackSize(NumBytes); if (!NumBytes) return; // REDZONE: If the stack size is less than 128 bytes, we don't need // to actually allocate. if (canUseRedZone(MF)) { AFI->setHasRedZone(true); ++NumRedZoneFunctions; } else { emitFrameOffset(MBB, MBBI, DL, AArch64::SP, AArch64::SP, {-NumBytes, MVT::i8}, TII, MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI); if (!NeedsWinCFI && needsFrameMoves) { // Label used to tie together the PROLOG_LABEL and the MachineMoves. MCSymbol *FrameLabel = MMI.getContext().createTempSymbol(); // Encode the stack size of the leaf function. unsigned CFIIndex = MF.addFrameInst( MCCFIInstruction::createDefCfaOffset(FrameLabel, -NumBytes)); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); } } if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd)) .setMIFlag(MachineInstr::FrameSetup); } return; } bool IsWin64 = Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); - // Var args are accounted for in the containing function, so don't - // include them for funclets. - unsigned FixedObject = (IsWin64 && !IsFunclet) ? - alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet); auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject; // All of the remaining stack allocations are for locals. AFI->setLocalStackSize(NumBytes - PrologueSaveSize); bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes); if (CombineSPBump) { assert(!SVEStackSize && "Cannot combine SP bump with SVE"); emitFrameOffset(MBB, MBBI, DL, AArch64::SP, AArch64::SP, {-NumBytes, MVT::i8}, TII, MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI); NumBytes = 0; } else if (PrologueSaveSize != 0) { MBBI = convertCalleeSaveRestoreToSPPrePostIncDec( MBB, MBBI, DL, TII, -PrologueSaveSize, NeedsWinCFI, &HasWinCFI); NumBytes -= PrologueSaveSize; } assert(NumBytes >= 0 && "Negative stack allocation size!?"); // Move past the saves of the callee-saved registers, fixing up the offsets // and pre-inc if we decided to combine the callee-save and local stack // pointer bump above. MachineBasicBlock::iterator End = MBB.end(); while (MBBI != End && MBBI->getFlag(MachineInstr::FrameSetup) && !IsSVECalleeSave(MBBI)) { if (CombineSPBump) fixupCalleeSaveRestoreStackOffset(*MBBI, AFI->getLocalStackSize(), NeedsWinCFI, &HasWinCFI); ++MBBI; } - // The code below is not applicable to funclets. We have emitted all the SEH - // opcodes that we needed to emit. The FP and BP belong to the containing - // function. - if (IsFunclet) { - if (NeedsWinCFI) { - HasWinCFI = true; - BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd)) - .setMIFlag(MachineInstr::FrameSetup); - } - - // SEH funclets are passed the frame pointer in X1. If the parent - // function uses the base register, then the base register is used - // directly, and is not retrieved from X1. - if (F.hasPersonalityFn()) { - EHPersonality Per = classifyEHPersonality(F.getPersonalityFn()); - if (isAsynchronousEHPersonality(Per)) { - BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP) - .addReg(AArch64::X1).setMIFlag(MachineInstr::FrameSetup); - MBB.addLiveIn(AArch64::X1); - } - } - - return; - } - - if (HasFP) { + // For funclets the FP belongs to the containing function. + if (!IsFunclet && HasFP) { // Only set up FP if we actually need to. int64_t FPOffset = isTargetDarwin(MF) ? (AFI->getCalleeSavedStackSize() - 16) : 0; if (CombineSPBump) FPOffset += AFI->getLocalStackSize(); // Issue sub fp, sp, FPOffset or // mov fp,sp when FPOffset is zero. // Note: All stores of callee-saved registers are marked as "FrameSetup". // This code marks the instruction(s) that set the FP also. emitFrameOffset(MBB, MBBI, DL, AArch64::FP, AArch64::SP, {FPOffset, MVT::i8}, TII, MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI); } if (windowsRequiresStackProbe(MF, NumBytes)) { uint64_t NumWords = NumBytes >> 4; if (NeedsWinCFI) { HasWinCFI = true; // alloc_l can hold at most 256MB, so assume that NumBytes doesn't // exceed this amount. We need to move at most 2^24 - 1 into x15. // This is at most two instructions, MOVZ follwed by MOVK. // TODO: Fix to use multiple stack alloc unwind codes for stacks // exceeding 256MB in size. if (NumBytes >= (1 << 28)) report_fatal_error("Stack size cannot exceed 256MB for stack " "unwinding purposes"); uint32_t LowNumWords = NumWords & 0xFFFF; BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVZXi), AArch64::X15) .addImm(LowNumWords) .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, 0)) .setMIFlag(MachineInstr::FrameSetup); BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop)) .setMIFlag(MachineInstr::FrameSetup); if ((NumWords & 0xFFFF0000) != 0) { BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVKXi), AArch64::X15) .addReg(AArch64::X15) .addImm((NumWords & 0xFFFF0000) >> 16) // High half .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, 16)) .setMIFlag(MachineInstr::FrameSetup); BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop)) .setMIFlag(MachineInstr::FrameSetup); } } else { BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVi64imm), AArch64::X15) .addImm(NumWords) .setMIFlags(MachineInstr::FrameSetup); } switch (MF.getTarget().getCodeModel()) { case CodeModel::Tiny: case CodeModel::Small: case CodeModel::Medium: case CodeModel::Kernel: BuildMI(MBB, MBBI, DL, TII->get(AArch64::BL)) .addExternalSymbol("__chkstk") .addReg(AArch64::X15, RegState::Implicit) .addReg(AArch64::X16, RegState::Implicit | RegState::Define | RegState::Dead) .addReg(AArch64::X17, RegState::Implicit | RegState::Define | RegState::Dead) .addReg(AArch64::NZCV, RegState::Implicit | RegState::Define | RegState::Dead) .setMIFlags(MachineInstr::FrameSetup); if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop)) .setMIFlag(MachineInstr::FrameSetup); } break; case CodeModel::Large: BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVaddrEXT)) .addReg(AArch64::X16, RegState::Define) .addExternalSymbol("__chkstk") .addExternalSymbol("__chkstk") .setMIFlags(MachineInstr::FrameSetup); if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop)) .setMIFlag(MachineInstr::FrameSetup); } BuildMI(MBB, MBBI, DL, TII->get(AArch64::BLR)) .addReg(AArch64::X16, RegState::Kill) .addReg(AArch64::X15, RegState::Implicit | RegState::Define) .addReg(AArch64::X16, RegState::Implicit | RegState::Define | RegState::Dead) .addReg(AArch64::X17, RegState::Implicit | RegState::Define | RegState::Dead) .addReg(AArch64::NZCV, RegState::Implicit | RegState::Define | RegState::Dead) .setMIFlags(MachineInstr::FrameSetup); if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop)) .setMIFlag(MachineInstr::FrameSetup); } break; } BuildMI(MBB, MBBI, DL, TII->get(AArch64::SUBXrx64), AArch64::SP) .addReg(AArch64::SP, RegState::Kill) .addReg(AArch64::X15, RegState::Kill) .addImm(AArch64_AM::getArithExtendImm(AArch64_AM::UXTX, 4)) .setMIFlags(MachineInstr::FrameSetup); if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_StackAlloc)) .addImm(NumBytes) .setMIFlag(MachineInstr::FrameSetup); } NumBytes = 0; } StackOffset AllocateBefore = SVEStackSize, AllocateAfter = {}; MachineBasicBlock::iterator CalleeSavesBegin = MBBI, CalleeSavesEnd = MBBI; // Process the SVE callee-saves to determine what space needs to be // allocated. if (AFI->getSVECalleeSavedStackSize()) { // Find callee save instructions in frame. CalleeSavesBegin = MBBI; assert(IsSVECalleeSave(CalleeSavesBegin) && "Unexpected instruction"); while (IsSVECalleeSave(MBBI) && MBBI != MBB.getFirstTerminator()) ++MBBI; CalleeSavesEnd = MBBI; int64_t OffsetToFirstCalleeSaveFromSP = MFI.getObjectOffset(AFI->getMaxSVECSFrameIndex()); StackOffset OffsetToCalleeSavesFromSP = StackOffset(OffsetToFirstCalleeSaveFromSP, MVT::nxv1i8) + SVEStackSize; AllocateBefore -= OffsetToCalleeSavesFromSP; AllocateAfter = SVEStackSize - AllocateBefore; } // Allocate space for the callee saves (if any). emitFrameOffset(MBB, CalleeSavesBegin, DL, AArch64::SP, AArch64::SP, -AllocateBefore, TII, MachineInstr::FrameSetup); // Finally allocate remaining SVE stack space. emitFrameOffset(MBB, CalleeSavesEnd, DL, AArch64::SP, AArch64::SP, -AllocateAfter, TII, MachineInstr::FrameSetup); // Allocate space for the rest of the frame. if (NumBytes) { - const bool NeedsRealignment = RegInfo->needsStackRealignment(MF); + // Alignment is required for the parent frame, not the funclet + const bool NeedsRealignment = + !IsFunclet && RegInfo->needsStackRealignment(MF); unsigned scratchSPReg = AArch64::SP; if (NeedsRealignment) { scratchSPReg = findScratchNonCalleeSaveRegister(&MBB); assert(scratchSPReg != AArch64::NoRegister); } // If we're a leaf function, try using the red zone. if (!canUseRedZone(MF)) // FIXME: in the case of dynamic re-alignment, NumBytes doesn't have // the correct value here, as NumBytes also includes padding bytes, // which shouldn't be counted here. emitFrameOffset(MBB, MBBI, DL, scratchSPReg, AArch64::SP, {-NumBytes, MVT::i8}, TII, MachineInstr::FrameSetup, false, NeedsWinCFI, &HasWinCFI); if (NeedsRealignment) { const unsigned Alignment = MFI.getMaxAlignment(); const unsigned NrBitsToZero = countTrailingZeros(Alignment); assert(NrBitsToZero > 1); assert(scratchSPReg != AArch64::SP); // SUB X9, SP, NumBytes // -- X9 is temporary register, so shouldn't contain any live data here, // -- free to use. This is already produced by emitFrameOffset above. // AND SP, X9, 0b11111...0000 // The logical immediates have a non-trivial encoding. The following // formula computes the encoded immediate with all ones but // NrBitsToZero zero bits as least significant bits. uint32_t andMaskEncoded = (1 << 12) // = N | ((64 - NrBitsToZero) << 6) // immr | ((64 - NrBitsToZero - 1) << 0); // imms BuildMI(MBB, MBBI, DL, TII->get(AArch64::ANDXri), AArch64::SP) .addReg(scratchSPReg, RegState::Kill) .addImm(andMaskEncoded); AFI->setStackRealigned(true); if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_StackAlloc)) .addImm(NumBytes & andMaskEncoded) .setMIFlag(MachineInstr::FrameSetup); } } } // If we need a base pointer, set it up here. It's whatever the value of the // stack pointer is at this point. Any variable size objects will be allocated // after this, so we can still use the base pointer to reference locals. // // FIXME: Clarify FrameSetup flags here. // Note: Use emitFrameOffset() like above for FP if the FrameSetup flag is // needed. - if (RegInfo->hasBasePointer(MF)) { + // For funclets the BP belongs to the containing function. + if (!IsFunclet && RegInfo->hasBasePointer(MF)) { TII->copyPhysReg(MBB, MBBI, DL, RegInfo->getBaseRegister(), AArch64::SP, false); if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_Nop)) .setMIFlag(MachineInstr::FrameSetup); } } // The very last FrameSetup instruction indicates the end of prologue. Emit a // SEH opcode indicating the prologue end. if (NeedsWinCFI && HasWinCFI) { BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd)) .setMIFlag(MachineInstr::FrameSetup); } + // SEH funclets are passed the frame pointer in X1. If the parent + // function uses the base register, then the base register is used + // directly, and is not retrieved from X1. + if (IsFunclet && F.hasPersonalityFn()) { + EHPersonality Per = classifyEHPersonality(F.getPersonalityFn()); + if (isAsynchronousEHPersonality(Per)) { + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP) + .addReg(AArch64::X1) + .setMIFlag(MachineInstr::FrameSetup); + MBB.addLiveIn(AArch64::X1); + } + } + if (needsFrameMoves) { const DataLayout &TD = MF.getDataLayout(); const int StackGrowth = isTargetDarwin(MF) ? (2 * -TD.getPointerSize(0)) : -AFI->getCalleeSavedStackSize(); Register FramePtr = RegInfo->getFrameRegister(MF); // An example of the prologue: // // .globl __foo // .align 2 // __foo: // Ltmp0: // .cfi_startproc // .cfi_personality 155, ___gxx_personality_v0 // Leh_func_begin: // .cfi_lsda 16, Lexception33 // // stp xa,bx, [sp, -#offset]! // ... // stp x28, x27, [sp, #offset-32] // stp fp, lr, [sp, #offset-16] // add fp, sp, #offset - 16 // sub sp, sp, #1360 // // The Stack: // +-------------------------------------------+ // 10000 | ........ | ........ | ........ | ........ | // 10004 | ........ | ........ | ........ | ........ | // +-------------------------------------------+ // 10008 | ........ | ........ | ........ | ........ | // 1000c | ........ | ........ | ........ | ........ | // +===========================================+ // 10010 | X28 Register | // 10014 | X28 Register | // +-------------------------------------------+ // 10018 | X27 Register | // 1001c | X27 Register | // +===========================================+ // 10020 | Frame Pointer | // 10024 | Frame Pointer | // +-------------------------------------------+ // 10028 | Link Register | // 1002c | Link Register | // +===========================================+ // 10030 | ........ | ........ | ........ | ........ | // 10034 | ........ | ........ | ........ | ........ | // +-------------------------------------------+ // 10038 | ........ | ........ | ........ | ........ | // 1003c | ........ | ........ | ........ | ........ | // +-------------------------------------------+ // // [sp] = 10030 :: >>initial value<< // sp = 10020 :: stp fp, lr, [sp, #-16]! // fp = sp == 10020 :: mov fp, sp // [sp] == 10020 :: stp x28, x27, [sp, #-16]! // sp == 10010 :: >>final value<< // // The frame pointer (w29) points to address 10020. If we use an offset of // '16' from 'w29', we get the CFI offsets of -8 for w30, -16 for w29, -24 // for w27, and -32 for w28: // // Ltmp1: // .cfi_def_cfa w29, 16 // Ltmp2: // .cfi_offset w30, -8 // Ltmp3: // .cfi_offset w29, -16 // Ltmp4: // .cfi_offset w27, -24 // Ltmp5: // .cfi_offset w28, -32 if (HasFP) { // Define the current CFA rule to use the provided FP. unsigned Reg = RegInfo->getDwarfRegNum(FramePtr, true); unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( nullptr, Reg, StackGrowth - FixedObject)); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); } else { // Encode the stack size of the leaf function. unsigned CFIIndex = MF.addFrameInst( MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlags(MachineInstr::FrameSetup); } // Now emit the moves for whatever callee saved regs we have (including FP, // LR if those are saved). emitCalleeSavedFrameMoves(MBB, MBBI); } } static void InsertReturnAddressAuth(MachineFunction &MF, MachineBasicBlock &MBB) { if (!ShouldSignReturnAddress(MF)) return; const AArch64Subtarget &Subtarget = MF.getSubtarget(); const TargetInstrInfo *TII = Subtarget.getInstrInfo(); MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); DebugLoc DL; if (MBBI != MBB.end()) DL = MBBI->getDebugLoc(); // The AUTIASP instruction assembles to a hint instruction before v8.3a so // this instruction can safely used for any v8a architecture. // From v8.3a onwards there are optimised authenticate LR and return // instructions, namely RETA{A,B}, that can be used instead. if (Subtarget.hasV8_3aOps() && MBBI != MBB.end() && MBBI->getOpcode() == AArch64::RET_ReallyLR) { BuildMI(MBB, MBBI, DL, TII->get(ShouldSignWithAKey(MF) ? AArch64::RETAA : AArch64::RETAB)) .copyImplicitOps(*MBBI); MBB.erase(MBBI); } else { BuildMI( MBB, MBBI, DL, TII->get(ShouldSignWithAKey(MF) ? AArch64::AUTIASP : AArch64::AUTIBSP)) .setMIFlag(MachineInstr::FrameDestroy); } } static bool isFuncletReturnInstr(const MachineInstr &MI) { switch (MI.getOpcode()) { default: return false; case AArch64::CATCHRET: case AArch64::CLEANUPRET: return true; } } void AArch64FrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); MachineFrameInfo &MFI = MF.getFrameInfo(); const AArch64Subtarget &Subtarget = MF.getSubtarget(); const TargetInstrInfo *TII = Subtarget.getInstrInfo(); DebugLoc DL; bool IsTailCallReturn = false; bool NeedsWinCFI = needsWinCFI(MF); bool HasWinCFI = false; bool IsFunclet = false; auto WinCFI = make_scope_exit([&]() { if (!MF.hasWinCFI()) MF.setHasWinCFI(HasWinCFI); }); if (MBB.end() != MBBI) { DL = MBBI->getDebugLoc(); unsigned RetOpcode = MBBI->getOpcode(); IsTailCallReturn = RetOpcode == AArch64::TCRETURNdi || RetOpcode == AArch64::TCRETURNri || RetOpcode == AArch64::TCRETURNriBTI; IsFunclet = isFuncletReturnInstr(*MBBI); } int64_t NumBytes = IsFunclet ? getWinEHFuncletFrameSize(MF) : MFI.getStackSize(); AArch64FunctionInfo *AFI = MF.getInfo(); // All calls are tail calls in GHC calling conv, and functions have no // prologue/epilogue. if (MF.getFunction().getCallingConv() == CallingConv::GHC) return; // Initial and residual are named for consistency with the prologue. Note that // in the epilogue, the residual adjustment is executed first. uint64_t ArgumentPopSize = 0; if (IsTailCallReturn) { MachineOperand &StackAdjust = MBBI->getOperand(1); // For a tail-call in a callee-pops-arguments environment, some or all of // the stack may actually be in use for the call's arguments, this is // calculated during LowerCall and consumed here... ArgumentPopSize = StackAdjust.getImm(); } else { // ... otherwise the amount to pop is *all* of the argument space, // conveniently stored in the MachineFunctionInfo by // LowerFormalArguments. This will, of course, be zero for the C calling // convention. ArgumentPopSize = AFI->getArgumentStackToRestore(); } // The stack frame should be like below, // // ---------------------- --- // | | | // | BytesInStackArgArea| CalleeArgStackSize // | (NumReusableBytes) | (of tail call) // | | --- // | | | // ---------------------| --- | // | | | | // | CalleeSavedReg | | | // | (CalleeSavedStackSize)| | | // | | | | // ---------------------| | NumBytes // | | StackSize (StackAdjustUp) // | LocalStackSize | | | // | (covering callee | | | // | args) | | | // | | | | // ---------------------- --- --- // // So NumBytes = StackSize + BytesInStackArgArea - CalleeArgStackSize // = StackSize + ArgumentPopSize // // AArch64TargetLowering::LowerCall figures out ArgumentPopSize and keeps // it as the 2nd argument of AArch64ISD::TC_RETURN. auto Cleanup = make_scope_exit([&] { InsertReturnAddressAuth(MF, MBB); }); bool IsWin64 = Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); - // Var args are accounted for in the containing function, so don't - // include them for funclets. - unsigned FixedObject = - (IsWin64 && !IsFunclet) ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet); uint64_t AfterCSRPopSize = ArgumentPopSize; auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject; // We cannot rely on the local stack size set in emitPrologue if the function // has funclets, as funclets have different local stack size requirements, and // the current value set in emitPrologue may be that of the containing // function. if (MF.hasEHFunclets()) AFI->setLocalStackSize(NumBytes - PrologueSaveSize); bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes); // Assume we can't combine the last pop with the sp restore. if (!CombineSPBump && PrologueSaveSize != 0) { MachineBasicBlock::iterator Pop = std::prev(MBB.getFirstTerminator()); while (AArch64InstrInfo::isSEHInstruction(*Pop)) Pop = std::prev(Pop); // Converting the last ldp to a post-index ldp is valid only if the last // ldp's offset is 0. const MachineOperand &OffsetOp = Pop->getOperand(Pop->getNumOperands() - 1); // If the offset is 0, convert it to a post-index ldp. if (OffsetOp.getImm() == 0) convertCalleeSaveRestoreToSPPrePostIncDec( MBB, Pop, DL, TII, PrologueSaveSize, NeedsWinCFI, &HasWinCFI, false); else { // If not, make sure to emit an add after the last ldp. // We're doing this by transfering the size to be restored from the // adjustment *before* the CSR pops to the adjustment *after* the CSR // pops. AfterCSRPopSize += PrologueSaveSize; } } // Move past the restores of the callee-saved registers. // If we plan on combining the sp bump of the local stack size and the callee // save stack size, we might need to adjust the CSR save and restore offsets. MachineBasicBlock::iterator LastPopI = MBB.getFirstTerminator(); MachineBasicBlock::iterator Begin = MBB.begin(); while (LastPopI != Begin) { --LastPopI; if (!LastPopI->getFlag(MachineInstr::FrameDestroy) || IsSVECalleeSave(LastPopI)) { ++LastPopI; break; } else if (CombineSPBump) fixupCalleeSaveRestoreStackOffset(*LastPopI, AFI->getLocalStackSize(), NeedsWinCFI, &HasWinCFI); } if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, LastPopI, DL, TII->get(AArch64::SEH_EpilogStart)) .setMIFlag(MachineInstr::FrameDestroy); } const StackOffset &SVEStackSize = getSVEStackSize(MF); // If there is a single SP update, insert it before the ret and we're done. if (CombineSPBump) { assert(!SVEStackSize && "Cannot combine SP bump with SVE"); emitFrameOffset(MBB, MBB.getFirstTerminator(), DL, AArch64::SP, AArch64::SP, {NumBytes + (int64_t)AfterCSRPopSize, MVT::i8}, TII, MachineInstr::FrameDestroy, false, NeedsWinCFI, &HasWinCFI); if (NeedsWinCFI && HasWinCFI) BuildMI(MBB, MBB.getFirstTerminator(), DL, TII->get(AArch64::SEH_EpilogEnd)) .setMIFlag(MachineInstr::FrameDestroy); return; } NumBytes -= PrologueSaveSize; assert(NumBytes >= 0 && "Negative stack allocation size!?"); // Process the SVE callee-saves to determine what space needs to be // deallocated. StackOffset DeallocateBefore = {}, DeallocateAfter = SVEStackSize; MachineBasicBlock::iterator RestoreBegin = LastPopI, RestoreEnd = LastPopI; if (AFI->getSVECalleeSavedStackSize()) { RestoreBegin = std::prev(RestoreEnd);; while (IsSVECalleeSave(RestoreBegin) && RestoreBegin != MBB.begin()) --RestoreBegin; ++RestoreBegin; assert(IsSVECalleeSave(RestoreBegin) && IsSVECalleeSave(std::prev(RestoreEnd)) && "Unexpected instruction"); int64_t OffsetToFirstCalleeSaveFromSP = MFI.getObjectOffset(AFI->getMaxSVECSFrameIndex()); StackOffset OffsetToCalleeSavesFromSP = StackOffset(OffsetToFirstCalleeSaveFromSP, MVT::nxv1i8) + SVEStackSize; DeallocateBefore = OffsetToCalleeSavesFromSP; DeallocateAfter = SVEStackSize - DeallocateBefore; } // Deallocate the SVE area. if (SVEStackSize) { if (AFI->isStackRealigned()) { if (AFI->getSVECalleeSavedStackSize()) // Set SP to start of SVE area, from which the callee-save reloads // can be done. The code below will deallocate the stack space // space by moving FP -> SP. emitFrameOffset(MBB, RestoreBegin, DL, AArch64::SP, AArch64::FP, -SVEStackSize, TII, MachineInstr::FrameDestroy); } else { if (AFI->getSVECalleeSavedStackSize()) { // Deallocate the non-SVE locals first before we can deallocate (and // restore callee saves) from the SVE area. emitFrameOffset(MBB, RestoreBegin, DL, AArch64::SP, AArch64::SP, {NumBytes, MVT::i8}, TII, MachineInstr::FrameDestroy); NumBytes = 0; } emitFrameOffset(MBB, RestoreBegin, DL, AArch64::SP, AArch64::SP, DeallocateBefore, TII, MachineInstr::FrameDestroy); emitFrameOffset(MBB, RestoreEnd, DL, AArch64::SP, AArch64::SP, DeallocateAfter, TII, MachineInstr::FrameDestroy); } } if (!hasFP(MF)) { bool RedZone = canUseRedZone(MF); // If this was a redzone leaf function, we don't need to restore the // stack pointer (but we may need to pop stack args for fastcc). if (RedZone && AfterCSRPopSize == 0) return; bool NoCalleeSaveRestore = PrologueSaveSize == 0; int64_t StackRestoreBytes = RedZone ? 0 : NumBytes; if (NoCalleeSaveRestore) StackRestoreBytes += AfterCSRPopSize; // If we were able to combine the local stack pop with the argument pop, // then we're done. bool Done = NoCalleeSaveRestore || AfterCSRPopSize == 0; // If we're done after this, make sure to help the load store optimizer. if (Done) adaptForLdStOpt(MBB, MBB.getFirstTerminator(), LastPopI); emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::SP, {StackRestoreBytes, MVT::i8}, TII, MachineInstr::FrameDestroy, false, NeedsWinCFI, &HasWinCFI); if (Done) { if (NeedsWinCFI) { HasWinCFI = true; BuildMI(MBB, MBB.getFirstTerminator(), DL, TII->get(AArch64::SEH_EpilogEnd)) .setMIFlag(MachineInstr::FrameDestroy); } return; } NumBytes = 0; } // Restore the original stack pointer. // FIXME: Rather than doing the math here, we should instead just use // non-post-indexed loads for the restores if we aren't actually going to // be able to save any instructions. if (!IsFunclet && (MFI.hasVarSizedObjects() || AFI->isStackRealigned())) { int64_t OffsetToFrameRecord = isTargetDarwin(MF) ? (-(int64_t)AFI->getCalleeSavedStackSize() + 16) : 0; emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::FP, {OffsetToFrameRecord, MVT::i8}, TII, MachineInstr::FrameDestroy, false, NeedsWinCFI); } else if (NumBytes) emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::SP, {NumBytes, MVT::i8}, TII, MachineInstr::FrameDestroy, false, NeedsWinCFI); // This must be placed after the callee-save restore code because that code // assumes the SP is at the same location as it was after the callee-save save // code in the prologue. if (AfterCSRPopSize) { // Find an insertion point for the first ldp so that it goes before the // shadow call stack epilog instruction. This ensures that the restore of // lr from x18 is placed after the restore from sp. auto FirstSPPopI = MBB.getFirstTerminator(); while (FirstSPPopI != Begin) { auto Prev = std::prev(FirstSPPopI); if (Prev->getOpcode() != AArch64::LDRXpre || Prev->getOperand(0).getReg() == AArch64::SP) break; FirstSPPopI = Prev; } adaptForLdStOpt(MBB, FirstSPPopI, LastPopI); emitFrameOffset(MBB, FirstSPPopI, DL, AArch64::SP, AArch64::SP, {(int64_t)AfterCSRPopSize, MVT::i8}, TII, MachineInstr::FrameDestroy, false, NeedsWinCFI, &HasWinCFI); } if (NeedsWinCFI && HasWinCFI) BuildMI(MBB, MBB.getFirstTerminator(), DL, TII->get(AArch64::SEH_EpilogEnd)) .setMIFlag(MachineInstr::FrameDestroy); MF.setHasWinCFI(HasWinCFI); } /// getFrameIndexReference - Provide a base+offset reference to an FI slot for /// debug info. It's the same as what we use for resolving the code-gen /// references for now. FIXME: This can go wrong when references are /// SP-relative and simple call frames aren't used. int AArch64FrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const { return resolveFrameIndexReference( MF, FI, FrameReg, /*PreferFP=*/ MF.getFunction().hasFnAttribute(Attribute::SanitizeHWAddress), /*ForSimm=*/false) .getBytes(); } int AArch64FrameLowering::getNonLocalFrameIndexReference( const MachineFunction &MF, int FI) const { return getSEHFrameIndexOffset(MF, FI); } static StackOffset getFPOffset(const MachineFunction &MF, int64_t ObjectOffset) { const auto *AFI = MF.getInfo(); const auto &Subtarget = MF.getSubtarget(); bool IsWin64 = Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); - unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + + unsigned FixedObject = + getFixedObjectSize(MF, AFI, IsWin64, /*IsFunclet=*/false); unsigned FPAdjust = isTargetDarwin(MF) ? 16 : AFI->getCalleeSavedStackSize(MF.getFrameInfo()); return {ObjectOffset + FixedObject + FPAdjust, MVT::i8}; } static StackOffset getStackOffset(const MachineFunction &MF, int64_t ObjectOffset) { const auto &MFI = MF.getFrameInfo(); return {ObjectOffset + (int64_t)MFI.getStackSize(), MVT::i8}; } int AArch64FrameLowering::getSEHFrameIndexOffset(const MachineFunction &MF, int FI) const { const auto *RegInfo = static_cast( MF.getSubtarget().getRegisterInfo()); int ObjectOffset = MF.getFrameInfo().getObjectOffset(FI); return RegInfo->getLocalAddressRegister(MF) == AArch64::FP ? getFPOffset(MF, ObjectOffset).getBytes() : getStackOffset(MF, ObjectOffset).getBytes(); } StackOffset AArch64FrameLowering::resolveFrameIndexReference( const MachineFunction &MF, int FI, unsigned &FrameReg, bool PreferFP, bool ForSimm) const { const auto &MFI = MF.getFrameInfo(); int64_t ObjectOffset = MFI.getObjectOffset(FI); bool isFixed = MFI.isFixedObjectIndex(FI); bool isSVE = MFI.getStackID(FI) == TargetStackID::SVEVector; return resolveFrameOffsetReference(MF, ObjectOffset, isFixed, isSVE, FrameReg, PreferFP, ForSimm); } StackOffset AArch64FrameLowering::resolveFrameOffsetReference( const MachineFunction &MF, int64_t ObjectOffset, bool isFixed, bool isSVE, unsigned &FrameReg, bool PreferFP, bool ForSimm) const { const auto &MFI = MF.getFrameInfo(); const auto *RegInfo = static_cast( MF.getSubtarget().getRegisterInfo()); const auto *AFI = MF.getInfo(); const auto &Subtarget = MF.getSubtarget(); int64_t FPOffset = getFPOffset(MF, ObjectOffset).getBytes(); int64_t Offset = getStackOffset(MF, ObjectOffset).getBytes(); bool isCSR = !isFixed && ObjectOffset >= -((int)AFI->getCalleeSavedStackSize(MFI)); const StackOffset &SVEStackSize = getSVEStackSize(MF); // Use frame pointer to reference fixed objects. Use it for locals if // there are VLAs or a dynamically realigned SP (and thus the SP isn't // reliable as a base). Make sure useFPForScavengingIndex() does the // right thing for the emergency spill slot. bool UseFP = false; if (AFI->hasStackFrame() && !isSVE) { // We shouldn't prefer using the FP when there is an SVE area // in between the FP and the non-SVE locals/spills. PreferFP &= !SVEStackSize; // Note: Keeping the following as multiple 'if' statements rather than // merging to a single expression for readability. // // Argument access should always use the FP. if (isFixed) { UseFP = hasFP(MF); } else if (isCSR && RegInfo->needsStackRealignment(MF)) { // References to the CSR area must use FP if we're re-aligning the stack // since the dynamically-sized alignment padding is between the SP/BP and // the CSR area. assert(hasFP(MF) && "Re-aligned stack must have frame pointer"); UseFP = true; } else if (hasFP(MF) && !RegInfo->needsStackRealignment(MF)) { // If the FPOffset is negative and we're producing a signed immediate, we // have to keep in mind that the available offset range for negative // offsets is smaller than for positive ones. If an offset is available // via the FP and the SP, use whichever is closest. bool FPOffsetFits = !ForSimm || FPOffset >= -256; PreferFP |= Offset > -FPOffset; if (MFI.hasVarSizedObjects()) { // If we have variable sized objects, we can use either FP or BP, as the // SP offset is unknown. We can use the base pointer if we have one and // FP is not preferred. If not, we're stuck with using FP. bool CanUseBP = RegInfo->hasBasePointer(MF); if (FPOffsetFits && CanUseBP) // Both are ok. Pick the best. UseFP = PreferFP; else if (!CanUseBP) { // Can't use BP. Forced to use FP. assert(!SVEStackSize && "Expected BP to be available"); UseFP = true; } // else we can use BP and FP, but the offset from FP won't fit. // That will make us scavenge registers which we can probably avoid by // using BP. If it won't fit for BP either, we'll scavenge anyway. } else if (FPOffset >= 0) { // Use SP or FP, whichever gives us the best chance of the offset // being in range for direct access. If the FPOffset is positive, // that'll always be best, as the SP will be even further away. UseFP = true; } else if (MF.hasEHFunclets() && !RegInfo->hasBasePointer(MF)) { // Funclets access the locals contained in the parent's stack frame // via the frame pointer, so we have to use the FP in the parent // function. (void) Subtarget; assert( Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()) && "Funclets should only be present on Win64"); UseFP = true; } else { // We have the choice between FP and (SP or BP). if (FPOffsetFits && PreferFP) // If FP is the best fit, use it. UseFP = true; } } } assert(((isFixed || isCSR) || !RegInfo->needsStackRealignment(MF) || !UseFP) && "In the presence of dynamic stack pointer realignment, " "non-argument/CSR objects cannot be accessed through the frame pointer"); if (isSVE) { int64_t OffsetToSVEArea = MFI.getStackSize() - AFI->getCalleeSavedStackSize(); StackOffset FPOffset = {ObjectOffset, MVT::nxv1i8}; StackOffset SPOffset = SVEStackSize + StackOffset(ObjectOffset, MVT::nxv1i8) + StackOffset(OffsetToSVEArea, MVT::i8); // Always use the FP for SVE spills if available and beneficial. if (hasFP(MF) && (SPOffset.getBytes() || FPOffset.getScalableBytes() < SPOffset.getScalableBytes() || RegInfo->needsStackRealignment(MF))) { FrameReg = RegInfo->getFrameRegister(MF); return FPOffset; } FrameReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() : (unsigned)AArch64::SP; return SPOffset; } StackOffset ScalableOffset = {}; if (UseFP && !(isFixed || isCSR)) ScalableOffset = -SVEStackSize; if (!UseFP && (isFixed || isCSR)) ScalableOffset = SVEStackSize; if (UseFP) { FrameReg = RegInfo->getFrameRegister(MF); return StackOffset(FPOffset, MVT::i8) + ScalableOffset; } // Use the base pointer if we have one. if (RegInfo->hasBasePointer(MF)) FrameReg = RegInfo->getBaseRegister(); else { assert(!MFI.hasVarSizedObjects() && "Can't use SP when we have var sized objects."); FrameReg = AArch64::SP; // If we're using the red zone for this function, the SP won't actually // be adjusted, so the offsets will be negative. They're also all // within range of the signed 9-bit immediate instructions. if (canUseRedZone(MF)) Offset -= AFI->getLocalStackSize(); } return StackOffset(Offset, MVT::i8) + ScalableOffset; } static unsigned getPrologueDeath(MachineFunction &MF, unsigned Reg) { // Do not set a kill flag on values that are also marked as live-in. This // happens with the @llvm-returnaddress intrinsic and with arguments passed in // callee saved registers. // Omitting the kill flags is conservatively correct even if the live-in // is not used after all. bool IsLiveIn = MF.getRegInfo().isLiveIn(Reg); return getKillRegState(!IsLiveIn); } static bool produceCompactUnwindFrame(MachineFunction &MF) { const AArch64Subtarget &Subtarget = MF.getSubtarget(); AttributeList Attrs = MF.getFunction().getAttributes(); return Subtarget.isTargetMachO() && !(Subtarget.getTargetLowering()->supportSwiftError() && Attrs.hasAttrSomewhere(Attribute::SwiftError)); } static bool invalidateWindowsRegisterPairing(unsigned Reg1, unsigned Reg2, bool NeedsWinCFI) { // If we are generating register pairs for a Windows function that requires // EH support, then pair consecutive registers only. There are no unwind // opcodes for saves/restores of non-consectuve register pairs. // The unwind opcodes are save_regp, save_regp_x, save_fregp, save_frepg_x. // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling // TODO: LR can be paired with any register. We don't support this yet in // the MCLayer. We need to add support for the save_lrpair unwind code. if (Reg2 == AArch64::FP) return true; if (!NeedsWinCFI) return false; if (Reg2 == Reg1 + 1) return false; return true; } /// Returns true if Reg1 and Reg2 cannot be paired using a ldp/stp instruction. /// WindowsCFI requires that only consecutive registers can be paired. /// LR and FP need to be allocated together when the frame needs to save /// the frame-record. This means any other register pairing with LR is invalid. static bool invalidateRegisterPairing(unsigned Reg1, unsigned Reg2, bool UsesWinAAPCS, bool NeedsWinCFI, bool NeedsFrameRecord) { if (UsesWinAAPCS) return invalidateWindowsRegisterPairing(Reg1, Reg2, NeedsWinCFI); // If we need to store the frame record, don't pair any register // with LR other than FP. if (NeedsFrameRecord) return Reg2 == AArch64::LR; return false; } namespace { struct RegPairInfo { unsigned Reg1 = AArch64::NoRegister; unsigned Reg2 = AArch64::NoRegister; int FrameIdx; int Offset; enum RegType { GPR, FPR64, FPR128, PPR, ZPR } Type; RegPairInfo() = default; bool isPaired() const { return Reg2 != AArch64::NoRegister; } unsigned getScale() const { switch (Type) { case PPR: return 2; case GPR: case FPR64: return 8; case ZPR: case FPR128: return 16; } llvm_unreachable("Unsupported type"); } bool isScalable() const { return Type == PPR || Type == ZPR; } }; } // end anonymous namespace static void computeCalleeSaveRegisterPairs( MachineFunction &MF, const std::vector &CSI, const TargetRegisterInfo *TRI, SmallVectorImpl &RegPairs, bool &NeedShadowCallStackProlog, bool NeedsFrameRecord) { if (CSI.empty()) return; bool IsWindows = isTargetWindows(MF); bool NeedsWinCFI = needsWinCFI(MF); AArch64FunctionInfo *AFI = MF.getInfo(); MachineFrameInfo &MFI = MF.getFrameInfo(); CallingConv::ID CC = MF.getFunction().getCallingConv(); unsigned Count = CSI.size(); (void)CC; // MachO's compact unwind format relies on all registers being stored in // pairs. assert((!produceCompactUnwindFrame(MF) || CC == CallingConv::PreserveMost || (Count & 1) == 0) && "Odd number of callee-saved regs to spill!"); int ByteOffset = AFI->getCalleeSavedStackSize(); int ScalableByteOffset = AFI->getSVECalleeSavedStackSize(); // On Linux, we will have either one or zero non-paired register. On Windows // with CFI, we can have multiple unpaired registers in order to utilize the // available unwind codes. This flag assures that the alignment fixup is done // only once, as intened. bool FixupDone = false; for (unsigned i = 0; i < Count; ++i) { RegPairInfo RPI; RPI.Reg1 = CSI[i].getReg(); if (AArch64::GPR64RegClass.contains(RPI.Reg1)) RPI.Type = RegPairInfo::GPR; else if (AArch64::FPR64RegClass.contains(RPI.Reg1)) RPI.Type = RegPairInfo::FPR64; else if (AArch64::FPR128RegClass.contains(RPI.Reg1)) RPI.Type = RegPairInfo::FPR128; else if (AArch64::ZPRRegClass.contains(RPI.Reg1)) RPI.Type = RegPairInfo::ZPR; else if (AArch64::PPRRegClass.contains(RPI.Reg1)) RPI.Type = RegPairInfo::PPR; else llvm_unreachable("Unsupported register class."); // Add the next reg to the pair if it is in the same register class. if (i + 1 < Count) { unsigned NextReg = CSI[i + 1].getReg(); switch (RPI.Type) { case RegPairInfo::GPR: if (AArch64::GPR64RegClass.contains(NextReg) && !invalidateRegisterPairing(RPI.Reg1, NextReg, IsWindows, NeedsWinCFI, NeedsFrameRecord)) RPI.Reg2 = NextReg; break; case RegPairInfo::FPR64: if (AArch64::FPR64RegClass.contains(NextReg) && !invalidateWindowsRegisterPairing(RPI.Reg1, NextReg, NeedsWinCFI)) RPI.Reg2 = NextReg; break; case RegPairInfo::FPR128: if (AArch64::FPR128RegClass.contains(NextReg)) RPI.Reg2 = NextReg; break; case RegPairInfo::PPR: case RegPairInfo::ZPR: break; } } // If either of the registers to be saved is the lr register, it means that // we also need to save lr in the shadow call stack. if ((RPI.Reg1 == AArch64::LR || RPI.Reg2 == AArch64::LR) && MF.getFunction().hasFnAttribute(Attribute::ShadowCallStack)) { if (!MF.getSubtarget().isXRegisterReserved(18)) report_fatal_error("Must reserve x18 to use shadow call stack"); NeedShadowCallStackProlog = true; } // GPRs and FPRs are saved in pairs of 64-bit regs. We expect the CSI // list to come in sorted by frame index so that we can issue the store // pair instructions directly. Assert if we see anything otherwise. // // The order of the registers in the list is controlled by // getCalleeSavedRegs(), so they will always be in-order, as well. assert((!RPI.isPaired() || (CSI[i].getFrameIdx() + 1 == CSI[i + 1].getFrameIdx())) && "Out of order callee saved regs!"); assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg2 != AArch64::FP || RPI.Reg1 == AArch64::LR) && "FrameRecord must be allocated together with LR"); // Windows AAPCS has FP and LR reversed. assert((!RPI.isPaired() || !NeedsFrameRecord || RPI.Reg1 != AArch64::FP || RPI.Reg2 == AArch64::LR) && "FrameRecord must be allocated together with LR"); // MachO's compact unwind format relies on all registers being stored in // adjacent register pairs. assert((!produceCompactUnwindFrame(MF) || CC == CallingConv::PreserveMost || (RPI.isPaired() && ((RPI.Reg1 == AArch64::LR && RPI.Reg2 == AArch64::FP) || RPI.Reg1 + 1 == RPI.Reg2))) && "Callee-save registers not saved as adjacent register pair!"); RPI.FrameIdx = CSI[i].getFrameIdx(); int Scale = RPI.getScale(); if (RPI.isScalable()) ScalableByteOffset -= Scale; else ByteOffset -= RPI.isPaired() ? 2 * Scale : Scale; assert(!(RPI.isScalable() && RPI.isPaired()) && "Paired spill/fill instructions don't exist for SVE vectors"); // Round up size of non-pair to pair size if we need to pad the // callee-save area to ensure 16-byte alignment. if (AFI->hasCalleeSaveStackFreeSpace() && !FixupDone && !RPI.isScalable() && RPI.Type != RegPairInfo::FPR128 && !RPI.isPaired()) { FixupDone = true; ByteOffset -= 8; assert(ByteOffset % 16 == 0); assert(MFI.getObjectAlignment(RPI.FrameIdx) <= 16); MFI.setObjectAlignment(RPI.FrameIdx, 16); } int Offset = RPI.isScalable() ? ScalableByteOffset : ByteOffset; assert(Offset % Scale == 0); RPI.Offset = Offset / Scale; assert(((!RPI.isScalable() && RPI.Offset >= -64 && RPI.Offset <= 63) || (RPI.isScalable() && RPI.Offset >= -256 && RPI.Offset <= 255)) && "Offset out of bounds for LDP/STP immediate"); RegPairs.push_back(RPI); if (RPI.isPaired()) ++i; } } bool AArch64FrameLowering::spillCalleeSavedRegisters( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const std::vector &CSI, const TargetRegisterInfo *TRI) const { MachineFunction &MF = *MBB.getParent(); const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); bool NeedsWinCFI = needsWinCFI(MF); DebugLoc DL; SmallVector RegPairs; bool NeedShadowCallStackProlog = false; computeCalleeSaveRegisterPairs(MF, CSI, TRI, RegPairs, NeedShadowCallStackProlog, hasFP(MF)); const MachineRegisterInfo &MRI = MF.getRegInfo(); if (NeedShadowCallStackProlog) { // Shadow call stack prolog: str x30, [x18], #8 BuildMI(MBB, MI, DL, TII.get(AArch64::STRXpost)) .addReg(AArch64::X18, RegState::Define) .addReg(AArch64::LR) .addReg(AArch64::X18) .addImm(8) .setMIFlag(MachineInstr::FrameSetup); if (NeedsWinCFI) BuildMI(MBB, MI, DL, TII.get(AArch64::SEH_Nop)) .setMIFlag(MachineInstr::FrameSetup); if (!MF.getFunction().hasFnAttribute(Attribute::NoUnwind)) { // Emit a CFI instruction that causes 8 to be subtracted from the value of // x18 when unwinding past this frame. static const char CFIInst[] = { dwarf::DW_CFA_val_expression, 18, // register 2, // length static_cast(unsigned(dwarf::DW_OP_breg18)), static_cast(-8) & 0x7f, // addend (sleb128) }; unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createEscape( nullptr, StringRef(CFIInst, sizeof(CFIInst)))); BuildMI(MBB, MI, DL, TII.get(AArch64::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex) .setMIFlag(MachineInstr::FrameSetup); } // This instruction also makes x18 live-in to the entry block. MBB.addLiveIn(AArch64::X18); } for (auto RPII = RegPairs.rbegin(), RPIE = RegPairs.rend(); RPII != RPIE; ++RPII) { RegPairInfo RPI = *RPII; unsigned Reg1 = RPI.Reg1; unsigned Reg2 = RPI.Reg2; unsigned StrOpc; // Issue sequence of spills for cs regs. The first spill may be converted // to a pre-decrement store later by emitPrologue if the callee-save stack // area allocation can't be combined with the local stack area allocation. // For example: // stp x22, x21, [sp, #0] // addImm(+0) // stp x20, x19, [sp, #16] // addImm(+2) // stp fp, lr, [sp, #32] // addImm(+4) // Rationale: This sequence saves uop updates compared to a sequence of // pre-increment spills like stp xi,xj,[sp,#-16]! // Note: Similar rationale and sequence for restores in epilog. unsigned Size, Align; switch (RPI.Type) { case RegPairInfo::GPR: StrOpc = RPI.isPaired() ? AArch64::STPXi : AArch64::STRXui; Size = 8; Align = 8; break; case RegPairInfo::FPR64: StrOpc = RPI.isPaired() ? AArch64::STPDi : AArch64::STRDui; Size = 8; Align = 8; break; case RegPairInfo::FPR128: StrOpc = RPI.isPaired() ? AArch64::STPQi : AArch64::STRQui; Size = 16; Align = 16; break; case RegPairInfo::ZPR: StrOpc = AArch64::STR_ZXI; Size = 16; Align = 16; break; case RegPairInfo::PPR: StrOpc = AArch64::STR_PXI; Size = 2; Align = 2; break; } LLVM_DEBUG(dbgs() << "CSR spill: (" << printReg(Reg1, TRI); if (RPI.isPaired()) dbgs() << ", " << printReg(Reg2, TRI); dbgs() << ") -> fi#(" << RPI.FrameIdx; if (RPI.isPaired()) dbgs() << ", " << RPI.FrameIdx + 1; dbgs() << ")\n"); assert((!NeedsWinCFI || !(Reg1 == AArch64::LR && Reg2 == AArch64::FP)) && "Windows unwdinding requires a consecutive (FP,LR) pair"); // Windows unwind codes require consecutive registers if registers are // paired. Make the switch here, so that the code below will save (x,x+1) // and not (x+1,x). unsigned FrameIdxReg1 = RPI.FrameIdx; unsigned FrameIdxReg2 = RPI.FrameIdx + 1; if (NeedsWinCFI && RPI.isPaired()) { std::swap(Reg1, Reg2); std::swap(FrameIdxReg1, FrameIdxReg2); } MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StrOpc)); if (!MRI.isReserved(Reg1)) MBB.addLiveIn(Reg1); if (RPI.isPaired()) { if (!MRI.isReserved(Reg2)) MBB.addLiveIn(Reg2); MIB.addReg(Reg2, getPrologueDeath(MF, Reg2)); MIB.addMemOperand(MF.getMachineMemOperand( MachinePointerInfo::getFixedStack(MF, FrameIdxReg2), MachineMemOperand::MOStore, Size, Align)); } MIB.addReg(Reg1, getPrologueDeath(MF, Reg1)) .addReg(AArch64::SP) .addImm(RPI.Offset) // [sp, #offset*scale], // where factor*scale is implicit .setMIFlag(MachineInstr::FrameSetup); MIB.addMemOperand(MF.getMachineMemOperand( MachinePointerInfo::getFixedStack(MF,FrameIdxReg1), MachineMemOperand::MOStore, Size, Align)); if (NeedsWinCFI) InsertSEH(MIB, TII, MachineInstr::FrameSetup); // Update the StackIDs of the SVE stack slots. MachineFrameInfo &MFI = MF.getFrameInfo(); if (RPI.Type == RegPairInfo::ZPR || RPI.Type == RegPairInfo::PPR) MFI.setStackID(RPI.FrameIdx, TargetStackID::SVEVector); } return true; } bool AArch64FrameLowering::restoreCalleeSavedRegisters( MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, std::vector &CSI, const TargetRegisterInfo *TRI) const { MachineFunction &MF = *MBB.getParent(); const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); DebugLoc DL; SmallVector RegPairs; bool NeedsWinCFI = needsWinCFI(MF); if (MI != MBB.end()) DL = MI->getDebugLoc(); bool NeedShadowCallStackProlog = false; computeCalleeSaveRegisterPairs(MF, CSI, TRI, RegPairs, NeedShadowCallStackProlog, hasFP(MF)); auto EmitMI = [&](const RegPairInfo &RPI) { unsigned Reg1 = RPI.Reg1; unsigned Reg2 = RPI.Reg2; // Issue sequence of restores for cs regs. The last restore may be converted // to a post-increment load later by emitEpilogue if the callee-save stack // area allocation can't be combined with the local stack area allocation. // For example: // ldp fp, lr, [sp, #32] // addImm(+4) // ldp x20, x19, [sp, #16] // addImm(+2) // ldp x22, x21, [sp, #0] // addImm(+0) // Note: see comment in spillCalleeSavedRegisters() unsigned LdrOpc; unsigned Size, Align; switch (RPI.Type) { case RegPairInfo::GPR: LdrOpc = RPI.isPaired() ? AArch64::LDPXi : AArch64::LDRXui; Size = 8; Align = 8; break; case RegPairInfo::FPR64: LdrOpc = RPI.isPaired() ? AArch64::LDPDi : AArch64::LDRDui; Size = 8; Align = 8; break; case RegPairInfo::FPR128: LdrOpc = RPI.isPaired() ? AArch64::LDPQi : AArch64::LDRQui; Size = 16; Align = 16; break; case RegPairInfo::ZPR: LdrOpc = AArch64::LDR_ZXI; Size = 16; Align = 16; break; case RegPairInfo::PPR: LdrOpc = AArch64::LDR_PXI; Size = 2; Align = 2; break; } LLVM_DEBUG(dbgs() << "CSR restore: (" << printReg(Reg1, TRI); if (RPI.isPaired()) dbgs() << ", " << printReg(Reg2, TRI); dbgs() << ") -> fi#(" << RPI.FrameIdx; if (RPI.isPaired()) dbgs() << ", " << RPI.FrameIdx + 1; dbgs() << ")\n"); // Windows unwind codes require consecutive registers if registers are // paired. Make the switch here, so that the code below will save (x,x+1) // and not (x+1,x). unsigned FrameIdxReg1 = RPI.FrameIdx; unsigned FrameIdxReg2 = RPI.FrameIdx + 1; if (NeedsWinCFI && RPI.isPaired()) { std::swap(Reg1, Reg2); std::swap(FrameIdxReg1, FrameIdxReg2); } MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(LdrOpc)); if (RPI.isPaired()) { MIB.addReg(Reg2, getDefRegState(true)); MIB.addMemOperand(MF.getMachineMemOperand( MachinePointerInfo::getFixedStack(MF, FrameIdxReg2), MachineMemOperand::MOLoad, Size, Align)); } MIB.addReg(Reg1, getDefRegState(true)) .addReg(AArch64::SP) .addImm(RPI.Offset) // [sp, #offset*scale] // where factor*scale is implicit .setMIFlag(MachineInstr::FrameDestroy); MIB.addMemOperand(MF.getMachineMemOperand( MachinePointerInfo::getFixedStack(MF, FrameIdxReg1), MachineMemOperand::MOLoad, Size, Align)); if (NeedsWinCFI) InsertSEH(MIB, TII, MachineInstr::FrameDestroy); }; // SVE objects are always restored in reverse order. for (const RegPairInfo &RPI : reverse(RegPairs)) if (RPI.isScalable()) EmitMI(RPI); if (ReverseCSRRestoreSeq) { for (const RegPairInfo &RPI : reverse(RegPairs)) if (!RPI.isScalable()) EmitMI(RPI); } else for (const RegPairInfo &RPI : RegPairs) if (!RPI.isScalable()) EmitMI(RPI); if (NeedShadowCallStackProlog) { // Shadow call stack epilog: ldr x30, [x18, #-8]! BuildMI(MBB, MI, DL, TII.get(AArch64::LDRXpre)) .addReg(AArch64::X18, RegState::Define) .addReg(AArch64::LR, RegState::Define) .addReg(AArch64::X18) .addImm(-8) .setMIFlag(MachineInstr::FrameDestroy); } return true; } void AArch64FrameLowering::determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const { // All calls are tail calls in GHC calling conv, and functions have no // prologue/epilogue. if (MF.getFunction().getCallingConv() == CallingConv::GHC) return; TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); const AArch64RegisterInfo *RegInfo = static_cast( MF.getSubtarget().getRegisterInfo()); AArch64FunctionInfo *AFI = MF.getInfo(); unsigned UnspilledCSGPR = AArch64::NoRegister; unsigned UnspilledCSGPRPaired = AArch64::NoRegister; MachineFrameInfo &MFI = MF.getFrameInfo(); const MCPhysReg *CSRegs = MF.getRegInfo().getCalleeSavedRegs(); unsigned BasePointerReg = RegInfo->hasBasePointer(MF) ? RegInfo->getBaseRegister() : (unsigned)AArch64::NoRegister; unsigned ExtraCSSpill = 0; // Figure out which callee-saved registers to save/restore. for (unsigned i = 0; CSRegs[i]; ++i) { const unsigned Reg = CSRegs[i]; // Add the base pointer register to SavedRegs if it is callee-save. if (Reg == BasePointerReg) SavedRegs.set(Reg); bool RegUsed = SavedRegs.test(Reg); unsigned PairedReg = AArch64::NoRegister; if (AArch64::GPR64RegClass.contains(Reg) || AArch64::FPR64RegClass.contains(Reg) || AArch64::FPR128RegClass.contains(Reg)) PairedReg = CSRegs[i ^ 1]; if (!RegUsed) { if (AArch64::GPR64RegClass.contains(Reg) && !RegInfo->isReservedReg(MF, Reg)) { UnspilledCSGPR = Reg; UnspilledCSGPRPaired = PairedReg; } continue; } // MachO's compact unwind format relies on all registers being stored in // pairs. // FIXME: the usual format is actually better if unwinding isn't needed. if (produceCompactUnwindFrame(MF) && PairedReg != AArch64::NoRegister && !SavedRegs.test(PairedReg)) { SavedRegs.set(PairedReg); if (AArch64::GPR64RegClass.contains(PairedReg) && !RegInfo->isReservedReg(MF, PairedReg)) ExtraCSSpill = PairedReg; } } // Calculates the callee saved stack size. unsigned CSStackSize = 0; unsigned SVECSStackSize = 0; const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); const MachineRegisterInfo &MRI = MF.getRegInfo(); for (unsigned Reg : SavedRegs.set_bits()) { auto RegSize = TRI->getRegSizeInBits(Reg, MRI) / 8; if (AArch64::PPRRegClass.contains(Reg) || AArch64::ZPRRegClass.contains(Reg)) SVECSStackSize += RegSize; else CSStackSize += RegSize; } // Save number of saved regs, so we can easily update CSStackSize later. unsigned NumSavedRegs = SavedRegs.count(); // The frame record needs to be created by saving the appropriate registers uint64_t EstimatedStackSize = MFI.estimateStackSize(MF); if (hasFP(MF) || windowsRequiresStackProbe(MF, EstimatedStackSize + CSStackSize + 16)) { SavedRegs.set(AArch64::FP); SavedRegs.set(AArch64::LR); } LLVM_DEBUG(dbgs() << "*** determineCalleeSaves\nSaved CSRs:"; for (unsigned Reg : SavedRegs.set_bits()) dbgs() << ' ' << printReg(Reg, RegInfo); dbgs() << "\n";); // If any callee-saved registers are used, the frame cannot be eliminated. int64_t SVEStackSize = alignTo(SVECSStackSize + estimateSVEStackObjectOffsets(MFI), 16); bool CanEliminateFrame = (SavedRegs.count() == 0) && !SVEStackSize; // The CSR spill slots have not been allocated yet, so estimateStackSize // won't include them. unsigned EstimatedStackSizeLimit = estimateRSStackSizeLimit(MF); // Conservatively always assume BigStack when there are SVE spills. bool BigStack = SVEStackSize || (EstimatedStackSize + CSStackSize) > EstimatedStackSizeLimit; if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF)) AFI->setHasStackFrame(true); // Estimate if we might need to scavenge a register at some point in order // to materialize a stack offset. If so, either spill one additional // callee-saved register or reserve a special spill slot to facilitate // register scavenging. If we already spilled an extra callee-saved register // above to keep the number of spills even, we don't need to do anything else // here. if (BigStack) { if (!ExtraCSSpill && UnspilledCSGPR != AArch64::NoRegister) { LLVM_DEBUG(dbgs() << "Spilling " << printReg(UnspilledCSGPR, RegInfo) << " to get a scratch register.\n"); SavedRegs.set(UnspilledCSGPR); // MachO's compact unwind format relies on all registers being stored in // pairs, so if we need to spill one extra for BigStack, then we need to // store the pair. if (produceCompactUnwindFrame(MF)) SavedRegs.set(UnspilledCSGPRPaired); ExtraCSSpill = UnspilledCSGPR; } // If we didn't find an extra callee-saved register to spill, create // an emergency spill slot. if (!ExtraCSSpill || MF.getRegInfo().isPhysRegUsed(ExtraCSSpill)) { const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); const TargetRegisterClass &RC = AArch64::GPR64RegClass; unsigned Size = TRI->getSpillSize(RC); unsigned Align = TRI->getSpillAlignment(RC); int FI = MFI.CreateStackObject(Size, Align, false); RS->addScavengingFrameIndex(FI); LLVM_DEBUG(dbgs() << "No available CS registers, allocated fi#" << FI << " as the emergency spill slot.\n"); } } // Adding the size of additional 64bit GPR saves. CSStackSize += 8 * (SavedRegs.count() - NumSavedRegs); uint64_t AlignedCSStackSize = alignTo(CSStackSize, 16); LLVM_DEBUG(dbgs() << "Estimated stack frame size: " << EstimatedStackSize + AlignedCSStackSize << " bytes.\n"); assert((!MFI.isCalleeSavedInfoValid() || AFI->getCalleeSavedStackSize() == AlignedCSStackSize) && "Should not invalidate callee saved info"); // Round up to register pair alignment to avoid additional SP adjustment // instructions. AFI->setCalleeSavedStackSize(AlignedCSStackSize); AFI->setCalleeSaveStackHasFreeSpace(AlignedCSStackSize != CSStackSize); AFI->setSVECalleeSavedStackSize(alignTo(SVECSStackSize, 16)); } bool AArch64FrameLowering::enableStackSlotScavenging( const MachineFunction &MF) const { const AArch64FunctionInfo *AFI = MF.getInfo(); return AFI->hasCalleeSaveStackFreeSpace(); } /// returns true if there are any SVE callee saves. static bool getSVECalleeSaveSlotRange(const MachineFrameInfo &MFI, int &Min, int &Max) { Min = std::numeric_limits::max(); Max = std::numeric_limits::min(); if (!MFI.isCalleeSavedInfoValid()) return false; const std::vector &CSI = MFI.getCalleeSavedInfo(); for (auto &CS : CSI) { if (AArch64::ZPRRegClass.contains(CS.getReg()) || AArch64::PPRRegClass.contains(CS.getReg())) { assert((Max == std::numeric_limits::min() || Max + 1 == CS.getFrameIdx()) && "SVE CalleeSaves are not consecutive"); Min = std::min(Min, CS.getFrameIdx()); Max = std::max(Max, CS.getFrameIdx()); } } return Min != std::numeric_limits::max(); } // Process all the SVE stack objects and determine offsets for each // object. If AssignOffsets is true, the offsets get assigned. // Fills in the first and last callee-saved frame indices into // Min/MaxCSFrameIndex, respectively. // Returns the size of the stack. static int64_t determineSVEStackObjectOffsets(MachineFrameInfo &MFI, int &MinCSFrameIndex, int &MaxCSFrameIndex, bool AssignOffsets) { // First process all fixed stack objects. int64_t Offset = 0; for (int I = MFI.getObjectIndexBegin(); I != 0; ++I) if (MFI.getStackID(I) == TargetStackID::SVEVector) { int64_t FixedOffset = -MFI.getObjectOffset(I); if (FixedOffset > Offset) Offset = FixedOffset; } auto Assign = [&MFI](int FI, int64_t Offset) { LLVM_DEBUG(dbgs() << "alloc FI(" << FI << ") at SP[" << Offset << "]\n"); MFI.setObjectOffset(FI, Offset); }; // Then process all callee saved slots. if (getSVECalleeSaveSlotRange(MFI, MinCSFrameIndex, MaxCSFrameIndex)) { // Make sure to align the last callee save slot. MFI.setObjectAlignment(MaxCSFrameIndex, 16U); // Assign offsets to the callee save slots. for (int I = MinCSFrameIndex; I <= MaxCSFrameIndex; ++I) { Offset += MFI.getObjectSize(I); Offset = alignTo(Offset, MFI.getObjectAlignment(I)); if (AssignOffsets) Assign(I, -Offset); } } // Create a buffer of SVE objects to allocate and sort it. SmallVector ObjectsToAllocate; for (int I = 0, E = MFI.getObjectIndexEnd(); I != E; ++I) { unsigned StackID = MFI.getStackID(I); if (StackID != TargetStackID::SVEVector) continue; if (MaxCSFrameIndex >= I && I >= MinCSFrameIndex) continue; if (MFI.isDeadObjectIndex(I)) continue; ObjectsToAllocate.push_back(I); } // Allocate all SVE locals and spills for (unsigned FI : ObjectsToAllocate) { unsigned Align = MFI.getObjectAlignment(FI); // FIXME: Given that the length of SVE vectors is not necessarily a power of // two, we'd need to align every object dynamically at runtime if the // alignment is larger than 16. This is not yet supported. if (Align > 16) report_fatal_error( "Alignment of scalable vectors > 16 bytes is not yet supported"); Offset = alignTo(Offset + MFI.getObjectSize(FI), Align); if (AssignOffsets) Assign(FI, -Offset); } return Offset; } int64_t AArch64FrameLowering::estimateSVEStackObjectOffsets( MachineFrameInfo &MFI) const { int MinCSFrameIndex, MaxCSFrameIndex; return determineSVEStackObjectOffsets(MFI, MinCSFrameIndex, MaxCSFrameIndex, false); } int64_t AArch64FrameLowering::assignSVEStackObjectOffsets( MachineFrameInfo &MFI, int &MinCSFrameIndex, int &MaxCSFrameIndex) const { return determineSVEStackObjectOffsets(MFI, MinCSFrameIndex, MaxCSFrameIndex, true); } void AArch64FrameLowering::processFunctionBeforeFrameFinalized( MachineFunction &MF, RegScavenger *RS) const { MachineFrameInfo &MFI = MF.getFrameInfo(); assert(getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown && "Upwards growing stack unsupported"); int MinCSFrameIndex, MaxCSFrameIndex; int64_t SVEStackSize = assignSVEStackObjectOffsets(MFI, MinCSFrameIndex, MaxCSFrameIndex); AArch64FunctionInfo *AFI = MF.getInfo(); AFI->setStackSizeSVE(alignTo(SVEStackSize, 16U)); AFI->setMinMaxSVECSFrameIndex(MinCSFrameIndex, MaxCSFrameIndex); // If this function isn't doing Win64-style C++ EH, we don't need to do // anything. if (!MF.hasEHFunclets()) return; const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); WinEHFuncInfo &EHInfo = *MF.getWinEHFuncInfo(); MachineBasicBlock &MBB = MF.front(); auto MBBI = MBB.begin(); while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup)) ++MBBI; // Create an UnwindHelp object. - int UnwindHelpFI = - MFI.CreateStackObject(/*size*/8, /*alignment*/16, false); + // The UnwindHelp object is allocated at the start of the fixed object area + int64_t FixedObject = + getFixedObjectSize(MF, AFI, /*IsWin64*/ true, /*IsFunclet*/ false); + int UnwindHelpFI = MFI.CreateFixedObject(/*Size*/ 8, + /*SPOffset*/ -FixedObject, + /*IsImmutable=*/false); EHInfo.UnwindHelpFrameIdx = UnwindHelpFI; + // We need to store -2 into the UnwindHelp object at the start of the // function. DebugLoc DL; RS->enterBasicBlockEnd(MBB); RS->backward(std::prev(MBBI)); unsigned DstReg = RS->FindUnusedReg(&AArch64::GPR64commonRegClass); assert(DstReg && "There must be a free register after frame setup"); BuildMI(MBB, MBBI, DL, TII.get(AArch64::MOVi64imm), DstReg).addImm(-2); BuildMI(MBB, MBBI, DL, TII.get(AArch64::STURXi)) .addReg(DstReg, getKillRegState(true)) .addFrameIndex(UnwindHelpFI) .addImm(0); } /// For Win64 AArch64 EH, the offset to the Unwind object is from the SP before /// the update. This is easily retrieved as it is exactly the offset that is set /// in processFunctionBeforeFrameFinalized. int AArch64FrameLowering::getFrameIndexReferencePreferSP( const MachineFunction &MF, int FI, unsigned &FrameReg, bool IgnoreSPUpdates) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); - LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is " - << MFI.getObjectOffset(FI) << "\n"); - FrameReg = AArch64::SP; - return MFI.getObjectOffset(FI); + if (IgnoreSPUpdates) { + LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is " + << MFI.getObjectOffset(FI) << "\n"); + FrameReg = AArch64::SP; + return MFI.getObjectOffset(FI); + } + + return getFrameIndexReference(MF, FI, FrameReg); } /// The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve /// the parent's frame pointer unsigned AArch64FrameLowering::getWinEHParentFrameOffset( const MachineFunction &MF) const { return 0; } /// Funclets only need to account for space for the callee saved registers, /// as the locals are accounted for in the parent's stack frame. unsigned AArch64FrameLowering::getWinEHFuncletFrameSize( const MachineFunction &MF) const { // This is the size of the pushed CSRs. unsigned CSSize = MF.getInfo()->getCalleeSavedStackSize(); // This is the amount of stack a funclet needs to allocate. return alignTo(CSSize + MF.getFrameInfo().getMaxCallFrameSize(), getStackAlignment()); } Index: head/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- head/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (revision 362718) +++ head/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (revision 362719) @@ -1,1811 +1,1814 @@ //===-- PPCAsmPrinter.cpp - Print machine instrs to PowerPC assembly ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains a printer that converts from our internal representation // of machine-dependent LLVM code to PowerPC assembly language. This printer is // the output mechanism used by `llc'. // // Documentation at http://developer.apple.com/documentation/DeveloperTools/ // Reference/Assembler/ASMIntroduction/chapter_1_section_1.html // //===----------------------------------------------------------------------===// #include "MCTargetDesc/PPCInstPrinter.h" #include "MCTargetDesc/PPCMCExpr.h" #include "MCTargetDesc/PPCMCTargetDesc.h" #include "MCTargetDesc/PPCPredicates.h" #include "PPC.h" #include "PPCInstrInfo.h" #include "PPCMachineFunctionInfo.h" #include "PPCSubtarget.h" #include "PPCTargetMachine.h" #include "PPCTargetStreamer.h" #include "TargetInfo/PowerPCTargetInfo.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/StackMaps.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/MCSymbolXCOFF.h" #include "llvm/MC/SectionKind.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include #include #include #include #include using namespace llvm; #define DEBUG_TYPE "asmprinter" namespace { class PPCAsmPrinter : public AsmPrinter { protected: MapVector TOC; const PPCSubtarget *Subtarget = nullptr; StackMaps SM; virtual MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO); public: explicit PPCAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) : AsmPrinter(TM, std::move(Streamer)), SM(*this) {} StringRef getPassName() const override { return "PowerPC Assembly Printer"; } MCSymbol *lookUpOrCreateTOCEntry(const MCSymbol *Sym); bool doInitialization(Module &M) override { if (!TOC.empty()) TOC.clear(); return AsmPrinter::doInitialization(M); } void EmitInstruction(const MachineInstr *MI) override; /// This function is for PrintAsmOperand and PrintAsmMemoryOperand, /// invoked by EmitMSInlineAsmStr and EmitGCCInlineAsmStr only. /// The \p MI would be INLINEASM ONLY. void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) override; bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) override; void EmitEndOfAsmFile(Module &M) override; void LowerSTACKMAP(StackMaps &SM, const MachineInstr &MI); void LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI); void EmitTlsCall(const MachineInstr *MI, MCSymbolRefExpr::VariantKind VK); bool runOnMachineFunction(MachineFunction &MF) override { Subtarget = &MF.getSubtarget(); bool Changed = AsmPrinter::runOnMachineFunction(MF); emitXRayTable(); return Changed; } }; /// PPCLinuxAsmPrinter - PowerPC assembly printer, customized for Linux class PPCLinuxAsmPrinter : public PPCAsmPrinter { public: explicit PPCLinuxAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) : PPCAsmPrinter(TM, std::move(Streamer)) {} StringRef getPassName() const override { return "Linux PPC Assembly Printer"; } bool doFinalization(Module &M) override; void EmitStartOfAsmFile(Module &M) override; void EmitFunctionEntryLabel() override; void EmitFunctionBodyStart() override; void EmitFunctionBodyEnd() override; void EmitInstruction(const MachineInstr *MI) override; }; class PPCAIXAsmPrinter : public PPCAsmPrinter { private: static void ValidateGV(const GlobalVariable *GV); protected: MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO) override; public: PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer) : PPCAsmPrinter(TM, std::move(Streamer)) {} StringRef getPassName() const override { return "AIX PPC Assembly Printer"; } void SetupMachineFunction(MachineFunction &MF) override; const MCExpr *lowerConstant(const Constant *CV) override; void EmitGlobalVariable(const GlobalVariable *GV) override; void EmitFunctionDescriptor() override; void EmitEndOfAsmFile(Module &) override; }; } // end anonymous namespace void PPCAsmPrinter::PrintSymbolOperand(const MachineOperand &MO, raw_ostream &O) { // Computing the address of a global symbol, not calling it. const GlobalValue *GV = MO.getGlobal(); MCSymbol *SymToPrint; // External or weakly linked global variables need non-lazily-resolved stubs if (Subtarget->hasLazyResolverStub(GV)) { SymToPrint = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); MachineModuleInfoImpl::StubValueTy &StubSym = MMI->getObjFileInfo().getGVStubEntry( SymToPrint); if (!StubSym.getPointer()) StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV), !GV->hasInternalLinkage()); } else { SymToPrint = getSymbol(GV); } SymToPrint->print(O, MAI); printOffset(MO.getOffset(), O); } void PPCAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) { const DataLayout &DL = getDataLayout(); const MachineOperand &MO = MI->getOperand(OpNo); switch (MO.getType()) { case MachineOperand::MO_Register: { // The MI is INLINEASM ONLY and UseVSXReg is always false. const char *RegName = PPCInstPrinter::getRegisterName(MO.getReg()); // Linux assembler (Others?) does not take register mnemonics. // FIXME - What about special registers used in mfspr/mtspr? if (!Subtarget->isDarwin()) RegName = PPCRegisterInfo::stripRegisterPrefix(RegName); O << RegName; return; } case MachineOperand::MO_Immediate: O << MO.getImm(); return; case MachineOperand::MO_MachineBasicBlock: MO.getMBB()->getSymbol()->print(O, MAI); return; case MachineOperand::MO_ConstantPoolIndex: O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' << MO.getIndex(); return; case MachineOperand::MO_BlockAddress: GetBlockAddressSymbol(MO.getBlockAddress())->print(O, MAI); return; case MachineOperand::MO_GlobalAddress: { PrintSymbolOperand(MO, O); return; } default: O << ""; return; } } /// PrintAsmOperand - Print out an operand for an inline asm expression. /// bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 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. switch (ExtraCode[0]) { default: // See if this is a generic print operand return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O); case 'L': // Write second word of DImode reference. // Verify that this operand has two consecutive registers. if (!MI->getOperand(OpNo).isReg() || OpNo+1 == MI->getNumOperands() || !MI->getOperand(OpNo+1).isReg()) return true; ++OpNo; // Return the high-part. break; case 'I': // Write 'i' if an integer constant, otherwise nothing. Used to print // addi vs add, etc. if (MI->getOperand(OpNo).isImm()) O << "i"; return false; case 'x': if(!MI->getOperand(OpNo).isReg()) return true; // This operand uses VSX numbering. // If the operand is a VMX register, convert it to a VSX register. Register Reg = MI->getOperand(OpNo).getReg(); if (PPCInstrInfo::isVRRegister(Reg)) Reg = PPC::VSX32 + (Reg - PPC::V0); else if (PPCInstrInfo::isVFRegister(Reg)) Reg = PPC::VSX32 + (Reg - PPC::VF0); const char *RegName; RegName = PPCInstPrinter::getRegisterName(Reg); RegName = PPCRegisterInfo::stripRegisterPrefix(RegName); O << RegName; return false; } } printOperand(MI, OpNo, O); return false; } // At the moment, all inline asm memory operands are a single register. // In any case, the output of this routine should always be just one // assembler operand. bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &O) { if (ExtraCode && ExtraCode[0]) { if (ExtraCode[1] != 0) return true; // Unknown modifier. switch (ExtraCode[0]) { default: return true; // Unknown modifier. + case 'L': // A memory reference to the upper word of a double word op. + O << getDataLayout().getPointerSize() << "("; + printOperand(MI, OpNo, O); + O << ")"; + return false; case 'y': // A memory reference for an X-form instruction { const char *RegName = "r0"; if (!Subtarget->isDarwin()) RegName = PPCRegisterInfo::stripRegisterPrefix(RegName); O << RegName << ", "; printOperand(MI, OpNo, O); return false; } case 'U': // Print 'u' for update form. case 'X': // Print 'x' for indexed form. - { // FIXME: Currently for PowerPC memory operands are always loaded // into a register, so we never get an update or indexed form. // This is bad even for offset forms, since even if we know we // have a value in -16(r1), we will generate a load into r // and then load from 0(r). Until that issue is fixed, // tolerate 'U' and 'X' but don't output anything. assert(MI->getOperand(OpNo).isReg()); return false; - } } } assert(MI->getOperand(OpNo).isReg()); O << "0("; printOperand(MI, OpNo, O); O << ")"; return false; } /// lookUpOrCreateTOCEntry -- Given a symbol, look up whether a TOC entry /// exists for it. If not, create one. Then return a symbol that references /// the TOC entry. MCSymbol *PPCAsmPrinter::lookUpOrCreateTOCEntry(const MCSymbol *Sym) { MCSymbol *&TOCEntry = TOC[Sym]; if (!TOCEntry) TOCEntry = createTempSymbol("C"); return TOCEntry; } void PPCAsmPrinter::EmitEndOfAsmFile(Module &M) { emitStackMaps(SM); } void PPCAsmPrinter::LowerSTACKMAP(StackMaps &SM, const MachineInstr &MI) { unsigned NumNOPBytes = MI.getOperand(1).getImm(); auto &Ctx = OutStreamer->getContext(); MCSymbol *MILabel = Ctx.createTempSymbol(); OutStreamer->EmitLabel(MILabel); SM.recordStackMap(*MILabel, MI); assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!"); // Scan ahead to trim the shadow. const MachineBasicBlock &MBB = *MI.getParent(); MachineBasicBlock::const_iterator MII(MI); ++MII; while (NumNOPBytes > 0) { if (MII == MBB.end() || MII->isCall() || MII->getOpcode() == PPC::DBG_VALUE || MII->getOpcode() == TargetOpcode::PATCHPOINT || MII->getOpcode() == TargetOpcode::STACKMAP) break; ++MII; NumNOPBytes -= 4; } // Emit nops. for (unsigned i = 0; i < NumNOPBytes; i += 4) EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::NOP)); } // Lower a patchpoint of the form: // [], , , , void PPCAsmPrinter::LowerPATCHPOINT(StackMaps &SM, const MachineInstr &MI) { auto &Ctx = OutStreamer->getContext(); MCSymbol *MILabel = Ctx.createTempSymbol(); OutStreamer->EmitLabel(MILabel); SM.recordPatchPoint(*MILabel, MI); PatchPointOpers Opers(&MI); unsigned EncodedBytes = 0; const MachineOperand &CalleeMO = Opers.getCallTarget(); if (CalleeMO.isImm()) { int64_t CallTarget = CalleeMO.getImm(); if (CallTarget) { assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget && "High 16 bits of call target should be zero."); Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg(); EncodedBytes = 0; // Materialize the jump address: EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LI8) .addReg(ScratchReg) .addImm((CallTarget >> 32) & 0xFFFF)); ++EncodedBytes; EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::RLDIC) .addReg(ScratchReg) .addReg(ScratchReg) .addImm(32).addImm(16)); ++EncodedBytes; EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ORIS8) .addReg(ScratchReg) .addReg(ScratchReg) .addImm((CallTarget >> 16) & 0xFFFF)); ++EncodedBytes; EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ORI8) .addReg(ScratchReg) .addReg(ScratchReg) .addImm(CallTarget & 0xFFFF)); // Save the current TOC pointer before the remote call. int TOCSaveOffset = Subtarget->getFrameLowering()->getTOCSaveOffset(); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::STD) .addReg(PPC::X2) .addImm(TOCSaveOffset) .addReg(PPC::X1)); ++EncodedBytes; // If we're on ELFv1, then we need to load the actual function pointer // from the function descriptor. if (!Subtarget->isELFv2ABI()) { // Load the new TOC pointer and the function address, but not r11 // (needing this is rare, and loading it here would prevent passing it // via a 'nest' parameter. EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LD) .addReg(PPC::X2) .addImm(8) .addReg(ScratchReg)); ++EncodedBytes; EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LD) .addReg(ScratchReg) .addImm(0) .addReg(ScratchReg)); ++EncodedBytes; } EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTCTR8) .addReg(ScratchReg)); ++EncodedBytes; EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BCTRL8)); ++EncodedBytes; // Restore the TOC pointer after the call. EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LD) .addReg(PPC::X2) .addImm(TOCSaveOffset) .addReg(PPC::X1)); ++EncodedBytes; } } else if (CalleeMO.isGlobal()) { const GlobalValue *GValue = CalleeMO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymVar = MCSymbolRefExpr::create(MOSymbol, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL8_NOP) .addExpr(SymVar)); EncodedBytes += 2; } // Each instruction is 4 bytes. EncodedBytes *= 4; // Emit padding. unsigned NumBytes = Opers.getNumPatchBytes(); assert(NumBytes >= EncodedBytes && "Patchpoint can't request size less than the length of a call."); assert((NumBytes - EncodedBytes) % 4 == 0 && "Invalid number of NOP bytes requested!"); for (unsigned i = EncodedBytes; i < NumBytes; i += 4) EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::NOP)); } /// EmitTlsCall -- Given a GETtls[ld]ADDR[32] instruction, print a /// call to __tls_get_addr to the current output stream. void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI, MCSymbolRefExpr::VariantKind VK) { StringRef Name = "__tls_get_addr"; MCSymbol *TlsGetAddr = OutContext.getOrCreateSymbol(Name); MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; const Module *M = MF->getFunction().getParent(); assert(MI->getOperand(0).isReg() && ((Subtarget->isPPC64() && MI->getOperand(0).getReg() == PPC::X3) || (!Subtarget->isPPC64() && MI->getOperand(0).getReg() == PPC::R3)) && "GETtls[ld]ADDR[32] must define GPR3"); assert(MI->getOperand(1).isReg() && ((Subtarget->isPPC64() && MI->getOperand(1).getReg() == PPC::X3) || (!Subtarget->isPPC64() && MI->getOperand(1).getReg() == PPC::R3)) && "GETtls[ld]ADDR[32] must read GPR3"); if (Subtarget->is32BitELFABI() && isPositionIndependent()) Kind = MCSymbolRefExpr::VK_PLT; const MCExpr *TlsRef = MCSymbolRefExpr::create(TlsGetAddr, Kind, OutContext); // Add 32768 offset to the symbol so we follow up the latest GOT/PLT ABI. if (Kind == MCSymbolRefExpr::VK_PLT && Subtarget->isSecurePlt() && M->getPICLevel() == PICLevel::BigPIC) TlsRef = MCBinaryExpr::createAdd( TlsRef, MCConstantExpr::create(32768, OutContext), OutContext); const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymVar = MCSymbolRefExpr::create(MOSymbol, VK, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(Subtarget->isPPC64() ? PPC::BL8_NOP_TLS : PPC::BL_TLS) .addExpr(TlsRef) .addExpr(SymVar)); } /// Map a machine operand for a TOC pseudo-machine instruction to its /// corresponding MCSymbol. MCSymbol *PPCAsmPrinter::getMCSymbolForTOCPseudoMO(const MachineOperand &MO) { switch (MO.getType()) { case MachineOperand::MO_GlobalAddress: return getSymbol(MO.getGlobal()); case MachineOperand::MO_ConstantPoolIndex: return GetCPISymbol(MO.getIndex()); case MachineOperand::MO_JumpTableIndex: return GetJTISymbol(MO.getIndex()); case MachineOperand::MO_BlockAddress: return GetBlockAddressSymbol(MO.getBlockAddress()); default: llvm_unreachable("Unexpected operand type to get symbol."); } } /// EmitInstruction -- Print out a single PowerPC MI in Darwin syntax to /// the current output stream. /// void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) { MCInst TmpInst; const bool IsDarwin = TM.getTargetTriple().isOSDarwin(); const bool IsPPC64 = Subtarget->isPPC64(); const bool IsAIX = Subtarget->isAIXABI(); const Module *M = MF->getFunction().getParent(); PICLevel::Level PL = M->getPICLevel(); #ifndef NDEBUG // Validate that SPE and FPU are mutually exclusive in codegen if (!MI->isInlineAsm()) { for (const MachineOperand &MO: MI->operands()) { if (MO.isReg()) { Register Reg = MO.getReg(); if (Subtarget->hasSPE()) { if (PPC::F4RCRegClass.contains(Reg) || PPC::F8RCRegClass.contains(Reg) || PPC::QBRCRegClass.contains(Reg) || PPC::QFRCRegClass.contains(Reg) || PPC::QSRCRegClass.contains(Reg) || PPC::VFRCRegClass.contains(Reg) || PPC::VRRCRegClass.contains(Reg) || PPC::VSFRCRegClass.contains(Reg) || PPC::VSSRCRegClass.contains(Reg) ) llvm_unreachable("SPE targets cannot have FPRegs!"); } else { if (PPC::SPERCRegClass.contains(Reg)) llvm_unreachable("SPE register found in FPU-targeted code!"); } } } } #endif // Lower multi-instruction pseudo operations. switch (MI->getOpcode()) { default: break; case TargetOpcode::DBG_VALUE: llvm_unreachable("Should be handled target independently"); case TargetOpcode::STACKMAP: return LowerSTACKMAP(SM, *MI); case TargetOpcode::PATCHPOINT: return LowerPATCHPOINT(SM, *MI); case PPC::MoveGOTtoLR: { // Transform %lr = MoveGOTtoLR // Into this: bl _GLOBAL_OFFSET_TABLE_@local-4 // _GLOBAL_OFFSET_TABLE_@local-4 (instruction preceding // _GLOBAL_OFFSET_TABLE_) has exactly one instruction: // blrl // This will return the pointer to _GLOBAL_OFFSET_TABLE_@local MCSymbol *GOTSymbol = OutContext.getOrCreateSymbol(StringRef("_GLOBAL_OFFSET_TABLE_")); const MCExpr *OffsExpr = MCBinaryExpr::createSub(MCSymbolRefExpr::create(GOTSymbol, MCSymbolRefExpr::VK_PPC_LOCAL, OutContext), MCConstantExpr::create(4, OutContext), OutContext); // Emit the 'bl'. EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL).addExpr(OffsExpr)); return; } case PPC::MovePCtoLR: case PPC::MovePCtoLR8: { // Transform %lr = MovePCtoLR // Into this, where the label is the PIC base: // bl L1$pb // L1$pb: MCSymbol *PICBase = MF->getPICBaseSymbol(); // Emit the 'bl'. EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL) // FIXME: We would like an efficient form for this, so we // don't have to do a lot of extra uniquing. .addExpr(MCSymbolRefExpr::create(PICBase, OutContext))); // Emit the label. OutStreamer->EmitLabel(PICBase); return; } case PPC::UpdateGBR: { // Transform %rd = UpdateGBR(%rt, %ri) // Into: lwz %rt, .L0$poff - .L0$pb(%ri) // add %rd, %rt, %ri // or into (if secure plt mode is on): // addis r30, r30, {.LTOC,_GLOBAL_OFFSET_TABLE} - .L0$pb@ha // addi r30, r30, {.LTOC,_GLOBAL_OFFSET_TABLE} - .L0$pb@l // Get the offset from the GOT Base Register to the GOT LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); if (Subtarget->isSecurePlt() && isPositionIndependent() ) { unsigned PICR = TmpInst.getOperand(0).getReg(); MCSymbol *BaseSymbol = OutContext.getOrCreateSymbol( M->getPICLevel() == PICLevel::SmallPIC ? "_GLOBAL_OFFSET_TABLE_" : ".LTOC"); const MCExpr *PB = MCSymbolRefExpr::create(MF->getPICBaseSymbol(), OutContext); const MCExpr *DeltaExpr = MCBinaryExpr::createSub( MCSymbolRefExpr::create(BaseSymbol, OutContext), PB, OutContext); const MCExpr *DeltaHi = PPCMCExpr::createHa(DeltaExpr, false, OutContext); EmitToStreamer( *OutStreamer, MCInstBuilder(PPC::ADDIS).addReg(PICR).addReg(PICR).addExpr(DeltaHi)); const MCExpr *DeltaLo = PPCMCExpr::createLo(DeltaExpr, false, OutContext); EmitToStreamer( *OutStreamer, MCInstBuilder(PPC::ADDI).addReg(PICR).addReg(PICR).addExpr(DeltaLo)); return; } else { MCSymbol *PICOffset = MF->getInfo()->getPICOffsetSymbol(); TmpInst.setOpcode(PPC::LWZ); const MCExpr *Exp = MCSymbolRefExpr::create(PICOffset, MCSymbolRefExpr::VK_None, OutContext); const MCExpr *PB = MCSymbolRefExpr::create(MF->getPICBaseSymbol(), MCSymbolRefExpr::VK_None, OutContext); const MCOperand TR = TmpInst.getOperand(1); const MCOperand PICR = TmpInst.getOperand(0); // Step 1: lwz %rt, .L$poff - .L$pb(%ri) TmpInst.getOperand(1) = MCOperand::createExpr(MCBinaryExpr::createSub(Exp, PB, OutContext)); TmpInst.getOperand(0) = TR; TmpInst.getOperand(2) = PICR; EmitToStreamer(*OutStreamer, TmpInst); TmpInst.setOpcode(PPC::ADD4); TmpInst.getOperand(0) = PICR; TmpInst.getOperand(1) = TR; TmpInst.getOperand(2) = PICR; EmitToStreamer(*OutStreamer, TmpInst); return; } } case PPC::LWZtoc: { assert(!IsDarwin && "TOC is an ELF/XCOFF construct."); // Transform %rN = LWZtoc @op1, %r2 LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); // Change the opcode to LWZ. TmpInst.setOpcode(PPC::LWZ); const MachineOperand &MO = MI->getOperand(1); assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && "Invalid operand for LWZtoc."); // Map the operand to its corresponding MCSymbol. const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO); // Create a reference to the GOT entry for the symbol. The GOT entry will be // synthesized later. if (PL == PICLevel::SmallPIC && !IsAIX) { const MCExpr *Exp = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_GOT, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } // Otherwise, use the TOC. 'TOCEntry' is a label used to reference the // storage allocated in the TOC which contains the address of // 'MOSymbol'. Said TOC entry will be synthesized later. MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_None, OutContext); // AIX uses the label directly as the lwz displacement operand for // references into the toc section. The displacement value will be generated // relative to the toc-base. if (IsAIX) { assert( TM.getCodeModel() == CodeModel::Small && "This pseudo should only be selected for 32-bit small code model."); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } // Create an explicit subtract expression between the local symbol and // '.LTOC' to manifest the toc-relative offset. const MCExpr *PB = MCSymbolRefExpr::create( OutContext.getOrCreateSymbol(Twine(".LTOC")), OutContext); Exp = MCBinaryExpr::createSub(Exp, PB, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::LDtocJTI: case PPC::LDtocCPT: case PPC::LDtocBA: case PPC::LDtoc: { assert(!IsDarwin && "TOC is an ELF/XCOFF construct"); // Transform %x3 = LDtoc @min1, %x2 LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); // Change the opcode to LD. TmpInst.setOpcode(PPC::LD); const MachineOperand &MO = MI->getOperand(1); assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && "Invalid operand!"); // Map the machine operand to its corresponding MCSymbol, then map the // global address operand to be a reference to the TOC entry we will // synthesize later. MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(getMCSymbolForTOCPseudoMO(MO)); const MCSymbolRefExpr::VariantKind VK = IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC; const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, VK, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::ADDIStocHA: { assert((IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large) && "This pseudo should only be selected for 32-bit large code model on" " AIX."); // Transform %rd = ADDIStocHA %rA, @sym(%r2) LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); // Change the opcode to ADDIS. TmpInst.setOpcode(PPC::ADDIS); const MachineOperand &MO = MI->getOperand(2); assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && "Invalid operand for ADDIStocHA."); // Map the machine operand to its corresponding MCSymbol. MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO); // Always use TOC on AIX. Map the global address operand to be a reference // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to // reference the storage allocated in the TOC which contains the address of // 'MOSymbol'. MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_PPC_U, OutContext); TmpInst.getOperand(2) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::LWZtocL: { assert(IsAIX && !IsPPC64 && TM.getCodeModel() == CodeModel::Large && "This pseudo should only be selected for 32-bit large code model on" " AIX."); // Transform %rd = LWZtocL @sym, %rs. LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); // Change the opcode to lwz. TmpInst.setOpcode(PPC::LWZ); const MachineOperand &MO = MI->getOperand(1); assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && "Invalid operand for LWZtocL."); // Map the machine operand to its corresponding MCSymbol. MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO); // Always use TOC on AIX. Map the global address operand to be a reference // to the TOC entry we will synthesize later. 'TOCEntry' is a label used to // reference the storage allocated in the TOC which contains the address of // 'MOSymbol'. MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol); const MCExpr *Exp = MCSymbolRefExpr::create(TOCEntry, MCSymbolRefExpr::VK_PPC_L, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::ADDIStocHA8: { assert(!IsDarwin && "TOC is an ELF/XCOFF construct"); // Transform %xd = ADDIStocHA8 %x2, @sym LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); // Change the opcode to ADDIS8. If the global address is the address of // an external symbol, is a jump table address, is a block address, or is a // constant pool index with large code model enabled, then generate a TOC // entry and reference that. Otherwise, reference the symbol directly. TmpInst.setOpcode(PPC::ADDIS8); const MachineOperand &MO = MI->getOperand(2); assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && "Invalid operand for ADDIStocHA8!"); const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO); const bool GlobalToc = MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal()); if (GlobalToc || MO.isJTI() || MO.isBlockAddress() || (MO.isCPI() && TM.getCodeModel() == CodeModel::Large)) MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); const MCSymbolRefExpr::VariantKind VK = IsAIX ? MCSymbolRefExpr::VK_PPC_U : MCSymbolRefExpr::VK_PPC_TOC_HA; const MCExpr *Exp = MCSymbolRefExpr::create(MOSymbol, VK, OutContext); if (!MO.isJTI() && MO.getOffset()) Exp = MCBinaryExpr::createAdd(Exp, MCConstantExpr::create(MO.getOffset(), OutContext), OutContext); TmpInst.getOperand(2) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::LDtocL: { assert(!IsDarwin && "TOC is an ELF/XCOFF construct"); // Transform %xd = LDtocL @sym, %xs LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); // Change the opcode to LD. If the global address is the address of // an external symbol, is a jump table address, is a block address, or is // a constant pool index with large code model enabled, then generate a // TOC entry and reference that. Otherwise, reference the symbol directly. TmpInst.setOpcode(PPC::LD); const MachineOperand &MO = MI->getOperand(1); assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) && "Invalid operand for LDtocL!"); LLVM_DEBUG(assert( (!MO.isGlobal() || Subtarget->isGVIndirectSymbol(MO.getGlobal())) && "LDtocL used on symbol that could be accessed directly is " "invalid. Must match ADDIStocHA8.")); const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO); if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large) MOSymbol = lookUpOrCreateTOCEntry(MOSymbol); const MCSymbolRefExpr::VariantKind VK = IsAIX ? MCSymbolRefExpr::VK_PPC_L : MCSymbolRefExpr::VK_PPC_TOC_LO; const MCExpr *Exp = MCSymbolRefExpr::create(MOSymbol, VK, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::ADDItocL: { // Transform %xd = ADDItocL %xs, @sym LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); // Change the opcode to ADDI8. If the global address is external, then // generate a TOC entry and reference that. Otherwise, reference the // symbol directly. TmpInst.setOpcode(PPC::ADDI8); const MachineOperand &MO = MI->getOperand(2); assert((MO.isGlobal() || MO.isCPI()) && "Invalid operand for ADDItocL."); LLVM_DEBUG(assert( !(MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal())) && "Interposable definitions must use indirect access.")); const MCExpr *Exp = MCSymbolRefExpr::create(getMCSymbolForTOCPseudoMO(MO), MCSymbolRefExpr::VK_PPC_TOC_LO, OutContext); TmpInst.getOperand(2) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::ADDISgotTprelHA: { // Transform: %xd = ADDISgotTprelHA %x2, @sym // Into: %xd = ADDIS8 %x2, sym@got@tlsgd@ha assert(IsPPC64 && "Not supported for 32-bit PowerPC"); const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymGotTprel = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()) .addExpr(SymGotTprel)); return; } case PPC::LDgotTprelL: case PPC::LDgotTprelL32: { // Transform %xd = LDgotTprelL @sym, %xs LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); // Change the opcode to LD. TmpInst.setOpcode(IsPPC64 ? PPC::LD : PPC::LWZ); const MachineOperand &MO = MI->getOperand(1); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *Exp = MCSymbolRefExpr::create( MOSymbol, IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO : MCSymbolRefExpr::VK_PPC_GOT_TPREL, OutContext); TmpInst.getOperand(1) = MCOperand::createExpr(Exp); EmitToStreamer(*OutStreamer, TmpInst); return; } case PPC::PPC32PICGOT: { MCSymbol *GOTSymbol = OutContext.getOrCreateSymbol(StringRef("_GLOBAL_OFFSET_TABLE_")); MCSymbol *GOTRef = OutContext.createTempSymbol(); MCSymbol *NextInstr = OutContext.createTempSymbol(); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL) // FIXME: We would like an efficient form for this, so we don't have to do // a lot of extra uniquing. .addExpr(MCSymbolRefExpr::create(NextInstr, OutContext))); const MCExpr *OffsExpr = MCBinaryExpr::createSub(MCSymbolRefExpr::create(GOTSymbol, OutContext), MCSymbolRefExpr::create(GOTRef, OutContext), OutContext); OutStreamer->EmitLabel(GOTRef); OutStreamer->EmitValue(OffsExpr, 4); OutStreamer->EmitLabel(NextInstr); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR) .addReg(MI->getOperand(0).getReg())); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LWZ) .addReg(MI->getOperand(1).getReg()) .addImm(0) .addReg(MI->getOperand(0).getReg())); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADD4) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()) .addReg(MI->getOperand(0).getReg())); return; } case PPC::PPC32GOT: { MCSymbol *GOTSymbol = OutContext.getOrCreateSymbol(StringRef("_GLOBAL_OFFSET_TABLE_")); const MCExpr *SymGotTlsL = MCSymbolRefExpr::create( GOTSymbol, MCSymbolRefExpr::VK_PPC_LO, OutContext); const MCExpr *SymGotTlsHA = MCSymbolRefExpr::create( GOTSymbol, MCSymbolRefExpr::VK_PPC_HA, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LI) .addReg(MI->getOperand(0).getReg()) .addExpr(SymGotTlsL)); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(0).getReg()) .addExpr(SymGotTlsHA)); return; } case PPC::ADDIStlsgdHA: { // Transform: %xd = ADDIStlsgdHA %x2, @sym // Into: %xd = ADDIS8 %x2, sym@got@tlsgd@ha assert(IsPPC64 && "Not supported for 32-bit PowerPC"); const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymGotTlsGD = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()) .addExpr(SymGotTlsGD)); return; } case PPC::ADDItlsgdL: // Transform: %xd = ADDItlsgdL %xs, @sym // Into: %xd = ADDI8 %xs, sym@got@tlsgd@l case PPC::ADDItlsgdL32: { // Transform: %rd = ADDItlsgdL32 %rs, @sym // Into: %rd = ADDI %rs, sym@got@tlsgd const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymGotTlsGD = MCSymbolRefExpr::create( MOSymbol, IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO : MCSymbolRefExpr::VK_PPC_GOT_TLSGD, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()) .addExpr(SymGotTlsGD)); return; } case PPC::GETtlsADDR: // Transform: %x3 = GETtlsADDR %x3, @sym // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsgd) case PPC::GETtlsADDR32: { // Transform: %r3 = GETtlsADDR32 %r3, @sym // Into: BL_TLS __tls_get_addr(sym at tlsgd)@PLT EmitTlsCall(MI, MCSymbolRefExpr::VK_PPC_TLSGD); return; } case PPC::ADDIStlsldHA: { // Transform: %xd = ADDIStlsldHA %x2, @sym // Into: %xd = ADDIS8 %x2, sym@got@tlsld@ha assert(IsPPC64 && "Not supported for 32-bit PowerPC"); const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymGotTlsLD = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS8) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()) .addExpr(SymGotTlsLD)); return; } case PPC::ADDItlsldL: // Transform: %xd = ADDItlsldL %xs, @sym // Into: %xd = ADDI8 %xs, sym@got@tlsld@l case PPC::ADDItlsldL32: { // Transform: %rd = ADDItlsldL32 %rs, @sym // Into: %rd = ADDI %rs, sym@got@tlsld const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymGotTlsLD = MCSymbolRefExpr::create( MOSymbol, IsPPC64 ? MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO : MCSymbolRefExpr::VK_PPC_GOT_TLSLD, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()) .addExpr(SymGotTlsLD)); return; } case PPC::GETtlsldADDR: // Transform: %x3 = GETtlsldADDR %x3, @sym // Into: BL8_NOP_TLS __tls_get_addr(sym at tlsld) case PPC::GETtlsldADDR32: { // Transform: %r3 = GETtlsldADDR32 %r3, @sym // Into: BL_TLS __tls_get_addr(sym at tlsld)@PLT EmitTlsCall(MI, MCSymbolRefExpr::VK_PPC_TLSLD); return; } case PPC::ADDISdtprelHA: // Transform: %xd = ADDISdtprelHA %xs, @sym // Into: %xd = ADDIS8 %xs, sym@dtprel@ha case PPC::ADDISdtprelHA32: { // Transform: %rd = ADDISdtprelHA32 %rs, @sym // Into: %rd = ADDIS %rs, sym@dtprel@ha const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymDtprel = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_DTPREL_HA, OutContext); EmitToStreamer( *OutStreamer, MCInstBuilder(IsPPC64 ? PPC::ADDIS8 : PPC::ADDIS) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()) .addExpr(SymDtprel)); return; } case PPC::ADDIdtprelL: // Transform: %xd = ADDIdtprelL %xs, @sym // Into: %xd = ADDI8 %xs, sym@dtprel@l case PPC::ADDIdtprelL32: { // Transform: %rd = ADDIdtprelL32 %rs, @sym // Into: %rd = ADDI %rs, sym@dtprel@l const MachineOperand &MO = MI->getOperand(2); const GlobalValue *GValue = MO.getGlobal(); MCSymbol *MOSymbol = getSymbol(GValue); const MCExpr *SymDtprel = MCSymbolRefExpr::create(MOSymbol, MCSymbolRefExpr::VK_PPC_DTPREL_LO, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(IsPPC64 ? PPC::ADDI8 : PPC::ADDI) .addReg(MI->getOperand(0).getReg()) .addReg(MI->getOperand(1).getReg()) .addExpr(SymDtprel)); return; } case PPC::MFOCRF: case PPC::MFOCRF8: if (!Subtarget->hasMFOCRF()) { // Transform: %r3 = MFOCRF %cr7 // Into: %r3 = MFCR ;; cr7 unsigned NewOpcode = MI->getOpcode() == PPC::MFOCRF ? PPC::MFCR : PPC::MFCR8; OutStreamer->AddComment(PPCInstPrinter:: getRegisterName(MI->getOperand(1).getReg())); EmitToStreamer(*OutStreamer, MCInstBuilder(NewOpcode) .addReg(MI->getOperand(0).getReg())); return; } break; case PPC::MTOCRF: case PPC::MTOCRF8: if (!Subtarget->hasMFOCRF()) { // Transform: %cr7 = MTOCRF %r3 // Into: MTCRF mask, %r3 ;; cr7 unsigned NewOpcode = MI->getOpcode() == PPC::MTOCRF ? PPC::MTCRF : PPC::MTCRF8; unsigned Mask = 0x80 >> OutContext.getRegisterInfo() ->getEncodingValue(MI->getOperand(0).getReg()); OutStreamer->AddComment(PPCInstPrinter:: getRegisterName(MI->getOperand(0).getReg())); EmitToStreamer(*OutStreamer, MCInstBuilder(NewOpcode) .addImm(Mask) .addReg(MI->getOperand(1).getReg())); return; } break; case PPC::LD: case PPC::STD: case PPC::LWA_32: case PPC::LWA: { // Verify alignment is legal, so we don't create relocations // that can't be supported. // FIXME: This test is currently disabled for Darwin. The test // suite shows a handful of test cases that fail this check for // Darwin. Those need to be investigated before this sanity test // can be enabled for those subtargets. if (!IsDarwin) { unsigned OpNum = (MI->getOpcode() == PPC::STD) ? 2 : 1; const MachineOperand &MO = MI->getOperand(OpNum); if (MO.isGlobal() && MO.getGlobal()->getAlignment() < 4) llvm_unreachable("Global must be word-aligned for LD, STD, LWA!"); } // Now process the instruction normally. break; } } LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, IsDarwin); EmitToStreamer(*OutStreamer, TmpInst); } void PPCLinuxAsmPrinter::EmitInstruction(const MachineInstr *MI) { if (!Subtarget->isPPC64()) return PPCAsmPrinter::EmitInstruction(MI); switch (MI->getOpcode()) { default: return PPCAsmPrinter::EmitInstruction(MI); case TargetOpcode::PATCHABLE_FUNCTION_ENTER: { // .begin: // b .end # lis 0, FuncId[16..32] // nop # li 0, FuncId[0..15] // std 0, -8(1) // mflr 0 // bl __xray_FunctionEntry // mtlr 0 // .end: // // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number // of instructions change. MCSymbol *BeginOfSled = OutContext.createTempSymbol(); MCSymbol *EndOfSled = OutContext.createTempSymbol(); OutStreamer->EmitLabel(BeginOfSled); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::B).addExpr( MCSymbolRefExpr::create(EndOfSled, OutContext))); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::NOP)); EmitToStreamer( *OutStreamer, MCInstBuilder(PPC::STD).addReg(PPC::X0).addImm(-8).addReg(PPC::X1)); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR8).addReg(PPC::X0)); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL8_NOP) .addExpr(MCSymbolRefExpr::create( OutContext.getOrCreateSymbol("__xray_FunctionEntry"), OutContext))); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTLR8).addReg(PPC::X0)); OutStreamer->EmitLabel(EndOfSled); recordSled(BeginOfSled, *MI, SledKind::FUNCTION_ENTER); break; } case TargetOpcode::PATCHABLE_RET: { unsigned RetOpcode = MI->getOperand(0).getImm(); MCInst RetInst; RetInst.setOpcode(RetOpcode); for (const auto &MO : make_range(std::next(MI->operands_begin()), MI->operands_end())) { MCOperand MCOp; if (LowerPPCMachineOperandToMCOperand(MO, MCOp, *this, false)) RetInst.addOperand(MCOp); } bool IsConditional; if (RetOpcode == PPC::BCCLR) { IsConditional = true; } else if (RetOpcode == PPC::TCRETURNdi8 || RetOpcode == PPC::TCRETURNri8 || RetOpcode == PPC::TCRETURNai8) { break; } else if (RetOpcode == PPC::BLR8 || RetOpcode == PPC::TAILB8) { IsConditional = false; } else { EmitToStreamer(*OutStreamer, RetInst); break; } MCSymbol *FallthroughLabel; if (IsConditional) { // Before: // bgtlr cr0 // // After: // ble cr0, .end // .p2align 3 // .begin: // blr # lis 0, FuncId[16..32] // nop # li 0, FuncId[0..15] // std 0, -8(1) // mflr 0 // bl __xray_FunctionExit // mtlr 0 // blr // .end: // // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number // of instructions change. FallthroughLabel = OutContext.createTempSymbol(); EmitToStreamer( *OutStreamer, MCInstBuilder(PPC::BCC) .addImm(PPC::InvertPredicate( static_cast(MI->getOperand(1).getImm()))) .addReg(MI->getOperand(2).getReg()) .addExpr(MCSymbolRefExpr::create(FallthroughLabel, OutContext))); RetInst = MCInst(); RetInst.setOpcode(PPC::BLR8); } // .p2align 3 // .begin: // b(lr)? # lis 0, FuncId[16..32] // nop # li 0, FuncId[0..15] // std 0, -8(1) // mflr 0 // bl __xray_FunctionExit // mtlr 0 // b(lr)? // // Update compiler-rt/lib/xray/xray_powerpc64.cc accordingly when number // of instructions change. OutStreamer->EmitCodeAlignment(8); MCSymbol *BeginOfSled = OutContext.createTempSymbol(); OutStreamer->EmitLabel(BeginOfSled); EmitToStreamer(*OutStreamer, RetInst); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::NOP)); EmitToStreamer( *OutStreamer, MCInstBuilder(PPC::STD).addReg(PPC::X0).addImm(-8).addReg(PPC::X1)); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MFLR8).addReg(PPC::X0)); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::BL8_NOP) .addExpr(MCSymbolRefExpr::create( OutContext.getOrCreateSymbol("__xray_FunctionExit"), OutContext))); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::MTLR8).addReg(PPC::X0)); EmitToStreamer(*OutStreamer, RetInst); if (IsConditional) OutStreamer->EmitLabel(FallthroughLabel); recordSled(BeginOfSled, *MI, SledKind::FUNCTION_EXIT); break; } case TargetOpcode::PATCHABLE_FUNCTION_EXIT: llvm_unreachable("PATCHABLE_FUNCTION_EXIT should never be emitted"); case TargetOpcode::PATCHABLE_TAIL_CALL: // TODO: Define a trampoline `__xray_FunctionTailExit` and differentiate a // normal function exit from a tail exit. llvm_unreachable("Tail call is handled in the normal case. See comments " "around this assert."); } } void PPCLinuxAsmPrinter::EmitStartOfAsmFile(Module &M) { if (static_cast(TM).isELFv2ABI()) { PPCTargetStreamer *TS = static_cast(OutStreamer->getTargetStreamer()); if (TS) TS->emitAbiVersion(2); } if (static_cast(TM).isPPC64() || !isPositionIndependent()) return AsmPrinter::EmitStartOfAsmFile(M); if (M.getPICLevel() == PICLevel::SmallPIC) return AsmPrinter::EmitStartOfAsmFile(M); OutStreamer->SwitchSection(OutContext.getELFSection( ".got2", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC)); MCSymbol *TOCSym = OutContext.getOrCreateSymbol(Twine(".LTOC")); MCSymbol *CurrentPos = OutContext.createTempSymbol(); OutStreamer->EmitLabel(CurrentPos); // The GOT pointer points to the middle of the GOT, in order to reference the // entire 64kB range. 0x8000 is the midpoint. const MCExpr *tocExpr = MCBinaryExpr::createAdd(MCSymbolRefExpr::create(CurrentPos, OutContext), MCConstantExpr::create(0x8000, OutContext), OutContext); OutStreamer->EmitAssignment(TOCSym, tocExpr); OutStreamer->SwitchSection(getObjFileLowering().getTextSection()); } void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() { // linux/ppc32 - Normal entry label. if (!Subtarget->isPPC64() && (!isPositionIndependent() || MF->getFunction().getParent()->getPICLevel() == PICLevel::SmallPIC)) return AsmPrinter::EmitFunctionEntryLabel(); if (!Subtarget->isPPC64()) { const PPCFunctionInfo *PPCFI = MF->getInfo(); if (PPCFI->usesPICBase() && !Subtarget->isSecurePlt()) { MCSymbol *RelocSymbol = PPCFI->getPICOffsetSymbol(); MCSymbol *PICBase = MF->getPICBaseSymbol(); OutStreamer->EmitLabel(RelocSymbol); const MCExpr *OffsExpr = MCBinaryExpr::createSub( MCSymbolRefExpr::create(OutContext.getOrCreateSymbol(Twine(".LTOC")), OutContext), MCSymbolRefExpr::create(PICBase, OutContext), OutContext); OutStreamer->EmitValue(OffsExpr, 4); OutStreamer->EmitLabel(CurrentFnSym); return; } else return AsmPrinter::EmitFunctionEntryLabel(); } // ELFv2 ABI - Normal entry label. if (Subtarget->isELFv2ABI()) { // In the Large code model, we allow arbitrary displacements between // the text section and its associated TOC section. We place the // full 8-byte offset to the TOC in memory immediately preceding // the function global entry point. if (TM.getCodeModel() == CodeModel::Large && !MF->getRegInfo().use_empty(PPC::X2)) { const PPCFunctionInfo *PPCFI = MF->getInfo(); MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(StringRef(".TOC.")); MCSymbol *GlobalEPSymbol = PPCFI->getGlobalEPSymbol(); const MCExpr *TOCDeltaExpr = MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCSymbol, OutContext), MCSymbolRefExpr::create(GlobalEPSymbol, OutContext), OutContext); OutStreamer->EmitLabel(PPCFI->getTOCOffsetSymbol()); OutStreamer->EmitValue(TOCDeltaExpr, 8); } return AsmPrinter::EmitFunctionEntryLabel(); } // Emit an official procedure descriptor. MCSectionSubPair Current = OutStreamer->getCurrentSection(); MCSectionELF *Section = OutStreamer->getContext().getELFSection( ".opd", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); OutStreamer->SwitchSection(Section); OutStreamer->EmitLabel(CurrentFnSym); OutStreamer->EmitValueToAlignment(8); MCSymbol *Symbol1 = CurrentFnSymForSize; // Generates a R_PPC64_ADDR64 (from FK_DATA_8) relocation for the function // entry point. OutStreamer->EmitValue(MCSymbolRefExpr::create(Symbol1, OutContext), 8 /*size*/); MCSymbol *Symbol2 = OutContext.getOrCreateSymbol(StringRef(".TOC.")); // Generates a R_PPC64_TOC relocation for TOC base insertion. OutStreamer->EmitValue( MCSymbolRefExpr::create(Symbol2, MCSymbolRefExpr::VK_PPC_TOCBASE, OutContext), 8/*size*/); // Emit a null environment pointer. OutStreamer->EmitIntValue(0, 8 /* size */); OutStreamer->SwitchSection(Current.first, Current.second); } bool PPCLinuxAsmPrinter::doFinalization(Module &M) { const DataLayout &DL = getDataLayout(); bool isPPC64 = DL.getPointerSizeInBits() == 64; PPCTargetStreamer &TS = static_cast(*OutStreamer->getTargetStreamer()); if (!TOC.empty()) { MCSectionELF *Section; if (isPPC64) Section = OutStreamer->getContext().getELFSection( ".toc", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); else Section = OutStreamer->getContext().getELFSection( ".got2", ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); OutStreamer->SwitchSection(Section); for (const auto &TOCMapPair : TOC) { const MCSymbol *const TOCEntryTarget = TOCMapPair.first; MCSymbol *const TOCEntryLabel = TOCMapPair.second; OutStreamer->EmitLabel(TOCEntryLabel); if (isPPC64) { TS.emitTCEntry(*TOCEntryTarget); } else { OutStreamer->EmitValueToAlignment(4); OutStreamer->EmitSymbolValue(TOCEntryTarget, 4); } } } return AsmPrinter::doFinalization(M); } /// EmitFunctionBodyStart - Emit a global entry point prefix for ELFv2. void PPCLinuxAsmPrinter::EmitFunctionBodyStart() { // In the ELFv2 ABI, in functions that use the TOC register, we need to // provide two entry points. The ABI guarantees that when calling the // local entry point, r2 is set up by the caller to contain the TOC base // for this function, and when calling the global entry point, r12 is set // up by the caller to hold the address of the global entry point. We // thus emit a prefix sequence along the following lines: // // func: // .Lfunc_gepNN: // # global entry point // addis r2,r12,(.TOC.-.Lfunc_gepNN)@ha // addi r2,r2,(.TOC.-.Lfunc_gepNN)@l // .Lfunc_lepNN: // .localentry func, .Lfunc_lepNN-.Lfunc_gepNN // # local entry point, followed by function body // // For the Large code model, we create // // .Lfunc_tocNN: // .quad .TOC.-.Lfunc_gepNN # done by EmitFunctionEntryLabel // func: // .Lfunc_gepNN: // # global entry point // ld r2,.Lfunc_tocNN-.Lfunc_gepNN(r12) // add r2,r2,r12 // .Lfunc_lepNN: // .localentry func, .Lfunc_lepNN-.Lfunc_gepNN // # local entry point, followed by function body // // This ensures we have r2 set up correctly while executing the function // body, no matter which entry point is called. if (Subtarget->isELFv2ABI() // Only do all that if the function uses r2 in the first place. && !MF->getRegInfo().use_empty(PPC::X2)) { // Note: The logic here must be synchronized with the code in the // branch-selection pass which sets the offset of the first block in the // function. This matters because it affects the alignment. const PPCFunctionInfo *PPCFI = MF->getInfo(); MCSymbol *GlobalEntryLabel = PPCFI->getGlobalEPSymbol(); OutStreamer->EmitLabel(GlobalEntryLabel); const MCSymbolRefExpr *GlobalEntryLabelExp = MCSymbolRefExpr::create(GlobalEntryLabel, OutContext); if (TM.getCodeModel() != CodeModel::Large) { MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(StringRef(".TOC.")); const MCExpr *TOCDeltaExpr = MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCSymbol, OutContext), GlobalEntryLabelExp, OutContext); const MCExpr *TOCDeltaHi = PPCMCExpr::createHa(TOCDeltaExpr, false, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS) .addReg(PPC::X2) .addReg(PPC::X12) .addExpr(TOCDeltaHi)); const MCExpr *TOCDeltaLo = PPCMCExpr::createLo(TOCDeltaExpr, false, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDI) .addReg(PPC::X2) .addReg(PPC::X2) .addExpr(TOCDeltaLo)); } else { MCSymbol *TOCOffset = PPCFI->getTOCOffsetSymbol(); const MCExpr *TOCOffsetDeltaExpr = MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCOffset, OutContext), GlobalEntryLabelExp, OutContext); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LD) .addReg(PPC::X2) .addExpr(TOCOffsetDeltaExpr) .addReg(PPC::X12)); EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADD8) .addReg(PPC::X2) .addReg(PPC::X2) .addReg(PPC::X12)); } MCSymbol *LocalEntryLabel = PPCFI->getLocalEPSymbol(); OutStreamer->EmitLabel(LocalEntryLabel); const MCSymbolRefExpr *LocalEntryLabelExp = MCSymbolRefExpr::create(LocalEntryLabel, OutContext); const MCExpr *LocalOffsetExp = MCBinaryExpr::createSub(LocalEntryLabelExp, GlobalEntryLabelExp, OutContext); PPCTargetStreamer *TS = static_cast(OutStreamer->getTargetStreamer()); if (TS) TS->emitLocalEntry(cast(CurrentFnSym), LocalOffsetExp); } } /// EmitFunctionBodyEnd - Print the traceback table before the .size /// directive. /// void PPCLinuxAsmPrinter::EmitFunctionBodyEnd() { // Only the 64-bit target requires a traceback table. For now, // we only emit the word of zeroes that GDB requires to find // the end of the function, and zeroes for the eight-byte // mandatory fields. // FIXME: We should fill in the eight-byte mandatory fields as described in // the PPC64 ELF ABI (this is a low-priority item because GDB does not // currently make use of these fields). if (Subtarget->isPPC64()) { OutStreamer->EmitIntValue(0, 4/*size*/); OutStreamer->EmitIntValue(0, 8/*size*/); } } void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) { // Get the function descriptor symbol. CurrentFnDescSym = getSymbol(&MF.getFunction()); // Set the containing csect. MCSectionXCOFF *FnDescSec = OutStreamer->getContext().getXCOFFSection( CurrentFnDescSym->getName(), XCOFF::XMC_DS, XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData()); cast(CurrentFnDescSym)->setContainingCsect(FnDescSec); return AsmPrinter::SetupMachineFunction(MF); } void PPCAIXAsmPrinter::ValidateGV(const GlobalVariable *GV) { // Early error checking limiting what is supported. if (GV->isThreadLocal()) report_fatal_error("Thread local not yet supported on AIX."); if (GV->hasSection()) report_fatal_error("Custom section for Data not yet supported."); if (GV->hasComdat()) report_fatal_error("COMDAT not yet supported by AIX."); } const MCExpr *PPCAIXAsmPrinter::lowerConstant(const Constant *CV) { if (const Function *F = dyn_cast(CV)) { MCSymbolXCOFF *FSym = cast(getSymbol(F)); if (!FSym->hasContainingCsect()) { const XCOFF::StorageClass SC = F->isDeclaration() ? TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(F) : XCOFF::C_HIDEXT; MCSectionXCOFF *Csect = OutStreamer->getContext().getXCOFFSection( FSym->getName(), XCOFF::XMC_DS, F->isDeclaration() ? XCOFF::XTY_ER : XCOFF::XTY_SD, SC, SectionKind::getData()); FSym->setContainingCsect(Csect); } return MCSymbolRefExpr::create( FSym->getContainingCsect()->getQualNameSymbol(), OutContext); } return PPCAsmPrinter::lowerConstant(CV); } void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { ValidateGV(GV); // External global variables are already handled. if (!GV->hasInitializer()) return; // Create the symbol, set its storage class. MCSymbolXCOFF *GVSym = cast(getSymbol(GV)); GVSym->setStorageClass( TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV)); SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM); if ((!GVKind.isGlobalWriteableData() && !GVKind.isReadOnly()) || GVKind.isMergeable2ByteCString() || GVKind.isMergeable4ByteCString()) report_fatal_error("Encountered a global variable kind that is " "not supported yet."); // Create the containing csect and switch to it. MCSectionXCOFF *Csect = cast( getObjFileLowering().SectionForGlobal(GV, GVKind, TM)); OutStreamer->SwitchSection(Csect); GVSym->setContainingCsect(Csect); const DataLayout &DL = GV->getParent()->getDataLayout(); // Handle common symbols. if (GVKind.isCommon() || GVKind.isBSSLocal()) { unsigned Align = GV->getAlignment() ? GV->getAlignment() : DL.getPreferredAlignment(GV); uint64_t Size = DL.getTypeAllocSize(GV->getType()->getElementType()); if (GVKind.isBSSLocal()) OutStreamer->EmitXCOFFLocalCommonSymbol( GVSym, Size, Csect->getQualNameSymbol(), Align); else OutStreamer->EmitCommonSymbol(Csect->getQualNameSymbol(), Size, Align); return; } MCSymbol *EmittedInitSym = GVSym; EmitLinkage(GV, EmittedInitSym); EmitAlignment(getGVAlignment(GV, DL), GV); OutStreamer->EmitLabel(EmittedInitSym); EmitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer()); } void PPCAIXAsmPrinter::EmitFunctionDescriptor() { const DataLayout &DL = getDataLayout(); const unsigned PointerSize = DL.getPointerSizeInBits() == 64 ? 8 : 4; MCSectionSubPair Current = OutStreamer->getCurrentSection(); // Emit function descriptor. OutStreamer->SwitchSection( cast(CurrentFnDescSym)->getContainingCsect()); OutStreamer->EmitLabel(CurrentFnDescSym); // Emit function entry point address. OutStreamer->EmitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext), PointerSize); // Emit TOC base address. const MCSectionXCOFF *TOCBaseSec = OutStreamer->getContext().getXCOFFSection( StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData()); const MCSymbol *TOCBaseSym = TOCBaseSec->getQualNameSymbol(); OutStreamer->EmitValue(MCSymbolRefExpr::create(TOCBaseSym, OutContext), PointerSize); // Emit a null environment pointer. OutStreamer->EmitIntValue(0, PointerSize); OutStreamer->SwitchSection(Current.first, Current.second); } void PPCAIXAsmPrinter::EmitEndOfAsmFile(Module &M) { // If there are no functions in this module, we will never need to reference // the TOC base. if (M.empty()) return; // Emit TOC base. MCSectionXCOFF *TOCBaseSection = OutStreamer->getContext().getXCOFFSection( StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData()); // The TOC-base always has 0 size, but 4 byte alignment. TOCBaseSection->setAlignment(Align(4)); // Switch to section to emit TOC base. OutStreamer->SwitchSection(TOCBaseSection); PPCTargetStreamer &TS = static_cast(*OutStreamer->getTargetStreamer()); for (auto &I : TOC) { // Setup the csect for the current TC entry. MCSectionXCOFF *TCEntry = OutStreamer->getContext().getXCOFFSection( cast(I.first)->getUnqualifiedName(), XCOFF::XMC_TC, XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData()); cast(I.second)->setContainingCsect(TCEntry); OutStreamer->SwitchSection(TCEntry); OutStreamer->EmitLabel(I.second); TS.emitTCEntry(*I.first); } } MCSymbol * PPCAIXAsmPrinter::getMCSymbolForTOCPseudoMO(const MachineOperand &MO) { const GlobalObject *GO = nullptr; // If the MO is a function or certain kind of globals, we want to make sure to // refer to the csect symbol, otherwise we can just do the default handling. if (MO.getType() != MachineOperand::MO_GlobalAddress || !(GO = dyn_cast(MO.getGlobal()))) return PPCAsmPrinter::getMCSymbolForTOCPseudoMO(MO); // Do an early error check for globals we don't support. This will go away // eventually. const auto *GV = dyn_cast(GO); if (GV) { ValidateGV(GV); } MCSymbolXCOFF *XSym = cast(getSymbol(GO)); // If the global object is a global variable without initializer or is a // declaration of a function, then XSym is an external referenced symbol. // Hence we may need to explictly create a MCSectionXCOFF for it so that we // can return its symbol later. if (GO->isDeclaration()) { if (!XSym->hasContainingCsect()) { // Make sure the storage class is set. const XCOFF::StorageClass SC = TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO); XSym->setStorageClass(SC); MCSectionXCOFF *Csect = OutStreamer->getContext().getXCOFFSection( XSym->getName(), isa(GO) ? XCOFF::XMC_DS : XCOFF::XMC_UA, XCOFF::XTY_ER, SC, SectionKind::getMetadata()); XSym->setContainingCsect(Csect); } return XSym->getContainingCsect()->getQualNameSymbol(); } // Handle initialized global variables and defined functions. SectionKind GOKind = getObjFileLowering().getKindForGlobal(GO, TM); if (GOKind.isText()) { // If the MO is a function, we want to make sure to refer to the function // descriptor csect. return OutStreamer->getContext() .getXCOFFSection(XSym->getName(), XCOFF::XMC_DS, XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData()) ->getQualNameSymbol(); } else if (GOKind.isCommon() || GOKind.isBSSLocal()) { // If the operand is a common then we should refer to the csect symbol. return cast( getObjFileLowering().SectionForGlobal(GO, GOKind, TM)) ->getQualNameSymbol(); } // Other global variables are refered to by labels inside of a single csect, // so refer to the label directly. return getSymbol(GV); } /// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code /// for a MachineFunction to the given output stream, in a format that the /// Darwin assembler can deal with. /// static AsmPrinter * createPPCAsmPrinterPass(TargetMachine &tm, std::unique_ptr &&Streamer) { if (tm.getTargetTriple().isOSAIX()) return new PPCAIXAsmPrinter(tm, std::move(Streamer)); return new PPCLinuxAsmPrinter(tm, std::move(Streamer)); } // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCAsmPrinter() { TargetRegistry::RegisterAsmPrinter(getThePPC32Target(), createPPCAsmPrinterPass); TargetRegistry::RegisterAsmPrinter(getThePPC64Target(), createPPCAsmPrinterPass); TargetRegistry::RegisterAsmPrinter(getThePPC64LETarget(), createPPCAsmPrinterPass); } Index: head/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp =================================================================== --- head/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (revision 362718) +++ head/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp (revision 362719) @@ -1,486 +1,486 @@ //===-- RISCVFrameLowering.cpp - RISCV Frame Information ------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains the RISCV implementation of TargetFrameLowering class. // //===----------------------------------------------------------------------===// #include "RISCVFrameLowering.h" #include "RISCVMachineFunctionInfo.h" #include "RISCVSubtarget.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/MC/MCDwarf.h" using namespace llvm; bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const { const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); const MachineFrameInfo &MFI = MF.getFrameInfo(); return MF.getTarget().Options.DisableFramePointerElim(MF) || RegInfo->needsStackRealignment(MF) || MFI.hasVarSizedObjects() || MFI.isFrameAddressTaken(); } bool RISCVFrameLowering::hasBP(const MachineFunction &MF) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetRegisterInfo *TRI = STI.getRegisterInfo(); return MFI.hasVarSizedObjects() && TRI->needsStackRealignment(MF); } // Determines the size of the frame and maximum call frame size. void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const { MachineFrameInfo &MFI = MF.getFrameInfo(); const RISCVRegisterInfo *RI = STI.getRegisterInfo(); // Get the number of bytes to allocate from the FrameInfo. uint64_t FrameSize = MFI.getStackSize(); // Get the alignment. unsigned StackAlign = getStackAlignment(); if (RI->needsStackRealignment(MF)) { unsigned MaxStackAlign = std::max(StackAlign, MFI.getMaxAlignment()); FrameSize += (MaxStackAlign - StackAlign); StackAlign = MaxStackAlign; } // Set Max Call Frame Size uint64_t MaxCallSize = alignTo(MFI.getMaxCallFrameSize(), StackAlign); MFI.setMaxCallFrameSize(MaxCallSize); // Make sure the frame is aligned. FrameSize = alignTo(FrameSize, StackAlign); // Update frame info. MFI.setStackSize(FrameSize); } void RISCVFrameLowering::adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, Register DestReg, Register SrcReg, int64_t Val, MachineInstr::MIFlag Flag) const { MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo(); const RISCVInstrInfo *TII = STI.getInstrInfo(); if (DestReg == SrcReg && Val == 0) return; if (isInt<12>(Val)) { BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), DestReg) .addReg(SrcReg) .addImm(Val) .setMIFlag(Flag); } else { unsigned Opc = RISCV::ADD; bool isSub = Val < 0; if (isSub) { Val = -Val; Opc = RISCV::SUB; } Register ScratchReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); TII->movImm(MBB, MBBI, DL, ScratchReg, Val, Flag); BuildMI(MBB, MBBI, DL, TII->get(Opc), DestReg) .addReg(SrcReg) .addReg(ScratchReg, RegState::Kill) .setMIFlag(Flag); } } // Returns the register used to hold the frame pointer. static Register getFPReg(const RISCVSubtarget &STI) { return RISCV::X8; } // Returns the register used to hold the stack pointer. static Register getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; } void RISCVFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo(); const RISCVRegisterInfo *RI = STI.getRegisterInfo(); const RISCVInstrInfo *TII = STI.getInstrInfo(); MachineBasicBlock::iterator MBBI = MBB.begin(); Register FPReg = getFPReg(STI); Register SPReg = getSPReg(STI); Register BPReg = RISCVABI::getBPReg(); // Debug location must be unknown since the first debug location is used // to determine the end of the prologue. DebugLoc DL; // Determine the correct frame layout determineFrameLayout(MF); // FIXME (note copied from Lanai): This appears to be overallocating. Needs // investigation. Get the number of bytes to allocate from the FrameInfo. uint64_t StackSize = MFI.getStackSize(); // Early exit if there is no need to allocate on the stack if (StackSize == 0 && !MFI.adjustsStack()) return; // If the stack pointer has been marked as reserved, then produce an error if // the frame requires stack allocation if (STI.isRegisterReservedByUser(SPReg)) MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ MF.getFunction(), "Stack pointer required, but has been reserved."}); uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); // Split the SP adjustment to reduce the offsets of callee saved spill. if (FirstSPAdjustAmount) StackSize = FirstSPAdjustAmount; // Allocate space on the stack if necessary. adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); // Emit ".cfi_def_cfa_offset StackSize" unsigned CFIIndex = MF.addFrameInst( MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize)); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); // The frame pointer is callee-saved, and code has been generated for us to // save it to the stack. We need to skip over the storing of callee-saved // registers as the frame pointer must be modified after it has been saved // to the stack, not before. // FIXME: assumes exactly one instruction is used to save each callee-saved // register. const std::vector &CSI = MFI.getCalleeSavedInfo(); std::advance(MBBI, CSI.size()); // Iterate over list of callee-saved registers and emit .cfi_offset // directives. for (const auto &Entry : CSI) { int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx()); Register Reg = Entry.getReg(); unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( nullptr, RI->getDwarfRegNum(Reg, true), Offset)); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } // Generate new FP. if (hasFP(MF)) { if (STI.isRegisterReservedByUser(FPReg)) MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ MF.getFunction(), "Frame pointer required, but has been reserved."}); adjustReg(MBB, MBBI, DL, FPReg, SPReg, StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup); - // Emit ".cfi_def_cfa $fp, 0" + // Emit ".cfi_def_cfa $fp, -RVFI->getVarArgsSaveSize()" unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa( - nullptr, RI->getDwarfRegNum(FPReg, true), 0)); + nullptr, RI->getDwarfRegNum(FPReg, true), -RVFI->getVarArgsSaveSize())); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } // Emit the second SP adjustment after saving callee saved registers. if (FirstSPAdjustAmount) { uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; assert(SecondSPAdjustAmount > 0 && "SecondSPAdjustAmount should be greater than zero"); adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, MachineInstr::FrameSetup); // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", // don't emit an sp-based .cfi_def_cfa_offset if (!hasFP(MF)) { // Emit ".cfi_def_cfa_offset StackSize" unsigned CFIIndex = MF.addFrameInst( MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize())); BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } } if (hasFP(MF)) { // Realign Stack const RISCVRegisterInfo *RI = STI.getRegisterInfo(); if (RI->needsStackRealignment(MF)) { unsigned MaxAlignment = MFI.getMaxAlignment(); const RISCVInstrInfo *TII = STI.getInstrInfo(); if (isInt<12>(-(int)MaxAlignment)) { BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg) .addReg(SPReg) .addImm(-(int)MaxAlignment); } else { unsigned ShiftAmount = countTrailingZeros(MaxAlignment); Register VR = MF.getRegInfo().createVirtualRegister(&RISCV::GPRRegClass); BuildMI(MBB, MBBI, DL, TII->get(RISCV::SRLI), VR) .addReg(SPReg) .addImm(ShiftAmount); BuildMI(MBB, MBBI, DL, TII->get(RISCV::SLLI), SPReg) .addReg(VR) .addImm(ShiftAmount); } // FP will be used to restore the frame in the epilogue, so we need // another base register BP to record SP after re-alignment. SP will // track the current stack after allocating variable sized objects. if (hasBP(MF)) { // move BP, SP BuildMI(MBB, MBBI, DL, TII->get(RISCV::ADDI), BPReg) .addReg(SPReg) .addImm(0); } } } } void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { const RISCVRegisterInfo *RI = STI.getRegisterInfo(); MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo(); Register FPReg = getFPReg(STI); Register SPReg = getSPReg(STI); // Get the insert location for the epilogue. If there were no terminators in // the block, get the last instruction. MachineBasicBlock::iterator MBBI = MBB.end(); DebugLoc DL; if (!MBB.empty()) { MBBI = MBB.getFirstTerminator(); if (MBBI == MBB.end()) MBBI = MBB.getLastNonDebugInstr(); DL = MBBI->getDebugLoc(); // If this is not a terminator, the actual insert location should be after the // last instruction. if (!MBBI->isTerminator()) MBBI = std::next(MBBI); } // Skip to before the restores of callee-saved registers // FIXME: assumes exactly one instruction is used to restore each // callee-saved register. auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size()); uint64_t StackSize = MFI.getStackSize(); uint64_t FPOffset = StackSize - RVFI->getVarArgsSaveSize(); // Restore the stack pointer using the value of the frame pointer. Only // necessary if the stack pointer was modified, meaning the stack size is // unknown. if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { assert(hasFP(MF) && "frame pointer should not have been eliminated"); adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, MachineInstr::FrameDestroy); } uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); if (FirstSPAdjustAmount) { uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; assert(SecondSPAdjustAmount > 0 && "SecondSPAdjustAmount should be greater than zero"); adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, MachineInstr::FrameDestroy); } if (FirstSPAdjustAmount) StackSize = FirstSPAdjustAmount; // Deallocate stack adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); } int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, unsigned &FrameReg) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); const auto *RVFI = MF.getInfo(); // Callee-saved registers should be referenced relative to the stack // pointer (positive offset), otherwise use the frame pointer (negative // offset). const std::vector &CSI = MFI.getCalleeSavedInfo(); int MinCSFI = 0; int MaxCSFI = -1; int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + MFI.getOffsetAdjustment(); uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); if (CSI.size()) { MinCSFI = CSI[0].getFrameIdx(); MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); } if (FI >= MinCSFI && FI <= MaxCSFI) { FrameReg = RISCV::X2; if (FirstSPAdjustAmount) Offset += FirstSPAdjustAmount; else Offset += MF.getFrameInfo().getStackSize(); } else if (RI->needsStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { // If the stack was realigned, the frame pointer is set in order to allow // SP to be restored, so we need another base register to record the stack // after realignment. if (hasBP(MF)) FrameReg = RISCVABI::getBPReg(); else FrameReg = RISCV::X2; Offset += MF.getFrameInfo().getStackSize(); } else { FrameReg = RI->getFrameRegister(MF); if (hasFP(MF)) Offset += RVFI->getVarArgsSaveSize(); else Offset += MF.getFrameInfo().getStackSize(); } return Offset; } void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs, RegScavenger *RS) const { TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); // Unconditionally spill RA and FP only if the function uses a frame // pointer. if (hasFP(MF)) { SavedRegs.set(RISCV::X1); SavedRegs.set(RISCV::X8); } // Mark BP as used if function has dedicated base pointer. if (hasBP(MF)) SavedRegs.set(RISCVABI::getBPReg()); // If interrupt is enabled and there are calls in the handler, // unconditionally save all Caller-saved registers and // all FP registers, regardless whether they are used. MachineFrameInfo &MFI = MF.getFrameInfo(); if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) { static const MCPhysReg CSRegs[] = { RISCV::X1, /* ra */ RISCV::X5, RISCV::X6, RISCV::X7, /* t0-t2 */ RISCV::X10, RISCV::X11, /* a0-a1, a2-a7 */ RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17, RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31, 0 /* t3-t6 */ }; for (unsigned i = 0; CSRegs[i]; ++i) SavedRegs.set(CSRegs[i]); if (MF.getSubtarget().hasStdExtD() || MF.getSubtarget().hasStdExtF()) { // If interrupt is enabled, this list contains all FP registers. const MCPhysReg * Regs = MF.getRegInfo().getCalleeSavedRegs(); for (unsigned i = 0; Regs[i]; ++i) if (RISCV::FPR32RegClass.contains(Regs[i]) || RISCV::FPR64RegClass.contains(Regs[i])) SavedRegs.set(Regs[i]); } } } void RISCVFrameLowering::processFunctionBeforeFrameFinalized( MachineFunction &MF, RegScavenger *RS) const { const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo(); MachineFrameInfo &MFI = MF.getFrameInfo(); const TargetRegisterClass *RC = &RISCV::GPRRegClass; // estimateStackSize has been observed to under-estimate the final stack // size, so give ourselves wiggle-room by checking for stack size // representable an 11-bit signed field rather than 12-bits. // FIXME: It may be possible to craft a function with a small stack that // still needs an emergency spill slot for branch relaxation. This case // would currently be missed. if (!isInt<11>(MFI.estimateStackSize(MF))) { int RegScavFI = MFI.CreateStackObject( RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false); RS->addScavengingFrameIndex(RegScavFI); } } // Not preserve stack space within prologue for outgoing variables when the // function contains variable size objects and let eliminateCallFramePseudoInstr // preserve stack space for it. bool RISCVFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { return !MF.getFrameInfo().hasVarSizedObjects(); } // Eliminate ADJCALLSTACKDOWN, ADJCALLSTACKUP pseudo instructions. MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr( MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const { Register SPReg = RISCV::X2; DebugLoc DL = MI->getDebugLoc(); if (!hasReservedCallFrame(MF)) { // If space has not been reserved for a call frame, ADJCALLSTACKDOWN and // ADJCALLSTACKUP must be converted to instructions manipulating the stack // pointer. This is necessary when there is a variable length stack // allocation (e.g. alloca), which means it's not possible to allocate // space for outgoing arguments from within the function prologue. int64_t Amount = MI->getOperand(0).getImm(); if (Amount != 0) { // Ensure the stack remains aligned after adjustment. Amount = alignSPAdjust(Amount); if (MI->getOpcode() == RISCV::ADJCALLSTACKDOWN) Amount = -Amount; adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); } } return MBB.erase(MI); } // We would like to split the SP adjustment to reduce prologue/epilogue // as following instructions. In this way, the offset of the callee saved // register could fit in a single store. // add sp,sp,-2032 // sw ra,2028(sp) // sw s0,2024(sp) // sw s1,2020(sp) // sw s3,2012(sp) // sw s4,2008(sp) // add sp,sp,-64 uint64_t RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); const std::vector &CSI = MFI.getCalleeSavedInfo(); uint64_t StackSize = MFI.getStackSize(); uint64_t StackAlign = getStackAlignment(); // FIXME: Disable SplitSPAdjust if save-restore libcall enabled when the patch // landing. The callee saved registers will be pushed by the // save-restore libcalls, so we don't have to split the SP adjustment // in this case. // // Return the FirstSPAdjustAmount if the StackSize can not fit in signed // 12-bit and there exists a callee saved register need to be pushed. if (!isInt<12>(StackSize) && (CSI.size() > 0)) { // FirstSPAdjustAmount is choosed as (2048 - StackAlign) // because 2048 will cause sp = sp + 2048 in epilogue split into // multi-instructions. The offset smaller than 2048 can fit in signle // load/store instruction and we have to stick with the stack alignment. // 2048 is 16-byte alignment. The stack alignment for RV32 and RV64 is 16, // for RV32E is 4. So (2048 - StackAlign) will satisfy the stack alignment. return 2048 - StackAlign; } return 0; } Index: head/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- head/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelLowering.cpp (revision 362718) +++ head/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVISelLowering.cpp (revision 362719) @@ -1,2923 +1,2957 @@ //===-- RISCVISelLowering.cpp - RISCV DAG Lowering Implementation --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines the interfaces that RISCV uses to lower LLVM code into a // selection DAG. // //===----------------------------------------------------------------------===// #include "RISCVISelLowering.h" #include "RISCV.h" #include "RISCVMachineFunctionInfo.h" #include "RISCVRegisterInfo.h" #include "RISCVSubtarget.h" #include "RISCVTargetMachine.h" #include "Utils/RISCVMatInt.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/IntrinsicsRISCV.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #define DEBUG_TYPE "riscv-lower" STATISTIC(NumTailCalls, "Number of tail calls"); RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, const RISCVSubtarget &STI) : TargetLowering(TM), Subtarget(STI) { if (Subtarget.isRV32E()) report_fatal_error("Codegen not yet implemented for RV32E"); RISCVABI::ABI ABI = Subtarget.getTargetABI(); assert(ABI != RISCVABI::ABI_Unknown && "Improperly initialised target ABI"); if ((ABI == RISCVABI::ABI_ILP32F || ABI == RISCVABI::ABI_LP64F) && !Subtarget.hasStdExtF()) { errs() << "Hard-float 'f' ABI can't be used for a target that " "doesn't support the F instruction set extension (ignoring " "target-abi)\n"; ABI = Subtarget.is64Bit() ? RISCVABI::ABI_LP64 : RISCVABI::ABI_ILP32; } else if ((ABI == RISCVABI::ABI_ILP32D || ABI == RISCVABI::ABI_LP64D) && !Subtarget.hasStdExtD()) { errs() << "Hard-float 'd' ABI can't be used for a target that " "doesn't support the D instruction set extension (ignoring " "target-abi)\n"; ABI = Subtarget.is64Bit() ? RISCVABI::ABI_LP64 : RISCVABI::ABI_ILP32; } switch (ABI) { default: report_fatal_error("Don't know how to lower this ABI"); case RISCVABI::ABI_ILP32: case RISCVABI::ABI_ILP32F: case RISCVABI::ABI_ILP32D: case RISCVABI::ABI_LP64: case RISCVABI::ABI_LP64F: case RISCVABI::ABI_LP64D: break; } MVT XLenVT = Subtarget.getXLenVT(); // Set up the register classes. addRegisterClass(XLenVT, &RISCV::GPRRegClass); if (Subtarget.hasStdExtF()) addRegisterClass(MVT::f32, &RISCV::FPR32RegClass); if (Subtarget.hasStdExtD()) addRegisterClass(MVT::f64, &RISCV::FPR64RegClass); // Compute derived properties from the register classes. computeRegisterProperties(STI.getRegisterInfo()); setStackPointerRegisterToSaveRestore(RISCV::X2); for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) setLoadExtAction(N, XLenVT, MVT::i1, Promote); // TODO: add all necessary setOperationAction calls. setOperationAction(ISD::DYNAMIC_STACKALLOC, XLenVT, Expand); setOperationAction(ISD::BR_JT, MVT::Other, Expand); setOperationAction(ISD::BR_CC, XLenVT, Expand); setOperationAction(ISD::SELECT, XLenVT, Custom); setOperationAction(ISD::SELECT_CC, XLenVT, Expand); setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); 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 VT : {MVT::i1, MVT::i8, MVT::i16}) setOperationAction(ISD::SIGN_EXTEND_INREG, VT, Expand); if (Subtarget.is64Bit()) { setOperationAction(ISD::ADD, MVT::i32, Custom); setOperationAction(ISD::SUB, MVT::i32, Custom); setOperationAction(ISD::SHL, MVT::i32, Custom); setOperationAction(ISD::SRA, MVT::i32, Custom); setOperationAction(ISD::SRL, MVT::i32, Custom); } if (!Subtarget.hasStdExtM()) { setOperationAction(ISD::MUL, XLenVT, Expand); setOperationAction(ISD::MULHS, XLenVT, Expand); setOperationAction(ISD::MULHU, XLenVT, Expand); setOperationAction(ISD::SDIV, XLenVT, Expand); setOperationAction(ISD::UDIV, XLenVT, Expand); setOperationAction(ISD::SREM, XLenVT, Expand); setOperationAction(ISD::UREM, XLenVT, Expand); } if (Subtarget.is64Bit() && Subtarget.hasStdExtM()) { setOperationAction(ISD::MUL, MVT::i32, Custom); setOperationAction(ISD::SDIV, MVT::i32, Custom); setOperationAction(ISD::UDIV, MVT::i32, Custom); setOperationAction(ISD::UREM, MVT::i32, Custom); } setOperationAction(ISD::SDIVREM, XLenVT, Expand); setOperationAction(ISD::UDIVREM, XLenVT, Expand); setOperationAction(ISD::SMUL_LOHI, XLenVT, Expand); setOperationAction(ISD::UMUL_LOHI, XLenVT, Expand); setOperationAction(ISD::SHL_PARTS, XLenVT, Custom); setOperationAction(ISD::SRL_PARTS, XLenVT, Custom); setOperationAction(ISD::SRA_PARTS, XLenVT, Custom); setOperationAction(ISD::ROTL, XLenVT, Expand); setOperationAction(ISD::ROTR, XLenVT, Expand); setOperationAction(ISD::BSWAP, XLenVT, Expand); setOperationAction(ISD::CTTZ, XLenVT, Expand); setOperationAction(ISD::CTLZ, XLenVT, Expand); setOperationAction(ISD::CTPOP, XLenVT, Expand); ISD::CondCode FPCCToExtend[] = { ISD::SETOGT, ISD::SETOGE, ISD::SETONE, ISD::SETUEQ, ISD::SETUGT, ISD::SETUGE, ISD::SETULT, ISD::SETULE, ISD::SETUNE, ISD::SETGT, ISD::SETGE, ISD::SETNE}; ISD::NodeType FPOpToExtend[] = { ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, ISD::FP16_TO_FP, ISD::FP_TO_FP16}; if (Subtarget.hasStdExtF()) { setOperationAction(ISD::FMINNUM, MVT::f32, Legal); setOperationAction(ISD::FMAXNUM, MVT::f32, Legal); for (auto CC : FPCCToExtend) setCondCodeAction(CC, MVT::f32, Expand); setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); setOperationAction(ISD::SELECT, MVT::f32, Custom); setOperationAction(ISD::BR_CC, MVT::f32, Expand); for (auto Op : FPOpToExtend) setOperationAction(Op, MVT::f32, Expand); setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand); setTruncStoreAction(MVT::f32, MVT::f16, Expand); } if (Subtarget.hasStdExtF() && Subtarget.is64Bit()) setOperationAction(ISD::BITCAST, MVT::i32, Custom); if (Subtarget.hasStdExtD()) { setOperationAction(ISD::FMINNUM, MVT::f64, Legal); setOperationAction(ISD::FMAXNUM, MVT::f64, Legal); for (auto CC : FPCCToExtend) setCondCodeAction(CC, MVT::f64, Expand); setOperationAction(ISD::SELECT_CC, MVT::f64, Expand); setOperationAction(ISD::SELECT, MVT::f64, Custom); setOperationAction(ISD::BR_CC, MVT::f64, Expand); setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); setTruncStoreAction(MVT::f64, MVT::f32, Expand); for (auto Op : FPOpToExtend) setOperationAction(Op, MVT::f64, Expand); setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand); setTruncStoreAction(MVT::f64, MVT::f16, Expand); } + if (Subtarget.is64Bit() && + !(Subtarget.hasStdExtD() || Subtarget.hasStdExtF())) { + setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); + setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom); + setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::i32, Custom); + setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::i32, Custom); + } + setOperationAction(ISD::GlobalAddress, XLenVT, Custom); setOperationAction(ISD::BlockAddress, XLenVT, Custom); setOperationAction(ISD::ConstantPool, XLenVT, Custom); setOperationAction(ISD::GlobalTLSAddress, XLenVT, Custom); // TODO: On M-mode only targets, the cycle[h] CSR may not be present. // Unfortunately this can't be determined just from the ISA naming string. setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Subtarget.is64Bit() ? Legal : Custom); setOperationAction(ISD::TRAP, MVT::Other, Legal); setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); if (Subtarget.hasStdExtA()) { setMaxAtomicSizeInBitsSupported(Subtarget.getXLen()); setMinCmpXchgSizeInBits(32); } else { setMaxAtomicSizeInBitsSupported(0); } setBooleanContents(ZeroOrOneBooleanContent); // Function alignments. const Align FunctionAlignment(Subtarget.hasStdExtC() ? 2 : 4); setMinFunctionAlignment(FunctionAlignment); setPrefFunctionAlignment(FunctionAlignment); // Effectively disable jump table generation. setMinimumJumpTableEntries(INT_MAX); } EVT RISCVTargetLowering::getSetCCResultType(const DataLayout &DL, LLVMContext &, EVT VT) const { if (!VT.isVector()) return getPointerTy(DL); return VT.changeVectorElementTypeToInteger(); } bool RISCVTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, const CallInst &I, MachineFunction &MF, unsigned Intrinsic) const { switch (Intrinsic) { default: return false; case Intrinsic::riscv_masked_atomicrmw_xchg_i32: case Intrinsic::riscv_masked_atomicrmw_add_i32: case Intrinsic::riscv_masked_atomicrmw_sub_i32: case Intrinsic::riscv_masked_atomicrmw_nand_i32: case Intrinsic::riscv_masked_atomicrmw_max_i32: case Intrinsic::riscv_masked_atomicrmw_min_i32: case Intrinsic::riscv_masked_atomicrmw_umax_i32: case Intrinsic::riscv_masked_atomicrmw_umin_i32: case Intrinsic::riscv_masked_cmpxchg_i32: PointerType *PtrTy = cast(I.getArgOperand(0)->getType()); Info.opc = ISD::INTRINSIC_W_CHAIN; Info.memVT = MVT::getVT(PtrTy->getElementType()); Info.ptrVal = I.getArgOperand(0); Info.offset = 0; Info.align = Align(4); Info.flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore | MachineMemOperand::MOVolatile; return true; } } bool RISCVTargetLowering::isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, unsigned AS, Instruction *I) const { // No global is ever allowed as a base. if (AM.BaseGV) return false; // Require a 12-bit signed offset. if (!isInt<12>(AM.BaseOffs)) return false; switch (AM.Scale) { case 0: // "r+i" or just "i", depending on HasBaseReg. break; case 1: if (!AM.HasBaseReg) // allow "r+i". break; return false; // disallow "r+r" or "r+r+i". default: return false; } return true; } bool RISCVTargetLowering::isLegalICmpImmediate(int64_t Imm) const { return isInt<12>(Imm); } bool RISCVTargetLowering::isLegalAddImmediate(int64_t Imm) const { return isInt<12>(Imm); } // On RV32, 64-bit integers are split into their high and low parts and held // in two different registers, so the trunc is free since the low register can // just be used. bool RISCVTargetLowering::isTruncateFree(Type *SrcTy, Type *DstTy) const { if (Subtarget.is64Bit() || !SrcTy->isIntegerTy() || !DstTy->isIntegerTy()) return false; unsigned SrcBits = SrcTy->getPrimitiveSizeInBits(); unsigned DestBits = DstTy->getPrimitiveSizeInBits(); return (SrcBits == 64 && DestBits == 32); } bool RISCVTargetLowering::isTruncateFree(EVT SrcVT, EVT DstVT) const { if (Subtarget.is64Bit() || SrcVT.isVector() || DstVT.isVector() || !SrcVT.isInteger() || !DstVT.isInteger()) return false; unsigned SrcBits = SrcVT.getSizeInBits(); unsigned DestBits = DstVT.getSizeInBits(); return (SrcBits == 64 && DestBits == 32); } bool RISCVTargetLowering::isZExtFree(SDValue Val, EVT VT2) const { // Zexts are free if they can be combined with a load. if (auto *LD = dyn_cast(Val)) { EVT MemVT = LD->getMemoryVT(); if ((MemVT == MVT::i8 || MemVT == MVT::i16 || (Subtarget.is64Bit() && MemVT == MVT::i32)) && (LD->getExtensionType() == ISD::NON_EXTLOAD || LD->getExtensionType() == ISD::ZEXTLOAD)) return true; } return TargetLowering::isZExtFree(Val, VT2); } bool RISCVTargetLowering::isSExtCheaperThanZExt(EVT SrcVT, EVT DstVT) const { return Subtarget.is64Bit() && SrcVT == MVT::i32 && DstVT == MVT::i64; } bool RISCVTargetLowering::hasBitPreservingFPLogic(EVT VT) const { return (VT == MVT::f32 && Subtarget.hasStdExtF()) || (VT == MVT::f64 && Subtarget.hasStdExtD()); } // Changes the condition code and swaps operands if necessary, so the SetCC // operation matches one of the comparisons supported directly in the RISC-V // ISA. static void normaliseSetCC(SDValue &LHS, SDValue &RHS, ISD::CondCode &CC) { switch (CC) { default: break; case ISD::SETGT: case ISD::SETLE: case ISD::SETUGT: case ISD::SETULE: CC = ISD::getSetCCSwappedOperands(CC); std::swap(LHS, RHS); break; } } // Return the RISC-V branch opcode that matches the given DAG integer // condition code. The CondCode must be one of those supported by the RISC-V // ISA (see normaliseSetCC). static unsigned getBranchOpcodeForIntCondCode(ISD::CondCode CC) { switch (CC) { default: llvm_unreachable("Unsupported CondCode"); case ISD::SETEQ: return RISCV::BEQ; case ISD::SETNE: return RISCV::BNE; case ISD::SETLT: return RISCV::BLT; case ISD::SETGE: return RISCV::BGE; case ISD::SETULT: return RISCV::BLTU; case ISD::SETUGE: return RISCV::BGEU; } } SDValue RISCVTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { default: report_fatal_error("unimplemented operand"); case ISD::GlobalAddress: return lowerGlobalAddress(Op, DAG); case ISD::BlockAddress: return lowerBlockAddress(Op, DAG); case ISD::ConstantPool: return lowerConstantPool(Op, DAG); case ISD::GlobalTLSAddress: return lowerGlobalTLSAddress(Op, DAG); case ISD::SELECT: return lowerSELECT(Op, DAG); case ISD::VASTART: return lowerVASTART(Op, DAG); case ISD::FRAMEADDR: return lowerFRAMEADDR(Op, DAG); case ISD::RETURNADDR: return lowerRETURNADDR(Op, DAG); case ISD::SHL_PARTS: return lowerShiftLeftParts(Op, DAG); case ISD::SRA_PARTS: return lowerShiftRightParts(Op, DAG, true); case ISD::SRL_PARTS: return lowerShiftRightParts(Op, DAG, false); case ISD::BITCAST: { assert(Subtarget.is64Bit() && Subtarget.hasStdExtF() && "Unexpected custom legalisation"); SDLoc DL(Op); SDValue Op0 = Op.getOperand(0); if (Op.getValueType() != MVT::f32 || Op0.getValueType() != MVT::i32) return SDValue(); SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0); SDValue FPConv = DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, NewOp0); return FPConv; } } } static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty, SelectionDAG &DAG, unsigned Flags) { return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); } static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty, SelectionDAG &DAG, unsigned Flags) { return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(), Flags); } static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty, SelectionDAG &DAG, unsigned Flags) { return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlignment(), N->getOffset(), Flags); } template SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, bool IsLocal) const { SDLoc DL(N); EVT Ty = getPointerTy(DAG.getDataLayout()); if (isPositionIndependent()) { SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); if (IsLocal) // Use PC-relative addressing to access the symbol. This generates the // pattern (PseudoLLA sym), which expands to (addi (auipc %pcrel_hi(sym)) // %pcrel_lo(auipc)). return SDValue(DAG.getMachineNode(RISCV::PseudoLLA, DL, Ty, Addr), 0); // Use PC-relative addressing to access the GOT for this symbol, then load // the address from the GOT. This generates the pattern (PseudoLA sym), // which expands to (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))). return SDValue(DAG.getMachineNode(RISCV::PseudoLA, DL, Ty, Addr), 0); } switch (getTargetMachine().getCodeModel()) { default: report_fatal_error("Unsupported code model for lowering"); case CodeModel::Small: { // Generate a sequence for accessing addresses within the first 2 GiB of // address space. This generates the pattern (addi (lui %hi(sym)) %lo(sym)). SDValue AddrHi = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_HI); SDValue AddrLo = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_LO); SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0); return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, AddrLo), 0); } case CodeModel::Medium: { // Generate a sequence for accessing addresses within any 2GiB range within // the address space. This generates the pattern (PseudoLLA sym), which // expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)). SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); return SDValue(DAG.getMachineNode(RISCV::PseudoLLA, DL, Ty, Addr), 0); } } } SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); EVT Ty = Op.getValueType(); GlobalAddressSDNode *N = cast(Op); int64_t Offset = N->getOffset(); MVT XLenVT = Subtarget.getXLenVT(); const GlobalValue *GV = N->getGlobal(); bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV); SDValue Addr = getAddr(N, DAG, IsLocal); // In order to maximise the opportunity for common subexpression elimination, // emit a separate ADD node for the global address offset instead of folding // it in the global address node. Later peephole optimisations may choose to // fold it back in when profitable. if (Offset != 0) return DAG.getNode(ISD::ADD, DL, Ty, Addr, DAG.getConstant(Offset, DL, XLenVT)); return Addr; } SDValue RISCVTargetLowering::lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const { BlockAddressSDNode *N = cast(Op); return getAddr(N, DAG); } SDValue RISCVTargetLowering::lowerConstantPool(SDValue Op, SelectionDAG &DAG) const { ConstantPoolSDNode *N = cast(Op); return getAddr(N, DAG); } SDValue RISCVTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, bool UseGOT) const { SDLoc DL(N); EVT Ty = getPointerTy(DAG.getDataLayout()); const GlobalValue *GV = N->getGlobal(); MVT XLenVT = Subtarget.getXLenVT(); if (UseGOT) { // Use PC-relative addressing to access the GOT for this TLS symbol, then // load the address from the GOT and add the thread pointer. This generates // the pattern (PseudoLA_TLS_IE sym), which expands to // (ld (auipc %tls_ie_pcrel_hi(sym)) %pcrel_lo(auipc)). SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0); SDValue Load = SDValue(DAG.getMachineNode(RISCV::PseudoLA_TLS_IE, DL, Ty, Addr), 0); // Add the thread pointer. SDValue TPReg = DAG.getRegister(RISCV::X4, XLenVT); return DAG.getNode(ISD::ADD, DL, Ty, Load, TPReg); } // Generate a sequence for accessing the address relative to the thread // pointer, with the appropriate adjustment for the thread pointer offset. // This generates the pattern // (add (add_tprel (lui %tprel_hi(sym)) tp %tprel_add(sym)) %tprel_lo(sym)) SDValue AddrHi = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_TPREL_HI); SDValue AddrAdd = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_TPREL_ADD); SDValue AddrLo = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_TPREL_LO); SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0); SDValue TPReg = DAG.getRegister(RISCV::X4, XLenVT); SDValue MNAdd = SDValue( DAG.getMachineNode(RISCV::PseudoAddTPRel, DL, Ty, MNHi, TPReg, AddrAdd), 0); return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNAdd, AddrLo), 0); } SDValue RISCVTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const { SDLoc DL(N); EVT Ty = getPointerTy(DAG.getDataLayout()); IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits()); const GlobalValue *GV = N->getGlobal(); // Use a PC-relative addressing mode to access the global dynamic GOT address. // This generates the pattern (PseudoLA_TLS_GD sym), which expands to // (addi (auipc %tls_gd_pcrel_hi(sym)) %pcrel_lo(auipc)). SDValue Addr = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, 0); SDValue Load = SDValue(DAG.getMachineNode(RISCV::PseudoLA_TLS_GD, DL, Ty, Addr), 0); // Prepare argument list to generate call. ArgListTy Args; ArgListEntry Entry; Entry.Node = Load; Entry.Ty = CallTy; Args.push_back(Entry); // Setup call to __tls_get_addr. TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(DL) .setChain(DAG.getEntryNode()) .setLibCallee(CallingConv::C, CallTy, DAG.getExternalSymbol("__tls_get_addr", Ty), std::move(Args)); return LowerCallTo(CLI).first; } SDValue RISCVTargetLowering::lowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); EVT Ty = Op.getValueType(); GlobalAddressSDNode *N = cast(Op); int64_t Offset = N->getOffset(); MVT XLenVT = Subtarget.getXLenVT(); TLSModel::Model Model = getTargetMachine().getTLSModel(N->getGlobal()); SDValue Addr; switch (Model) { case TLSModel::LocalExec: Addr = getStaticTLSAddr(N, DAG, /*UseGOT=*/false); break; case TLSModel::InitialExec: Addr = getStaticTLSAddr(N, DAG, /*UseGOT=*/true); break; case TLSModel::LocalDynamic: case TLSModel::GeneralDynamic: Addr = getDynamicTLSAddr(N, DAG); break; } // In order to maximise the opportunity for common subexpression elimination, // emit a separate ADD node for the global address offset instead of folding // it in the global address node. Later peephole optimisations may choose to // fold it back in when profitable. if (Offset != 0) return DAG.getNode(ISD::ADD, DL, Ty, Addr, DAG.getConstant(Offset, DL, XLenVT)); return Addr; } SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const { SDValue CondV = Op.getOperand(0); SDValue TrueV = Op.getOperand(1); SDValue FalseV = Op.getOperand(2); SDLoc DL(Op); MVT XLenVT = Subtarget.getXLenVT(); // If the result type is XLenVT and CondV is the output of a SETCC node // which also operated on XLenVT inputs, then merge the SETCC node into the // lowered RISCVISD::SELECT_CC to take advantage of the integer // compare+branch instructions. i.e.: // (select (setcc lhs, rhs, cc), truev, falsev) // -> (riscvisd::select_cc lhs, rhs, cc, truev, falsev) if (Op.getSimpleValueType() == XLenVT && CondV.getOpcode() == ISD::SETCC && CondV.getOperand(0).getSimpleValueType() == XLenVT) { SDValue LHS = CondV.getOperand(0); SDValue RHS = CondV.getOperand(1); auto CC = cast(CondV.getOperand(2)); ISD::CondCode CCVal = CC->get(); normaliseSetCC(LHS, RHS, CCVal); SDValue TargetCC = DAG.getConstant(CCVal, DL, XLenVT); SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV}; return DAG.getNode(RISCVISD::SELECT_CC, DL, VTs, Ops); } // Otherwise: // (select condv, truev, falsev) // -> (riscvisd::select_cc condv, zero, setne, truev, falsev) SDValue Zero = DAG.getConstant(0, DL, XLenVT); SDValue SetNE = DAG.getConstant(ISD::SETNE, DL, XLenVT); SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV}; return DAG.getNode(RISCVISD::SELECT_CC, DL, VTs, Ops); } SDValue RISCVTargetLowering::lowerVASTART(SDValue Op, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); RISCVMachineFunctionInfo *FuncInfo = MF.getInfo(); SDLoc DL(Op); SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), getPointerTy(MF.getDataLayout())); // vastart just stores the address of the VarArgsFrameIndex slot into the // memory location argument. const Value *SV = cast(Op.getOperand(2))->getValue(); return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1), MachinePointerInfo(SV)); } SDValue RISCVTargetLowering::lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { const RISCVRegisterInfo &RI = *Subtarget.getRegisterInfo(); MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); MFI.setFrameAddressIsTaken(true); Register FrameReg = RI.getFrameRegister(MF); int XLenInBytes = Subtarget.getXLen() / 8; EVT VT = Op.getValueType(); SDLoc DL(Op); SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), DL, FrameReg, VT); unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); while (Depth--) { int Offset = -(XLenInBytes * 2); SDValue Ptr = DAG.getNode(ISD::ADD, DL, VT, FrameAddr, DAG.getIntPtrConstant(Offset, DL)); FrameAddr = DAG.getLoad(VT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo()); } return FrameAddr; } SDValue RISCVTargetLowering::lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const { const RISCVRegisterInfo &RI = *Subtarget.getRegisterInfo(); MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); MFI.setReturnAddressIsTaken(true); MVT XLenVT = Subtarget.getXLenVT(); int XLenInBytes = Subtarget.getXLen() / 8; if (verifyReturnAddressArgumentIsConstant(Op, DAG)) return SDValue(); EVT VT = Op.getValueType(); SDLoc DL(Op); unsigned Depth = cast(Op.getOperand(0))->getZExtValue(); if (Depth) { int Off = -XLenInBytes; SDValue FrameAddr = lowerFRAMEADDR(Op, DAG); SDValue Offset = DAG.getConstant(Off, DL, VT); return DAG.getLoad(VT, DL, DAG.getEntryNode(), DAG.getNode(ISD::ADD, DL, VT, FrameAddr, Offset), MachinePointerInfo()); } // Return the value of the return address register, marking it an implicit // live-in. Register Reg = MF.addLiveIn(RI.getRARegister(), getRegClassFor(XLenVT)); return DAG.getCopyFromReg(DAG.getEntryNode(), DL, Reg, XLenVT); } SDValue RISCVTargetLowering::lowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); SDValue Lo = Op.getOperand(0); SDValue Hi = Op.getOperand(1); SDValue Shamt = Op.getOperand(2); EVT VT = Lo.getValueType(); // if Shamt-XLEN < 0: // Shamt < XLEN // Lo = Lo << Shamt // Hi = (Hi << Shamt) | ((Lo >>u 1) >>u (XLEN-1 - Shamt)) // else: // Lo = 0 // Hi = Lo << (Shamt-XLEN) SDValue Zero = DAG.getConstant(0, DL, VT); SDValue One = DAG.getConstant(1, DL, VT); SDValue MinusXLen = DAG.getConstant(-(int)Subtarget.getXLen(), DL, VT); SDValue XLenMinus1 = DAG.getConstant(Subtarget.getXLen() - 1, DL, VT); SDValue ShamtMinusXLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusXLen); SDValue XLenMinus1Shamt = DAG.getNode(ISD::SUB, DL, VT, XLenMinus1, Shamt); SDValue LoTrue = DAG.getNode(ISD::SHL, DL, VT, Lo, Shamt); SDValue ShiftRight1Lo = DAG.getNode(ISD::SRL, DL, VT, Lo, One); SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, ShiftRight1Lo, XLenMinus1Shamt); SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, Hi, Shamt); SDValue HiTrue = DAG.getNode(ISD::OR, DL, VT, ShiftLeftHi, ShiftRightLo); SDValue HiFalse = DAG.getNode(ISD::SHL, DL, VT, Lo, ShamtMinusXLen); SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusXLen, Zero, ISD::SETLT); Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, Zero); Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); SDValue Parts[2] = {Lo, Hi}; return DAG.getMergeValues(Parts, DL); } SDValue RISCVTargetLowering::lowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const { SDLoc DL(Op); SDValue Lo = Op.getOperand(0); SDValue Hi = Op.getOperand(1); SDValue Shamt = Op.getOperand(2); EVT VT = Lo.getValueType(); // SRA expansion: // if Shamt-XLEN < 0: // Shamt < XLEN // Lo = (Lo >>u Shamt) | ((Hi << 1) << (XLEN-1 - Shamt)) // Hi = Hi >>s Shamt // else: // Lo = Hi >>s (Shamt-XLEN); // Hi = Hi >>s (XLEN-1) // // SRL expansion: // if Shamt-XLEN < 0: // Shamt < XLEN // Lo = (Lo >>u Shamt) | ((Hi << 1) << (XLEN-1 - Shamt)) // Hi = Hi >>u Shamt // else: // Lo = Hi >>u (Shamt-XLEN); // Hi = 0; unsigned ShiftRightOp = IsSRA ? ISD::SRA : ISD::SRL; SDValue Zero = DAG.getConstant(0, DL, VT); SDValue One = DAG.getConstant(1, DL, VT); SDValue MinusXLen = DAG.getConstant(-(int)Subtarget.getXLen(), DL, VT); SDValue XLenMinus1 = DAG.getConstant(Subtarget.getXLen() - 1, DL, VT); SDValue ShamtMinusXLen = DAG.getNode(ISD::ADD, DL, VT, Shamt, MinusXLen); SDValue XLenMinus1Shamt = DAG.getNode(ISD::SUB, DL, VT, XLenMinus1, Shamt); SDValue ShiftRightLo = DAG.getNode(ISD::SRL, DL, VT, Lo, Shamt); SDValue ShiftLeftHi1 = DAG.getNode(ISD::SHL, DL, VT, Hi, One); SDValue ShiftLeftHi = DAG.getNode(ISD::SHL, DL, VT, ShiftLeftHi1, XLenMinus1Shamt); SDValue LoTrue = DAG.getNode(ISD::OR, DL, VT, ShiftRightLo, ShiftLeftHi); SDValue HiTrue = DAG.getNode(ShiftRightOp, DL, VT, Hi, Shamt); SDValue LoFalse = DAG.getNode(ShiftRightOp, DL, VT, Hi, ShamtMinusXLen); SDValue HiFalse = IsSRA ? DAG.getNode(ISD::SRA, DL, VT, Hi, XLenMinus1) : Zero; SDValue CC = DAG.getSetCC(DL, VT, ShamtMinusXLen, Zero, ISD::SETLT); Lo = DAG.getNode(ISD::SELECT, DL, VT, CC, LoTrue, LoFalse); Hi = DAG.getNode(ISD::SELECT, DL, VT, CC, HiTrue, HiFalse); SDValue Parts[2] = {Lo, Hi}; return DAG.getMergeValues(Parts, DL); } // Returns the opcode of the target-specific SDNode that implements the 32-bit // form of the given Opcode. static RISCVISD::NodeType getRISCVWOpcode(unsigned Opcode) { switch (Opcode) { default: llvm_unreachable("Unexpected opcode"); case ISD::SHL: return RISCVISD::SLLW; case ISD::SRA: return RISCVISD::SRAW; case ISD::SRL: return RISCVISD::SRLW; case ISD::SDIV: return RISCVISD::DIVW; case ISD::UDIV: return RISCVISD::DIVUW; case ISD::UREM: return RISCVISD::REMUW; } } // Converts the given 32-bit operation to a target-specific SelectionDAG node. // Because i32 isn't a legal type for RV64, these operations would otherwise // be promoted to i64, making it difficult to select the SLLW/DIVUW/.../*W // later one because the fact the operation was originally of type i32 is // lost. static SDValue customLegalizeToWOp(SDNode *N, SelectionDAG &DAG) { SDLoc DL(N); RISCVISD::NodeType WOpcode = getRISCVWOpcode(N->getOpcode()); SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0)); SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); SDValue NewRes = DAG.getNode(WOpcode, DL, MVT::i64, NewOp0, NewOp1); // ReplaceNodeResults requires we maintain the same type for the return value. return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes); } // Converts the given 32-bit operation to a i64 operation with signed extension // semantic to reduce the signed extension instructions. static SDValue customLegalizeToWOpWithSExt(SDNode *N, SelectionDAG &DAG) { SDLoc DL(N); SDValue NewOp0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(0)); SDValue NewOp1 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N->getOperand(1)); SDValue NewWOp = DAG.getNode(N->getOpcode(), DL, MVT::i64, NewOp0, NewOp1); SDValue NewRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, NewWOp, DAG.getValueType(MVT::i32)); return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, NewRes); } void RISCVTargetLowering::ReplaceNodeResults(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const { SDLoc DL(N); switch (N->getOpcode()) { default: llvm_unreachable("Don't know how to custom type legalize this operation!"); + case ISD::STRICT_FP_TO_SINT: + case ISD::STRICT_FP_TO_UINT: + case ISD::FP_TO_SINT: + case ISD::FP_TO_UINT: { + bool IsStrict = N->isStrictFPOpcode(); + assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && + "Unexpected custom legalisation"); + SDValue Op0 = IsStrict ? N->getOperand(1) : N->getOperand(0); + RTLIB::Libcall LC; + if (N->getOpcode() == ISD::FP_TO_SINT || + N->getOpcode() == ISD::STRICT_FP_TO_SINT) + LC = RTLIB::getFPTOSINT(Op0.getValueType(), N->getValueType(0)); + else + LC = RTLIB::getFPTOUINT(Op0.getValueType(), N->getValueType(0)); + MakeLibCallOptions CallOptions; + EVT OpVT = Op0.getValueType(); + CallOptions.setTypeListBeforeSoften(OpVT, N->getValueType(0), true); + SDValue Chain = IsStrict ? N->getOperand(0) : SDValue(); + SDValue Result; + std::tie(Result, Chain) = + makeLibCall(DAG, LC, N->getValueType(0), Op0, CallOptions, DL, Chain); + Results.push_back(Result); + if (IsStrict) + Results.push_back(Chain); + break; + } case ISD::READCYCLECOUNTER: { assert(!Subtarget.is64Bit() && "READCYCLECOUNTER only has custom type legalization on riscv32"); SDVTList VTs = DAG.getVTList(MVT::i32, MVT::i32, MVT::Other); SDValue RCW = DAG.getNode(RISCVISD::READ_CYCLE_WIDE, DL, VTs, N->getOperand(0)); Results.push_back(RCW); Results.push_back(RCW.getValue(1)); Results.push_back(RCW.getValue(2)); break; } case ISD::ADD: case ISD::SUB: case ISD::MUL: assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && "Unexpected custom legalisation"); if (N->getOperand(1).getOpcode() == ISD::Constant) return; Results.push_back(customLegalizeToWOpWithSExt(N, DAG)); break; case ISD::SHL: case ISD::SRA: case ISD::SRL: assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && "Unexpected custom legalisation"); if (N->getOperand(1).getOpcode() == ISD::Constant) return; Results.push_back(customLegalizeToWOp(N, DAG)); break; case ISD::SDIV: case ISD::UDIV: case ISD::UREM: assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && Subtarget.hasStdExtM() && "Unexpected custom legalisation"); if (N->getOperand(0).getOpcode() == ISD::Constant || N->getOperand(1).getOpcode() == ISD::Constant) return; Results.push_back(customLegalizeToWOp(N, DAG)); break; case ISD::BITCAST: { assert(N->getValueType(0) == MVT::i32 && Subtarget.is64Bit() && Subtarget.hasStdExtF() && "Unexpected custom legalisation"); SDLoc DL(N); SDValue Op0 = N->getOperand(0); if (Op0.getValueType() != MVT::f32) return; SDValue FPConv = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Op0); Results.push_back(DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, FPConv)); break; } } } SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; switch (N->getOpcode()) { default: break; case RISCVISD::SplitF64: { SDValue Op0 = N->getOperand(0); // If the input to SplitF64 is just BuildPairF64 then the operation is // redundant. Instead, use BuildPairF64's operands directly. if (Op0->getOpcode() == RISCVISD::BuildPairF64) return DCI.CombineTo(N, Op0.getOperand(0), Op0.getOperand(1)); SDLoc DL(N); // It's cheaper to materialise two 32-bit integers than to load a double // from the constant pool and transfer it to integer registers through the // stack. if (ConstantFPSDNode *C = dyn_cast(Op0)) { APInt V = C->getValueAPF().bitcastToAPInt(); SDValue Lo = DAG.getConstant(V.trunc(32), DL, MVT::i32); SDValue Hi = DAG.getConstant(V.lshr(32).trunc(32), DL, MVT::i32); return DCI.CombineTo(N, Lo, Hi); } // This is a target-specific version of a DAGCombine performed in // DAGCombiner::visitBITCAST. It performs the equivalent of: // fold (bitconvert (fneg x)) -> (xor (bitconvert x), signbit) // fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) if (!(Op0.getOpcode() == ISD::FNEG || Op0.getOpcode() == ISD::FABS) || !Op0.getNode()->hasOneUse()) break; SDValue NewSplitF64 = DAG.getNode(RISCVISD::SplitF64, DL, DAG.getVTList(MVT::i32, MVT::i32), Op0.getOperand(0)); SDValue Lo = NewSplitF64.getValue(0); SDValue Hi = NewSplitF64.getValue(1); APInt SignBit = APInt::getSignMask(32); if (Op0.getOpcode() == ISD::FNEG) { SDValue NewHi = DAG.getNode(ISD::XOR, DL, MVT::i32, Hi, DAG.getConstant(SignBit, DL, MVT::i32)); return DCI.CombineTo(N, Lo, NewHi); } assert(Op0.getOpcode() == ISD::FABS); SDValue NewHi = DAG.getNode(ISD::AND, DL, MVT::i32, Hi, DAG.getConstant(~SignBit, DL, MVT::i32)); return DCI.CombineTo(N, Lo, NewHi); } case RISCVISD::SLLW: case RISCVISD::SRAW: case RISCVISD::SRLW: { // Only the lower 32 bits of LHS and lower 5 bits of RHS are read. SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); APInt LHSMask = APInt::getLowBitsSet(LHS.getValueSizeInBits(), 32); APInt RHSMask = APInt::getLowBitsSet(RHS.getValueSizeInBits(), 5); if ((SimplifyDemandedBits(N->getOperand(0), LHSMask, DCI)) || (SimplifyDemandedBits(N->getOperand(1), RHSMask, DCI))) return SDValue(); break; } case RISCVISD::FMV_X_ANYEXTW_RV64: { SDLoc DL(N); SDValue Op0 = N->getOperand(0); // If the input to FMV_X_ANYEXTW_RV64 is just FMV_W_X_RV64 then the // conversion is unnecessary and can be replaced with an ANY_EXTEND // of the FMV_W_X_RV64 operand. if (Op0->getOpcode() == RISCVISD::FMV_W_X_RV64) { SDValue AExtOp = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, Op0.getOperand(0)); return DCI.CombineTo(N, AExtOp); } // This is a target-specific version of a DAGCombine performed in // DAGCombiner::visitBITCAST. It performs the equivalent of: // fold (bitconvert (fneg x)) -> (xor (bitconvert x), signbit) // fold (bitconvert (fabs x)) -> (and (bitconvert x), (not signbit)) if (!(Op0.getOpcode() == ISD::FNEG || Op0.getOpcode() == ISD::FABS) || !Op0.getNode()->hasOneUse()) break; SDValue NewFMV = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Op0.getOperand(0)); APInt SignBit = APInt::getSignMask(32).sext(64); if (Op0.getOpcode() == ISD::FNEG) { return DCI.CombineTo(N, DAG.getNode(ISD::XOR, DL, MVT::i64, NewFMV, DAG.getConstant(SignBit, DL, MVT::i64))); } assert(Op0.getOpcode() == ISD::FABS); return DCI.CombineTo(N, DAG.getNode(ISD::AND, DL, MVT::i64, NewFMV, DAG.getConstant(~SignBit, DL, MVT::i64))); } } return SDValue(); } bool RISCVTargetLowering::isDesirableToCommuteWithShift( const SDNode *N, CombineLevel Level) const { // The following folds are only desirable if `(OP _, c1 << c2)` can be // materialised in fewer instructions than `(OP _, c1)`: // // (shl (add x, c1), c2) -> (add (shl x, c2), c1 << c2) // (shl (or x, c1), c2) -> (or (shl x, c2), c1 << c2) SDValue N0 = N->getOperand(0); EVT Ty = N0.getValueType(); if (Ty.isScalarInteger() && (N0.getOpcode() == ISD::ADD || N0.getOpcode() == ISD::OR)) { auto *C1 = dyn_cast(N0->getOperand(1)); auto *C2 = dyn_cast(N->getOperand(1)); if (C1 && C2) { APInt C1Int = C1->getAPIntValue(); APInt ShiftedC1Int = C1Int << C2->getAPIntValue(); // We can materialise `c1 << c2` into an add immediate, so it's "free", // and the combine should happen, to potentially allow further combines // later. if (ShiftedC1Int.getMinSignedBits() <= 64 && isLegalAddImmediate(ShiftedC1Int.getSExtValue())) return true; // We can materialise `c1` in an add immediate, so it's "free", and the // combine should be prevented. if (C1Int.getMinSignedBits() <= 64 && isLegalAddImmediate(C1Int.getSExtValue())) return false; // Neither constant will fit into an immediate, so find materialisation // costs. int C1Cost = RISCVMatInt::getIntMatCost(C1Int, Ty.getSizeInBits(), Subtarget.is64Bit()); int ShiftedC1Cost = RISCVMatInt::getIntMatCost( ShiftedC1Int, Ty.getSizeInBits(), Subtarget.is64Bit()); // Materialising `c1` is cheaper than materialising `c1 << c2`, so the // combine should be prevented. if (C1Cost < ShiftedC1Cost) return false; } } return true; } unsigned RISCVTargetLowering::ComputeNumSignBitsForTargetNode( SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG, unsigned Depth) const { switch (Op.getOpcode()) { default: break; case RISCVISD::SLLW: case RISCVISD::SRAW: case RISCVISD::SRLW: case RISCVISD::DIVW: case RISCVISD::DIVUW: case RISCVISD::REMUW: // TODO: As the result is sign-extended, this is conservatively correct. A // more precise answer could be calculated for SRAW depending on known // bits in the shift amount. return 33; } return 1; } static MachineBasicBlock *emitReadCycleWidePseudo(MachineInstr &MI, MachineBasicBlock *BB) { assert(MI.getOpcode() == RISCV::ReadCycleWide && "Unexpected instruction"); // To read the 64-bit cycle CSR on a 32-bit target, we read the two halves. // Should the count have wrapped while it was being read, we need to try // again. // ... // read: // rdcycleh x3 # load high word of cycle // rdcycle x2 # load low word of cycle // rdcycleh x4 # load high word of cycle // bne x3, x4, read # check if high word reads match, otherwise try again // ... MachineFunction &MF = *BB->getParent(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); MachineFunction::iterator It = ++BB->getIterator(); MachineBasicBlock *LoopMBB = MF.CreateMachineBasicBlock(LLVM_BB); MF.insert(It, LoopMBB); MachineBasicBlock *DoneMBB = MF.CreateMachineBasicBlock(LLVM_BB); MF.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(LoopMBB); MachineRegisterInfo &RegInfo = MF.getRegInfo(); Register ReadAgainReg = RegInfo.createVirtualRegister(&RISCV::GPRRegClass); Register LoReg = MI.getOperand(0).getReg(); Register HiReg = MI.getOperand(1).getReg(); DebugLoc DL = MI.getDebugLoc(); const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), HiReg) .addImm(RISCVSysReg::lookupSysRegByName("CYCLEH")->Encoding) .addReg(RISCV::X0); BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), LoReg) .addImm(RISCVSysReg::lookupSysRegByName("CYCLE")->Encoding) .addReg(RISCV::X0); BuildMI(LoopMBB, DL, TII->get(RISCV::CSRRS), ReadAgainReg) .addImm(RISCVSysReg::lookupSysRegByName("CYCLEH")->Encoding) .addReg(RISCV::X0); BuildMI(LoopMBB, DL, TII->get(RISCV::BNE)) .addReg(HiReg) .addReg(ReadAgainReg) .addMBB(LoopMBB); LoopMBB->addSuccessor(LoopMBB); LoopMBB->addSuccessor(DoneMBB); MI.eraseFromParent(); return DoneMBB; } static MachineBasicBlock *emitSplitF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB) { assert(MI.getOpcode() == RISCV::SplitF64Pseudo && "Unexpected instruction"); MachineFunction &MF = *BB->getParent(); DebugLoc DL = MI.getDebugLoc(); const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); Register LoReg = MI.getOperand(0).getReg(); Register HiReg = MI.getOperand(1).getReg(); Register SrcReg = MI.getOperand(2).getReg(); const TargetRegisterClass *SrcRC = &RISCV::FPR64RegClass; int FI = MF.getInfo()->getMoveF64FrameIndex(); TII.storeRegToStackSlot(*BB, MI, SrcReg, MI.getOperand(2).isKill(), FI, SrcRC, RI); MachineMemOperand *MMO = MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad, 8, 8); BuildMI(*BB, MI, DL, TII.get(RISCV::LW), LoReg) .addFrameIndex(FI) .addImm(0) .addMemOperand(MMO); BuildMI(*BB, MI, DL, TII.get(RISCV::LW), HiReg) .addFrameIndex(FI) .addImm(4) .addMemOperand(MMO); MI.eraseFromParent(); // The pseudo instruction is gone now. return BB; } static MachineBasicBlock *emitBuildPairF64Pseudo(MachineInstr &MI, MachineBasicBlock *BB) { assert(MI.getOpcode() == RISCV::BuildPairF64Pseudo && "Unexpected instruction"); MachineFunction &MF = *BB->getParent(); DebugLoc DL = MI.getDebugLoc(); const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo(); Register DstReg = MI.getOperand(0).getReg(); Register LoReg = MI.getOperand(1).getReg(); Register HiReg = MI.getOperand(2).getReg(); const TargetRegisterClass *DstRC = &RISCV::FPR64RegClass; int FI = MF.getInfo()->getMoveF64FrameIndex(); MachineMemOperand *MMO = MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore, 8, 8); BuildMI(*BB, MI, DL, TII.get(RISCV::SW)) .addReg(LoReg, getKillRegState(MI.getOperand(1).isKill())) .addFrameIndex(FI) .addImm(0) .addMemOperand(MMO); BuildMI(*BB, MI, DL, TII.get(RISCV::SW)) .addReg(HiReg, getKillRegState(MI.getOperand(2).isKill())) .addFrameIndex(FI) .addImm(4) .addMemOperand(MMO); TII.loadRegFromStackSlot(*BB, MI, DstReg, FI, DstRC, RI); MI.eraseFromParent(); // The pseudo instruction is gone now. return BB; } static bool isSelectPseudo(MachineInstr &MI) { switch (MI.getOpcode()) { default: return false; case RISCV::Select_GPR_Using_CC_GPR: case RISCV::Select_FPR32_Using_CC_GPR: case RISCV::Select_FPR64_Using_CC_GPR: return true; } } static MachineBasicBlock *emitSelectPseudo(MachineInstr &MI, MachineBasicBlock *BB) { // To "insert" Select_* instructions, we actually have to insert the triangle // control-flow pattern. The incoming instructions know the destination vreg // to set, the condition code register to branch on, the true/false values to // select between, and the condcode to use to select the appropriate branch. // // We produce the following control flow: // HeadMBB // | \ // | IfFalseMBB // | / // TailMBB // // When we find a sequence of selects we attempt to optimize their emission // by sharing the control flow. Currently we only handle cases where we have // multiple selects with the exact same condition (same LHS, RHS and CC). // The selects may be interleaved with other instructions if the other // instructions meet some requirements we deem safe: // - They are debug instructions. Otherwise, // - They do not have side-effects, do not access memory and their inputs do // not depend on the results of the select pseudo-instructions. // The TrueV/FalseV operands of the selects cannot depend on the result of // previous selects in the sequence. // These conditions could be further relaxed. See the X86 target for a // related approach and more information. Register LHS = MI.getOperand(1).getReg(); Register RHS = MI.getOperand(2).getReg(); auto CC = static_cast(MI.getOperand(3).getImm()); SmallVector SelectDebugValues; SmallSet SelectDests; SelectDests.insert(MI.getOperand(0).getReg()); MachineInstr *LastSelectPseudo = &MI; for (auto E = BB->end(), SequenceMBBI = MachineBasicBlock::iterator(MI); SequenceMBBI != E; ++SequenceMBBI) { if (SequenceMBBI->isDebugInstr()) continue; else if (isSelectPseudo(*SequenceMBBI)) { if (SequenceMBBI->getOperand(1).getReg() != LHS || SequenceMBBI->getOperand(2).getReg() != RHS || SequenceMBBI->getOperand(3).getImm() != CC || SelectDests.count(SequenceMBBI->getOperand(4).getReg()) || SelectDests.count(SequenceMBBI->getOperand(5).getReg())) break; LastSelectPseudo = &*SequenceMBBI; SequenceMBBI->collectDebugValues(SelectDebugValues); SelectDests.insert(SequenceMBBI->getOperand(0).getReg()); } else { if (SequenceMBBI->hasUnmodeledSideEffects() || SequenceMBBI->mayLoadOrStore()) break; if (llvm::any_of(SequenceMBBI->operands(), [&](MachineOperand &MO) { return MO.isReg() && MO.isUse() && SelectDests.count(MO.getReg()); })) break; } } const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo(); const BasicBlock *LLVM_BB = BB->getBasicBlock(); DebugLoc DL = MI.getDebugLoc(); MachineFunction::iterator I = ++BB->getIterator(); MachineBasicBlock *HeadMBB = BB; MachineFunction *F = BB->getParent(); MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB); MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB); F->insert(I, IfFalseMBB); F->insert(I, TailMBB); // Transfer debug instructions associated with the selects to TailMBB. for (MachineInstr *DebugInstr : SelectDebugValues) { TailMBB->push_back(DebugInstr->removeFromParent()); } // Move all instructions after the sequence to TailMBB. TailMBB->splice(TailMBB->end(), HeadMBB, std::next(LastSelectPseudo->getIterator()), HeadMBB->end()); // Update machine-CFG edges by transferring all successors of the current // block to the new block which will contain the Phi nodes for the selects. TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB); // Set the successors for HeadMBB. HeadMBB->addSuccessor(IfFalseMBB); HeadMBB->addSuccessor(TailMBB); // Insert appropriate branch. unsigned Opcode = getBranchOpcodeForIntCondCode(CC); BuildMI(HeadMBB, DL, TII.get(Opcode)) .addReg(LHS) .addReg(RHS) .addMBB(TailMBB); // IfFalseMBB just falls through to TailMBB. IfFalseMBB->addSuccessor(TailMBB); // Create PHIs for all of the select pseudo-instructions. auto SelectMBBI = MI.getIterator(); auto SelectEnd = std::next(LastSelectPseudo->getIterator()); auto InsertionPoint = TailMBB->begin(); while (SelectMBBI != SelectEnd) { auto Next = std::next(SelectMBBI); if (isSelectPseudo(*SelectMBBI)) { // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ] BuildMI(*TailMBB, InsertionPoint, SelectMBBI->getDebugLoc(), TII.get(RISCV::PHI), SelectMBBI->getOperand(0).getReg()) .addReg(SelectMBBI->getOperand(4).getReg()) .addMBB(HeadMBB) .addReg(SelectMBBI->getOperand(5).getReg()) .addMBB(IfFalseMBB); SelectMBBI->eraseFromParent(); } SelectMBBI = Next; } F->getProperties().reset(MachineFunctionProperties::Property::NoPHIs); return TailMBB; } MachineBasicBlock * RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *BB) const { switch (MI.getOpcode()) { default: llvm_unreachable("Unexpected instr type to insert"); case RISCV::ReadCycleWide: assert(!Subtarget.is64Bit() && "ReadCycleWrite is only to be used on riscv32"); return emitReadCycleWidePseudo(MI, BB); case RISCV::Select_GPR_Using_CC_GPR: case RISCV::Select_FPR32_Using_CC_GPR: case RISCV::Select_FPR64_Using_CC_GPR: return emitSelectPseudo(MI, BB); case RISCV::BuildPairF64Pseudo: return emitBuildPairF64Pseudo(MI, BB); case RISCV::SplitF64Pseudo: return emitSplitF64Pseudo(MI, BB); } } // Calling Convention Implementation. // The expectations for frontend ABI lowering vary from target to target. // Ideally, an LLVM frontend would be able to avoid worrying about many ABI // details, but this is a longer term goal. For now, we simply try to keep the // role of the frontend as simple and well-defined as possible. The rules can // be summarised as: // * Never split up large scalar arguments. We handle them here. // * If a hardfloat calling convention is being used, and the struct may be // passed in a pair of registers (fp+fp, int+fp), and both registers are // available, then pass as two separate arguments. If either the GPRs or FPRs // are exhausted, then pass according to the rule below. // * If a struct could never be passed in registers or directly in a stack // slot (as it is larger than 2*XLEN and the floating point rules don't // apply), then pass it using a pointer with the byval attribute. // * If a struct is less than 2*XLEN, then coerce to either a two-element // word-sized array or a 2*XLEN scalar (depending on alignment). // * The frontend can determine whether a struct is returned by reference or // not based on its size and fields. If it will be returned by reference, the // frontend must modify the prototype so a pointer with the sret annotation is // passed as the first argument. This is not necessary for large scalar // returns. // * Struct return values and varargs should be coerced to structs containing // register-size fields in the same situations they would be for fixed // arguments. static const MCPhysReg ArgGPRs[] = { RISCV::X10, RISCV::X11, RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17 }; static const MCPhysReg ArgFPR32s[] = { RISCV::F10_F, RISCV::F11_F, RISCV::F12_F, RISCV::F13_F, RISCV::F14_F, RISCV::F15_F, RISCV::F16_F, RISCV::F17_F }; static const MCPhysReg ArgFPR64s[] = { RISCV::F10_D, RISCV::F11_D, RISCV::F12_D, RISCV::F13_D, RISCV::F14_D, RISCV::F15_D, RISCV::F16_D, RISCV::F17_D }; // Pass a 2*XLEN argument that has been split into two XLEN values through // registers or the stack as necessary. static bool CC_RISCVAssign2XLen(unsigned XLen, CCState &State, CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, MVT ValVT2, MVT LocVT2, ISD::ArgFlagsTy ArgFlags2) { unsigned XLenInBytes = XLen / 8; if (Register Reg = State.AllocateReg(ArgGPRs)) { // At least one half can be passed via register. State.addLoc(CCValAssign::getReg(VA1.getValNo(), VA1.getValVT(), Reg, VA1.getLocVT(), CCValAssign::Full)); } else { // Both halves must be passed on the stack, with proper alignment. unsigned StackAlign = std::max(XLenInBytes, ArgFlags1.getOrigAlign()); State.addLoc( CCValAssign::getMem(VA1.getValNo(), VA1.getValVT(), State.AllocateStack(XLenInBytes, StackAlign), VA1.getLocVT(), CCValAssign::Full)); State.addLoc(CCValAssign::getMem( ValNo2, ValVT2, State.AllocateStack(XLenInBytes, XLenInBytes), LocVT2, CCValAssign::Full)); return false; } if (Register Reg = State.AllocateReg(ArgGPRs)) { // The second half can also be passed via register. State.addLoc( CCValAssign::getReg(ValNo2, ValVT2, Reg, LocVT2, CCValAssign::Full)); } else { // The second half is passed via the stack, without additional alignment. State.addLoc(CCValAssign::getMem( ValNo2, ValVT2, State.AllocateStack(XLenInBytes, XLenInBytes), LocVT2, CCValAssign::Full)); } return false; } // Implements the RISC-V calling convention. Returns true upon failure. static bool CC_RISCV(const DataLayout &DL, RISCVABI::ABI ABI, unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, bool IsRet, Type *OrigTy) { unsigned XLen = DL.getLargestLegalIntTypeSizeInBits(); assert(XLen == 32 || XLen == 64); MVT XLenVT = XLen == 32 ? MVT::i32 : MVT::i64; // Any return value split in to more than two values can't be returned // directly. if (IsRet && ValNo > 1) return true; // UseGPRForF32 if targeting one of the soft-float ABIs, if passing a // variadic argument, or if no F32 argument registers are available. bool UseGPRForF32 = true; // UseGPRForF64 if targeting soft-float ABIs or an FLEN=32 ABI, if passing a // variadic argument, or if no F64 argument registers are available. bool UseGPRForF64 = true; switch (ABI) { default: llvm_unreachable("Unexpected ABI"); case RISCVABI::ABI_ILP32: case RISCVABI::ABI_LP64: break; case RISCVABI::ABI_ILP32F: case RISCVABI::ABI_LP64F: UseGPRForF32 = !IsFixed; break; case RISCVABI::ABI_ILP32D: case RISCVABI::ABI_LP64D: UseGPRForF32 = !IsFixed; UseGPRForF64 = !IsFixed; break; } if (State.getFirstUnallocated(ArgFPR32s) == array_lengthof(ArgFPR32s)) UseGPRForF32 = true; if (State.getFirstUnallocated(ArgFPR64s) == array_lengthof(ArgFPR64s)) UseGPRForF64 = true; // From this point on, rely on UseGPRForF32, UseGPRForF64 and similar local // variables rather than directly checking against the target ABI. if (UseGPRForF32 && ValVT == MVT::f32) { LocVT = XLenVT; LocInfo = CCValAssign::BCvt; } else if (UseGPRForF64 && XLen == 64 && ValVT == MVT::f64) { LocVT = MVT::i64; LocInfo = CCValAssign::BCvt; } // If this is a variadic argument, the RISC-V calling convention requires // that it is assigned an 'even' or 'aligned' register if it has 8-byte // alignment (RV32) or 16-byte alignment (RV64). An aligned register should // be used regardless of whether the original argument was split during // legalisation or not. The argument will not be passed by registers if the // original type is larger than 2*XLEN, so the register alignment rule does // not apply. unsigned TwoXLenInBytes = (2 * XLen) / 8; if (!IsFixed && ArgFlags.getOrigAlign() == TwoXLenInBytes && DL.getTypeAllocSize(OrigTy) == TwoXLenInBytes) { unsigned RegIdx = State.getFirstUnallocated(ArgGPRs); // Skip 'odd' register if necessary. if (RegIdx != array_lengthof(ArgGPRs) && RegIdx % 2 == 1) State.AllocateReg(ArgGPRs); } SmallVectorImpl &PendingLocs = State.getPendingLocs(); SmallVectorImpl &PendingArgFlags = State.getPendingArgFlags(); assert(PendingLocs.size() == PendingArgFlags.size() && "PendingLocs and PendingArgFlags out of sync"); // Handle passing f64 on RV32D with a soft float ABI or when floating point // registers are exhausted. if (UseGPRForF64 && XLen == 32 && ValVT == MVT::f64) { assert(!ArgFlags.isSplit() && PendingLocs.empty() && "Can't lower f64 if it is split"); // Depending on available argument GPRS, f64 may be passed in a pair of // GPRs, split between a GPR and the stack, or passed completely on the // stack. LowerCall/LowerFormalArguments/LowerReturn must recognise these // cases. Register Reg = State.AllocateReg(ArgGPRs); LocVT = MVT::i32; if (!Reg) { unsigned StackOffset = State.AllocateStack(8, 8); State.addLoc( CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo)); return false; } if (!State.AllocateReg(ArgGPRs)) State.AllocateStack(4, 4); State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); return false; } // Split arguments might be passed indirectly, so keep track of the pending // values. if (ArgFlags.isSplit() || !PendingLocs.empty()) { LocVT = XLenVT; LocInfo = CCValAssign::Indirect; PendingLocs.push_back( CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo)); PendingArgFlags.push_back(ArgFlags); if (!ArgFlags.isSplitEnd()) { return false; } } // If the split argument only had two elements, it should be passed directly // in registers or on the stack. if (ArgFlags.isSplitEnd() && PendingLocs.size() <= 2) { assert(PendingLocs.size() == 2 && "Unexpected PendingLocs.size()"); // Apply the normal calling convention rules to the first half of the // split argument. CCValAssign VA = PendingLocs[0]; ISD::ArgFlagsTy AF = PendingArgFlags[0]; PendingLocs.clear(); PendingArgFlags.clear(); return CC_RISCVAssign2XLen(XLen, State, VA, AF, ValNo, ValVT, LocVT, ArgFlags); } // Allocate to a register if possible, or else a stack slot. Register Reg; if (ValVT == MVT::f32 && !UseGPRForF32) Reg = State.AllocateReg(ArgFPR32s, ArgFPR64s); else if (ValVT == MVT::f64 && !UseGPRForF64) Reg = State.AllocateReg(ArgFPR64s, ArgFPR32s); else Reg = State.AllocateReg(ArgGPRs); unsigned StackOffset = Reg ? 0 : State.AllocateStack(XLen / 8, XLen / 8); // If we reach this point and PendingLocs is non-empty, we must be at the // end of a split argument that must be passed indirectly. if (!PendingLocs.empty()) { assert(ArgFlags.isSplitEnd() && "Expected ArgFlags.isSplitEnd()"); assert(PendingLocs.size() > 2 && "Unexpected PendingLocs.size()"); for (auto &It : PendingLocs) { if (Reg) It.convertToReg(Reg); else It.convertToMem(StackOffset); State.addLoc(It); } PendingLocs.clear(); PendingArgFlags.clear(); return false; } assert((!UseGPRForF32 || !UseGPRForF64 || LocVT == XLenVT) && "Expected an XLenVT at this stage"); if (Reg) { State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); return false; } // When an f32 or f64 is passed on the stack, no bit-conversion is needed. if (ValVT == MVT::f32 || ValVT == MVT::f64) { LocVT = ValVT; LocInfo = CCValAssign::Full; } State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo)); return false; } void RISCVTargetLowering::analyzeInputArgs( MachineFunction &MF, CCState &CCInfo, const SmallVectorImpl &Ins, bool IsRet) const { unsigned NumArgs = Ins.size(); FunctionType *FType = MF.getFunction().getFunctionType(); for (unsigned i = 0; i != NumArgs; ++i) { MVT ArgVT = Ins[i].VT; ISD::ArgFlagsTy ArgFlags = Ins[i].Flags; Type *ArgTy = nullptr; if (IsRet) ArgTy = FType->getReturnType(); else if (Ins[i].isOrigArg()) ArgTy = FType->getParamType(Ins[i].getOrigArgIndex()); RISCVABI::ABI ABI = MF.getSubtarget().getTargetABI(); if (CC_RISCV(MF.getDataLayout(), ABI, i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo, /*IsRet=*/true, IsRet, ArgTy)) { LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type " << EVT(ArgVT).getEVTString() << '\n'); llvm_unreachable(nullptr); } } } void RISCVTargetLowering::analyzeOutputArgs( MachineFunction &MF, CCState &CCInfo, const SmallVectorImpl &Outs, bool IsRet, CallLoweringInfo *CLI) const { unsigned NumArgs = Outs.size(); for (unsigned i = 0; i != NumArgs; i++) { MVT ArgVT = Outs[i].VT; ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; Type *OrigTy = CLI ? CLI->getArgs()[Outs[i].OrigArgIndex].Ty : nullptr; RISCVABI::ABI ABI = MF.getSubtarget().getTargetABI(); if (CC_RISCV(MF.getDataLayout(), ABI, i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo, Outs[i].IsFixed, IsRet, OrigTy)) { LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type " << EVT(ArgVT).getEVTString() << "\n"); llvm_unreachable(nullptr); } } } // Convert Val to a ValVT. Should not be called for CCValAssign::Indirect // values. static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL) { switch (VA.getLocInfo()) { default: llvm_unreachable("Unexpected CCValAssign::LocInfo"); case CCValAssign::Full: break; case CCValAssign::BCvt: if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) { Val = DAG.getNode(RISCVISD::FMV_W_X_RV64, DL, MVT::f32, Val); break; } Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); break; } return Val; } // The caller is responsible for loading the full value if the argument is // passed with CCValAssign::Indirect. static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL) { MachineFunction &MF = DAG.getMachineFunction(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); EVT LocVT = VA.getLocVT(); SDValue Val; const TargetRegisterClass *RC; switch (LocVT.getSimpleVT().SimpleTy) { default: llvm_unreachable("Unexpected register type"); case MVT::i32: case MVT::i64: RC = &RISCV::GPRRegClass; break; case MVT::f32: RC = &RISCV::FPR32RegClass; break; case MVT::f64: RC = &RISCV::FPR64RegClass; break; } Register VReg = RegInfo.createVirtualRegister(RC); RegInfo.addLiveIn(VA.getLocReg(), VReg); Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); if (VA.getLocInfo() == CCValAssign::Indirect) return Val; return convertLocVTToValVT(DAG, Val, VA, DL); } static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, const CCValAssign &VA, const SDLoc &DL) { EVT LocVT = VA.getLocVT(); switch (VA.getLocInfo()) { default: llvm_unreachable("Unexpected CCValAssign::LocInfo"); case CCValAssign::Full: break; case CCValAssign::BCvt: if (VA.getLocVT() == MVT::i64 && VA.getValVT() == MVT::f32) { Val = DAG.getNode(RISCVISD::FMV_X_ANYEXTW_RV64, DL, MVT::i64, Val); break; } Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val); break; } return Val; } // The caller is responsible for loading the full value if the argument is // passed with CCValAssign::Indirect. static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL) { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); EVT LocVT = VA.getLocVT(); EVT ValVT = VA.getValVT(); EVT PtrVT = MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)); int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8, VA.getLocMemOffset(), /*Immutable=*/true); SDValue FIN = DAG.getFrameIndex(FI, PtrVT); SDValue Val; ISD::LoadExtType ExtType; switch (VA.getLocInfo()) { default: llvm_unreachable("Unexpected CCValAssign::LocInfo"); case CCValAssign::Full: case CCValAssign::Indirect: case CCValAssign::BCvt: ExtType = ISD::NON_EXTLOAD; break; } Val = DAG.getExtLoad( ExtType, DL, LocVT, Chain, FIN, MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT); return Val; } static SDValue unpackF64OnRV32DSoftABI(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, const SDLoc &DL) { assert(VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64 && "Unexpected VA"); MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); if (VA.isMemLoc()) { // f64 is passed on the stack. int FI = MFI.CreateFixedObject(8, VA.getLocMemOffset(), /*Immutable=*/true); SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); return DAG.getLoad(MVT::f64, DL, Chain, FIN, MachinePointerInfo::getFixedStack(MF, FI)); } assert(VA.isRegLoc() && "Expected register VA assignment"); Register LoVReg = RegInfo.createVirtualRegister(&RISCV::GPRRegClass); RegInfo.addLiveIn(VA.getLocReg(), LoVReg); SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32); SDValue Hi; if (VA.getLocReg() == RISCV::X17) { // Second half of f64 is passed on the stack. int FI = MFI.CreateFixedObject(4, 0, /*Immutable=*/true); SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN, MachinePointerInfo::getFixedStack(MF, FI)); } else { // Second half of f64 is passed in another GPR. Register HiVReg = RegInfo.createVirtualRegister(&RISCV::GPRRegClass); RegInfo.addLiveIn(VA.getLocReg() + 1, HiVReg); Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32); } return DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, Lo, Hi); } // FastCC has less than 1% performance improvement for some particular // benchmark. But theoretically, it may has benenfit for some cases. static bool CC_RISCV_FastCC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) { if (LocVT == MVT::i32 || LocVT == MVT::i64) { // X5 and X6 might be used for save-restore libcall. static const MCPhysReg GPRList[] = { RISCV::X10, RISCV::X11, RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17, RISCV::X7, RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31}; if (unsigned Reg = State.AllocateReg(GPRList)) { State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); return false; } } if (LocVT == MVT::f32) { static const MCPhysReg FPR32List[] = { RISCV::F10_F, RISCV::F11_F, RISCV::F12_F, RISCV::F13_F, RISCV::F14_F, RISCV::F15_F, RISCV::F16_F, RISCV::F17_F, RISCV::F0_F, RISCV::F1_F, RISCV::F2_F, RISCV::F3_F, RISCV::F4_F, RISCV::F5_F, RISCV::F6_F, RISCV::F7_F, RISCV::F28_F, RISCV::F29_F, RISCV::F30_F, RISCV::F31_F}; if (unsigned Reg = State.AllocateReg(FPR32List)) { State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); return false; } } if (LocVT == MVT::f64) { static const MCPhysReg FPR64List[] = { RISCV::F10_D, RISCV::F11_D, RISCV::F12_D, RISCV::F13_D, RISCV::F14_D, RISCV::F15_D, RISCV::F16_D, RISCV::F17_D, RISCV::F0_D, RISCV::F1_D, RISCV::F2_D, RISCV::F3_D, RISCV::F4_D, RISCV::F5_D, RISCV::F6_D, RISCV::F7_D, RISCV::F28_D, RISCV::F29_D, RISCV::F30_D, RISCV::F31_D}; if (unsigned Reg = State.AllocateReg(FPR64List)) { State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); return false; } } if (LocVT == MVT::i32 || LocVT == MVT::f32) { unsigned Offset4 = State.AllocateStack(4, 4); State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset4, LocVT, LocInfo)); return false; } if (LocVT == MVT::i64 || LocVT == MVT::f64) { unsigned Offset5 = State.AllocateStack(8, 8); State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset5, LocVT, LocInfo)); return false; } return true; // CC didn't match. } // Transform physical registers into virtual registers. SDValue RISCVTargetLowering::LowerFormalArguments( SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Ins, const SDLoc &DL, SelectionDAG &DAG, SmallVectorImpl &InVals) const { switch (CallConv) { default: report_fatal_error("Unsupported calling convention"); case CallingConv::C: case CallingConv::Fast: break; } MachineFunction &MF = DAG.getMachineFunction(); const Function &Func = MF.getFunction(); if (Func.hasFnAttribute("interrupt")) { if (!Func.arg_empty()) report_fatal_error( "Functions with the interrupt attribute cannot have arguments!"); StringRef Kind = MF.getFunction().getFnAttribute("interrupt").getValueAsString(); if (!(Kind == "user" || Kind == "supervisor" || Kind == "machine")) report_fatal_error( "Function interrupt attribute argument not supported!"); } EVT PtrVT = getPointerTy(DAG.getDataLayout()); MVT XLenVT = Subtarget.getXLenVT(); unsigned XLenInBytes = Subtarget.getXLen() / 8; // Used with vargs to acumulate store chains. std::vector OutChains; // Assign locations to all of the incoming arguments. SmallVector ArgLocs; CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); if (CallConv == CallingConv::Fast) CCInfo.AnalyzeFormalArguments(Ins, CC_RISCV_FastCC); else analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false); for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue ArgValue; // Passing f64 on RV32D with a soft float ABI must be handled as a special // case. if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) ArgValue = unpackF64OnRV32DSoftABI(DAG, Chain, VA, DL); else if (VA.isRegLoc()) ArgValue = unpackFromRegLoc(DAG, Chain, VA, DL); else ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); if (VA.getLocInfo() == CCValAssign::Indirect) { // If the original argument was split and passed by reference (e.g. i128 // on RV32), we need to load all parts of it here (using the same // address). InVals.push_back(DAG.getLoad(VA.getValVT(), DL, Chain, ArgValue, MachinePointerInfo())); unsigned ArgIndex = Ins[i].OrigArgIndex; assert(Ins[i].PartOffset == 0); while (i + 1 != e && Ins[i + 1].OrigArgIndex == ArgIndex) { CCValAssign &PartVA = ArgLocs[i + 1]; unsigned PartOffset = Ins[i + 1].PartOffset; SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, ArgValue, DAG.getIntPtrConstant(PartOffset, DL)); InVals.push_back(DAG.getLoad(PartVA.getValVT(), DL, Chain, Address, MachinePointerInfo())); ++i; } continue; } InVals.push_back(ArgValue); } if (IsVarArg) { ArrayRef ArgRegs = makeArrayRef(ArgGPRs); unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); const TargetRegisterClass *RC = &RISCV::GPRRegClass; MachineFrameInfo &MFI = MF.getFrameInfo(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); RISCVMachineFunctionInfo *RVFI = MF.getInfo(); // Offset of the first variable argument from stack pointer, and size of // the vararg save area. For now, the varargs save area is either zero or // large enough to hold a0-a7. int VaArgOffset, VarArgsSaveSize; // If all registers are allocated, then all varargs must be passed on the // stack and we don't need to save any argregs. if (ArgRegs.size() == Idx) { VaArgOffset = CCInfo.getNextStackOffset(); VarArgsSaveSize = 0; } else { VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx); VaArgOffset = -VarArgsSaveSize; } // Record the frame index of the first variable argument // which is a value necessary to VASTART. int FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); RVFI->setVarArgsFrameIndex(FI); // If saving an odd number of registers then create an extra stack slot to // ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures // offsets to even-numbered registered remain 2*XLEN-aligned. if (Idx % 2) { MFI.CreateFixedObject(XLenInBytes, VaArgOffset - (int)XLenInBytes, true); VarArgsSaveSize += XLenInBytes; } // Copy the integer registers that may have been used for passing varargs // to the vararg save area. for (unsigned I = Idx; I < ArgRegs.size(); ++I, VaArgOffset += XLenInBytes) { const Register Reg = RegInfo.createVirtualRegister(RC); RegInfo.addLiveIn(ArgRegs[I], Reg); SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, XLenVT); FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, MachinePointerInfo::getFixedStack(MF, FI)); cast(Store.getNode()) ->getMemOperand() ->setValue((Value *)nullptr); OutChains.push_back(Store); } RVFI->setVarArgsSaveSize(VarArgsSaveSize); } // All stores are grouped in one node to allow the matching between // the size of Ins and InVals. This only happens for vararg functions. if (!OutChains.empty()) { OutChains.push_back(Chain); Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); } return Chain; } /// isEligibleForTailCallOptimization - Check whether the call is eligible /// for tail call optimization. /// Note: This is modelled after ARM's IsEligibleForTailCallOptimization. bool RISCVTargetLowering::isEligibleForTailCallOptimization( CCState &CCInfo, CallLoweringInfo &CLI, MachineFunction &MF, const SmallVector &ArgLocs) const { auto &Callee = CLI.Callee; auto CalleeCC = CLI.CallConv; auto &Outs = CLI.Outs; auto &Caller = MF.getFunction(); auto CallerCC = Caller.getCallingConv(); // Exception-handling functions need a special set of instructions to // indicate a return to the hardware. Tail-calling another function would // probably break this. // TODO: The "interrupt" attribute isn't currently defined by RISC-V. This // should be expanded as new function attributes are introduced. if (Caller.hasFnAttribute("interrupt")) return false; // Do not tail call opt if the stack is used to pass parameters. if (CCInfo.getNextStackOffset() != 0) return false; // Do not tail call opt if any parameters need to be passed indirectly. // Since long doubles (fp128) and i128 are larger than 2*XLEN, they are // passed indirectly. So the address of the value will be passed in a // register, or if not available, then the address is put on the stack. In // order to pass indirectly, space on the stack often needs to be allocated // in order to store the value. In this case the CCInfo.getNextStackOffset() // != 0 check is not enough and we need to check if any CCValAssign ArgsLocs // are passed CCValAssign::Indirect. for (auto &VA : ArgLocs) if (VA.getLocInfo() == CCValAssign::Indirect) return false; // Do not tail call opt if either caller or callee uses struct return // semantics. auto IsCallerStructRet = Caller.hasStructRetAttr(); auto IsCalleeStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet(); if (IsCallerStructRet || IsCalleeStructRet) return false; // Externally-defined functions with weak linkage should not be // tail-called. The behaviour of branch instructions in this situation (as // used for tail calls) is implementation-defined, so we cannot rely on the // linker replacing the tail call with a return. if (GlobalAddressSDNode *G = dyn_cast(Callee)) { const GlobalValue *GV = G->getGlobal(); if (GV->hasExternalWeakLinkage()) return false; } // The callee has to preserve all registers the caller needs to preserve. const RISCVRegisterInfo *TRI = Subtarget.getRegisterInfo(); const uint32_t *CallerPreserved = TRI->getCallPreservedMask(MF, CallerCC); if (CalleeCC != CallerCC) { const uint32_t *CalleePreserved = TRI->getCallPreservedMask(MF, CalleeCC); if (!TRI->regmaskSubsetEqual(CallerPreserved, CalleePreserved)) return false; } // Byval parameters hand the function a pointer directly into the stack area // we want to reuse during a tail call. Working around this *is* possible // but less efficient and uglier in LowerCall. for (auto &Arg : Outs) if (Arg.Flags.isByVal()) return false; return true; } // Lower a call to a callseq_start + CALL + callseq_end chain, and add input // and output parameter nodes. SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { SelectionDAG &DAG = CLI.DAG; SDLoc &DL = CLI.DL; SmallVectorImpl &Outs = CLI.Outs; SmallVectorImpl &OutVals = CLI.OutVals; SmallVectorImpl &Ins = CLI.Ins; SDValue Chain = CLI.Chain; SDValue Callee = CLI.Callee; bool &IsTailCall = CLI.IsTailCall; CallingConv::ID CallConv = CLI.CallConv; bool IsVarArg = CLI.IsVarArg; EVT PtrVT = getPointerTy(DAG.getDataLayout()); MVT XLenVT = Subtarget.getXLenVT(); MachineFunction &MF = DAG.getMachineFunction(); // Analyze the operands of the call, assigning locations to each operand. SmallVector ArgLocs; CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); if (CallConv == CallingConv::Fast) ArgCCInfo.AnalyzeCallOperands(Outs, CC_RISCV_FastCC); else analyzeOutputArgs(MF, ArgCCInfo, Outs, /*IsRet=*/false, &CLI); // Check if it's really possible to do a tail call. if (IsTailCall) IsTailCall = isEligibleForTailCallOptimization(ArgCCInfo, CLI, MF, ArgLocs); if (IsTailCall) ++NumTailCalls; else if (CLI.CS && CLI.CS.isMustTailCall()) report_fatal_error("failed to perform tail call elimination on a call " "site marked musttail"); // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = ArgCCInfo.getNextStackOffset(); // Create local copies for byval args SmallVector ByValArgs; for (unsigned i = 0, e = Outs.size(); i != e; ++i) { ISD::ArgFlagsTy Flags = Outs[i].Flags; if (!Flags.isByVal()) continue; SDValue Arg = OutVals[i]; unsigned Size = Flags.getByValSize(); unsigned Align = Flags.getByValAlign(); int FI = MF.getFrameInfo().CreateStackObject(Size, Align, /*isSS=*/false); SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); SDValue SizeNode = DAG.getConstant(Size, DL, XLenVT); Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Align, /*IsVolatile=*/false, /*AlwaysInline=*/false, IsTailCall, MachinePointerInfo(), MachinePointerInfo()); ByValArgs.push_back(FIPtr); } if (!IsTailCall) Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); // Copy argument values to their designated locations. SmallVector, 8> RegsToPass; SmallVector MemOpChains; SDValue StackPtr; for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue ArgValue = OutVals[i]; ISD::ArgFlagsTy Flags = Outs[i].Flags; // Handle passing f64 on RV32D with a soft float ABI as a special case. bool IsF64OnRV32DSoftABI = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64; if (IsF64OnRV32DSoftABI && VA.isRegLoc()) { SDValue SplitF64 = DAG.getNode( RISCVISD::SplitF64, DL, DAG.getVTList(MVT::i32, MVT::i32), ArgValue); SDValue Lo = SplitF64.getValue(0); SDValue Hi = SplitF64.getValue(1); Register RegLo = VA.getLocReg(); RegsToPass.push_back(std::make_pair(RegLo, Lo)); if (RegLo == RISCV::X17) { // Second half of f64 is passed on the stack. // Work out the address of the stack slot. if (!StackPtr.getNode()) StackPtr = DAG.getCopyFromReg(Chain, DL, RISCV::X2, PtrVT); // Emit the store. MemOpChains.push_back( DAG.getStore(Chain, DL, Hi, StackPtr, MachinePointerInfo())); } else { // Second half of f64 is passed in another GPR. assert(RegLo < RISCV::X31 && "Invalid register pair"); Register RegHigh = RegLo + 1; RegsToPass.push_back(std::make_pair(RegHigh, Hi)); } continue; } // IsF64OnRV32DSoftABI && VA.isMemLoc() is handled below in the same way // as any other MemLoc. // Promote the value if needed. // For now, only handle fully promoted and indirect arguments. if (VA.getLocInfo() == CCValAssign::Indirect) { // Store the argument in a stack slot and pass its address. SDValue SpillSlot = DAG.CreateStackTemporary(Outs[i].ArgVT); int FI = cast(SpillSlot)->getIndex(); MemOpChains.push_back( DAG.getStore(Chain, DL, ArgValue, SpillSlot, MachinePointerInfo::getFixedStack(MF, FI))); // If the original argument was split (e.g. i128), we need // to store all parts of it here (and pass just one address). unsigned ArgIndex = Outs[i].OrigArgIndex; assert(Outs[i].PartOffset == 0); while (i + 1 != e && Outs[i + 1].OrigArgIndex == ArgIndex) { SDValue PartValue = OutVals[i + 1]; unsigned PartOffset = Outs[i + 1].PartOffset; SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, SpillSlot, DAG.getIntPtrConstant(PartOffset, DL)); MemOpChains.push_back( DAG.getStore(Chain, DL, PartValue, Address, MachinePointerInfo::getFixedStack(MF, FI))); ++i; } ArgValue = SpillSlot; } else { ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL); } // Use local copy if it is a byval arg. if (Flags.isByVal()) ArgValue = ByValArgs[j++]; if (VA.isRegLoc()) { // Queue up the argument copies and emit them at the end. RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); } else { assert(VA.isMemLoc() && "Argument not register or memory"); assert(!IsTailCall && "Tail call not allowed if stack is used " "for passing parameters"); // Work out the address of the stack slot. if (!StackPtr.getNode()) StackPtr = DAG.getCopyFromReg(Chain, DL, RISCV::X2, PtrVT); SDValue Address = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); // Emit the store. MemOpChains.push_back( DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); } } // Join the stores, which are independent of one another. if (!MemOpChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); SDValue Glue; // Build a sequence of copy-to-reg nodes, chained and glued together. for (auto &Reg : RegsToPass) { Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue); Glue = Chain.getValue(1); } // Validate that none of the argument registers have been marked as // reserved, if so report an error. Do the same for the return address if this // is not a tailcall. validateCCReservedRegs(RegsToPass, MF); if (!IsTailCall && MF.getSubtarget().isRegisterReservedByUser(RISCV::X1)) MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ MF.getFunction(), "Return address register required, but has been reserved."}); // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't // split it and then direct call can be matched by PseudoCALL. if (GlobalAddressSDNode *S = dyn_cast(Callee)) { const GlobalValue *GV = S->getGlobal(); unsigned OpFlags = RISCVII::MO_CALL; if (!getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) OpFlags = RISCVII::MO_PLT; Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags); } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { unsigned OpFlags = RISCVII::MO_CALL; if (!getTargetMachine().shouldAssumeDSOLocal(*MF.getFunction().getParent(), nullptr)) OpFlags = RISCVII::MO_PLT; Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags); } // The first call operand is the chain and the second is the target address. SmallVector 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())); if (!IsTailCall) { // Add a register mask operand representing the call-preserved registers. const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); assert(Mask && "Missing call preserved mask for calling convention"); Ops.push_back(DAG.getRegisterMask(Mask)); } // Glue the call to the argument copies, if any. if (Glue.getNode()) Ops.push_back(Glue); // Emit the call. SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); if (IsTailCall) { MF.getFrameInfo().setHasTailCall(); return DAG.getNode(RISCVISD::TAIL, DL, NodeTys, Ops); } Chain = DAG.getNode(RISCVISD::CALL, DL, NodeTys, Ops); Glue = Chain.getValue(1); // Mark the end of the call, which is glued to the call itself. Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, DL, PtrVT, true), DAG.getConstant(0, DL, PtrVT, true), Glue, DL); Glue = Chain.getValue(1); // Assign locations to each value returned by this call. SmallVector RVLocs; CCState RetCCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); analyzeInputArgs(MF, RetCCInfo, Ins, /*IsRet=*/true); // Copy all of the result registers out of their specified physreg. for (auto &VA : RVLocs) { // Copy the value out SDValue RetValue = DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue); // Glue the RetValue to the end of the call sequence Chain = RetValue.getValue(1); Glue = RetValue.getValue(2); if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) { assert(VA.getLocReg() == ArgGPRs[0] && "Unexpected reg assignment"); SDValue RetValue2 = DAG.getCopyFromReg(Chain, DL, ArgGPRs[1], MVT::i32, Glue); Chain = RetValue2.getValue(1); Glue = RetValue2.getValue(2); RetValue = DAG.getNode(RISCVISD::BuildPairF64, DL, MVT::f64, RetValue, RetValue2); } RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL); InVals.push_back(RetValue); } return Chain; } bool RISCVTargetLowering::CanLowerReturn( CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, const SmallVectorImpl &Outs, LLVMContext &Context) const { SmallVector RVLocs; CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context); for (unsigned i = 0, e = Outs.size(); i != e; ++i) { MVT VT = Outs[i].VT; ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; RISCVABI::ABI ABI = MF.getSubtarget().getTargetABI(); if (CC_RISCV(MF.getDataLayout(), ABI, i, VT, VT, CCValAssign::Full, ArgFlags, CCInfo, /*IsFixed=*/true, /*IsRet=*/true, nullptr)) return false; } return true; } SDValue RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { const MachineFunction &MF = DAG.getMachineFunction(); const RISCVSubtarget &STI = MF.getSubtarget(); // Stores the assignment of the return value to a location. SmallVector RVLocs; // Info about the registers and stack slot. CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, *DAG.getContext()); analyzeOutputArgs(DAG.getMachineFunction(), CCInfo, Outs, /*IsRet=*/true, nullptr); SDValue Glue; SmallVector RetOps(1, Chain); // Copy the result values into the output registers. for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { SDValue Val = OutVals[i]; CCValAssign &VA = RVLocs[i]; assert(VA.isRegLoc() && "Can only return in registers!"); if (VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64) { // Handle returning f64 on RV32D with a soft float ABI. assert(VA.isRegLoc() && "Expected return via registers"); SDValue SplitF64 = DAG.getNode(RISCVISD::SplitF64, DL, DAG.getVTList(MVT::i32, MVT::i32), Val); SDValue Lo = SplitF64.getValue(0); SDValue Hi = SplitF64.getValue(1); Register RegLo = VA.getLocReg(); assert(RegLo < RISCV::X31 && "Invalid register pair"); Register RegHi = RegLo + 1; if (STI.isRegisterReservedByUser(RegLo) || STI.isRegisterReservedByUser(RegHi)) MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ MF.getFunction(), "Return value register required, but has been reserved."}); Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue); Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(RegLo, MVT::i32)); Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue); Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(RegHi, MVT::i32)); } else { // Handle a 'normal' return. Val = convertValVTToLocVT(DAG, Val, VA, DL); Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); if (STI.isRegisterReservedByUser(VA.getLocReg())) MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ MF.getFunction(), "Return value register required, but has been reserved."}); // Guarantee that all emitted copies are stuck together. Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); } } RetOps[0] = Chain; // Update chain. // Add the glue node if we have it. if (Glue.getNode()) { RetOps.push_back(Glue); } // Interrupt service routines use different return instructions. const Function &Func = DAG.getMachineFunction().getFunction(); if (Func.hasFnAttribute("interrupt")) { if (!Func.getReturnType()->isVoidTy()) report_fatal_error( "Functions with the interrupt attribute must have void return type!"); MachineFunction &MF = DAG.getMachineFunction(); StringRef Kind = MF.getFunction().getFnAttribute("interrupt").getValueAsString(); unsigned RetOpc; if (Kind == "user") RetOpc = RISCVISD::URET_FLAG; else if (Kind == "supervisor") RetOpc = RISCVISD::SRET_FLAG; else RetOpc = RISCVISD::MRET_FLAG; return DAG.getNode(RetOpc, DL, MVT::Other, RetOps); } return DAG.getNode(RISCVISD::RET_FLAG, DL, MVT::Other, RetOps); } void RISCVTargetLowering::validateCCReservedRegs( const SmallVectorImpl> &Regs, MachineFunction &MF) const { const Function &F = MF.getFunction(); const RISCVSubtarget &STI = MF.getSubtarget(); if (std::any_of(std::begin(Regs), std::end(Regs), [&STI](auto Reg) { return STI.isRegisterReservedByUser(Reg.first); })) F.getContext().diagnose(DiagnosticInfoUnsupported{ F, "Argument register required, but has been reserved."}); } const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { switch ((RISCVISD::NodeType)Opcode) { case RISCVISD::FIRST_NUMBER: break; case RISCVISD::RET_FLAG: return "RISCVISD::RET_FLAG"; case RISCVISD::URET_FLAG: return "RISCVISD::URET_FLAG"; case RISCVISD::SRET_FLAG: return "RISCVISD::SRET_FLAG"; case RISCVISD::MRET_FLAG: return "RISCVISD::MRET_FLAG"; case RISCVISD::CALL: return "RISCVISD::CALL"; case RISCVISD::SELECT_CC: return "RISCVISD::SELECT_CC"; case RISCVISD::BuildPairF64: return "RISCVISD::BuildPairF64"; case RISCVISD::SplitF64: return "RISCVISD::SplitF64"; case RISCVISD::TAIL: return "RISCVISD::TAIL"; case RISCVISD::SLLW: return "RISCVISD::SLLW"; case RISCVISD::SRAW: return "RISCVISD::SRAW"; case RISCVISD::SRLW: return "RISCVISD::SRLW"; case RISCVISD::DIVW: return "RISCVISD::DIVW"; case RISCVISD::DIVUW: return "RISCVISD::DIVUW"; case RISCVISD::REMUW: return "RISCVISD::REMUW"; case RISCVISD::FMV_W_X_RV64: return "RISCVISD::FMV_W_X_RV64"; case RISCVISD::FMV_X_ANYEXTW_RV64: return "RISCVISD::FMV_X_ANYEXTW_RV64"; case RISCVISD::READ_CYCLE_WIDE: return "RISCVISD::READ_CYCLE_WIDE"; } return nullptr; } /// getConstraintType - Given a constraint letter, return the type of /// constraint it is for this target. RISCVTargetLowering::ConstraintType RISCVTargetLowering::getConstraintType(StringRef Constraint) const { if (Constraint.size() == 1) { switch (Constraint[0]) { default: break; case 'f': return C_RegisterClass; case 'I': case 'J': case 'K': return C_Immediate; case 'A': return C_Memory; } } return TargetLowering::getConstraintType(Constraint); } std::pair RISCVTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { // First, see if this is a constraint that directly corresponds to a // RISCV register class. if (Constraint.size() == 1) { switch (Constraint[0]) { case 'r': return std::make_pair(0U, &RISCV::GPRRegClass); case 'f': if (Subtarget.hasStdExtF() && VT == MVT::f32) return std::make_pair(0U, &RISCV::FPR32RegClass); if (Subtarget.hasStdExtD() && VT == MVT::f64) return std::make_pair(0U, &RISCV::FPR64RegClass); break; default: break; } } // Clang will correctly decode the usage of register name aliases into their // official names. However, other frontends like `rustc` do not. This allows // users of these frontends to use the ABI names for registers in LLVM-style // register constraints. Register XRegFromAlias = StringSwitch(Constraint.lower()) .Case("{zero}", RISCV::X0) .Case("{ra}", RISCV::X1) .Case("{sp}", RISCV::X2) .Case("{gp}", RISCV::X3) .Case("{tp}", RISCV::X4) .Case("{t0}", RISCV::X5) .Case("{t1}", RISCV::X6) .Case("{t2}", RISCV::X7) .Cases("{s0}", "{fp}", RISCV::X8) .Case("{s1}", RISCV::X9) .Case("{a0}", RISCV::X10) .Case("{a1}", RISCV::X11) .Case("{a2}", RISCV::X12) .Case("{a3}", RISCV::X13) .Case("{a4}", RISCV::X14) .Case("{a5}", RISCV::X15) .Case("{a6}", RISCV::X16) .Case("{a7}", RISCV::X17) .Case("{s2}", RISCV::X18) .Case("{s3}", RISCV::X19) .Case("{s4}", RISCV::X20) .Case("{s5}", RISCV::X21) .Case("{s6}", RISCV::X22) .Case("{s7}", RISCV::X23) .Case("{s8}", RISCV::X24) .Case("{s9}", RISCV::X25) .Case("{s10}", RISCV::X26) .Case("{s11}", RISCV::X27) .Case("{t3}", RISCV::X28) .Case("{t4}", RISCV::X29) .Case("{t5}", RISCV::X30) .Case("{t6}", RISCV::X31) .Default(RISCV::NoRegister); if (XRegFromAlias != RISCV::NoRegister) return std::make_pair(XRegFromAlias, &RISCV::GPRRegClass); // Since TargetLowering::getRegForInlineAsmConstraint uses the name of the // TableGen record rather than the AsmName to choose registers for InlineAsm // constraints, plus we want to match those names to the widest floating point // register type available, manually select floating point registers here. // // The second case is the ABI name of the register, so that frontends can also // use the ABI names in register constraint lists. if (Subtarget.hasStdExtF() || Subtarget.hasStdExtD()) { std::pair FReg = StringSwitch>(Constraint.lower()) .Cases("{f0}", "{ft0}", {RISCV::F0_F, RISCV::F0_D}) .Cases("{f1}", "{ft1}", {RISCV::F1_F, RISCV::F1_D}) .Cases("{f2}", "{ft2}", {RISCV::F2_F, RISCV::F2_D}) .Cases("{f3}", "{ft3}", {RISCV::F3_F, RISCV::F3_D}) .Cases("{f4}", "{ft4}", {RISCV::F4_F, RISCV::F4_D}) .Cases("{f5}", "{ft5}", {RISCV::F5_F, RISCV::F5_D}) .Cases("{f6}", "{ft6}", {RISCV::F6_F, RISCV::F6_D}) .Cases("{f7}", "{ft7}", {RISCV::F7_F, RISCV::F7_D}) .Cases("{f8}", "{fs0}", {RISCV::F8_F, RISCV::F8_D}) .Cases("{f9}", "{fs1}", {RISCV::F9_F, RISCV::F9_D}) .Cases("{f10}", "{fa0}", {RISCV::F10_F, RISCV::F10_D}) .Cases("{f11}", "{fa1}", {RISCV::F11_F, RISCV::F11_D}) .Cases("{f12}", "{fa2}", {RISCV::F12_F, RISCV::F12_D}) .Cases("{f13}", "{fa3}", {RISCV::F13_F, RISCV::F13_D}) .Cases("{f14}", "{fa4}", {RISCV::F14_F, RISCV::F14_D}) .Cases("{f15}", "{fa5}", {RISCV::F15_F, RISCV::F15_D}) .Cases("{f16}", "{fa6}", {RISCV::F16_F, RISCV::F16_D}) .Cases("{f17}", "{fa7}", {RISCV::F17_F, RISCV::F17_D}) .Cases("{f18}", "{fs2}", {RISCV::F18_F, RISCV::F18_D}) .Cases("{f19}", "{fs3}", {RISCV::F19_F, RISCV::F19_D}) .Cases("{f20}", "{fs4}", {RISCV::F20_F, RISCV::F20_D}) .Cases("{f21}", "{fs5}", {RISCV::F21_F, RISCV::F21_D}) .Cases("{f22}", "{fs6}", {RISCV::F22_F, RISCV::F22_D}) .Cases("{f23}", "{fs7}", {RISCV::F23_F, RISCV::F23_D}) .Cases("{f24}", "{fs8}", {RISCV::F24_F, RISCV::F24_D}) .Cases("{f25}", "{fs9}", {RISCV::F25_F, RISCV::F25_D}) .Cases("{f26}", "{fs10}", {RISCV::F26_F, RISCV::F26_D}) .Cases("{f27}", "{fs11}", {RISCV::F27_F, RISCV::F27_D}) .Cases("{f28}", "{ft8}", {RISCV::F28_F, RISCV::F28_D}) .Cases("{f29}", "{ft9}", {RISCV::F29_F, RISCV::F29_D}) .Cases("{f30}", "{ft10}", {RISCV::F30_F, RISCV::F30_D}) .Cases("{f31}", "{ft11}", {RISCV::F31_F, RISCV::F31_D}) .Default({RISCV::NoRegister, RISCV::NoRegister}); if (FReg.first != RISCV::NoRegister) return Subtarget.hasStdExtD() ? std::make_pair(FReg.second, &RISCV::FPR64RegClass) : std::make_pair(FReg.first, &RISCV::FPR32RegClass); } return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); } unsigned RISCVTargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const { // Currently only support length 1 constraints. if (ConstraintCode.size() == 1) { switch (ConstraintCode[0]) { case 'A': return InlineAsm::Constraint_A; default: break; } } return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); } void RISCVTargetLowering::LowerAsmOperandForConstraint( SDValue Op, std::string &Constraint, std::vector &Ops, SelectionDAG &DAG) const { // Currently only support length 1 constraints. if (Constraint.length() == 1) { switch (Constraint[0]) { case 'I': // Validate & create a 12-bit signed immediate operand. if (auto *C = dyn_cast(Op)) { uint64_t CVal = C->getSExtValue(); if (isInt<12>(CVal)) Ops.push_back( DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT())); } return; case 'J': // Validate & create an integer zero operand. if (auto *C = dyn_cast(Op)) if (C->getZExtValue() == 0) Ops.push_back( DAG.getTargetConstant(0, SDLoc(Op), Subtarget.getXLenVT())); return; case 'K': // Validate & create a 5-bit unsigned immediate operand. if (auto *C = dyn_cast(Op)) { uint64_t CVal = C->getZExtValue(); if (isUInt<5>(CVal)) Ops.push_back( DAG.getTargetConstant(CVal, SDLoc(Op), Subtarget.getXLenVT())); } return; default: break; } } TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); } Instruction *RISCVTargetLowering::emitLeadingFence(IRBuilder<> &Builder, Instruction *Inst, AtomicOrdering Ord) const { if (isa(Inst) && Ord == AtomicOrdering::SequentiallyConsistent) return Builder.CreateFence(Ord); if (isa(Inst) && isReleaseOrStronger(Ord)) return Builder.CreateFence(AtomicOrdering::Release); return nullptr; } Instruction *RISCVTargetLowering::emitTrailingFence(IRBuilder<> &Builder, Instruction *Inst, AtomicOrdering Ord) const { if (isa(Inst) && isAcquireOrStronger(Ord)) return Builder.CreateFence(AtomicOrdering::Acquire); return nullptr; } TargetLowering::AtomicExpansionKind RISCVTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { // atomicrmw {fadd,fsub} must be expanded to use compare-exchange, as floating // point operations can't be used in an lr/sc sequence without breaking the // forward-progress guarantee. if (AI->isFloatingPointOperation()) return AtomicExpansionKind::CmpXChg; unsigned Size = AI->getType()->getPrimitiveSizeInBits(); if (Size == 8 || Size == 16) return AtomicExpansionKind::MaskedIntrinsic; return AtomicExpansionKind::None; } static Intrinsic::ID getIntrinsicForMaskedAtomicRMWBinOp(unsigned XLen, AtomicRMWInst::BinOp BinOp) { if (XLen == 32) { switch (BinOp) { default: llvm_unreachable("Unexpected AtomicRMW BinOp"); case AtomicRMWInst::Xchg: return Intrinsic::riscv_masked_atomicrmw_xchg_i32; case AtomicRMWInst::Add: return Intrinsic::riscv_masked_atomicrmw_add_i32; case AtomicRMWInst::Sub: return Intrinsic::riscv_masked_atomicrmw_sub_i32; case AtomicRMWInst::Nand: return Intrinsic::riscv_masked_atomicrmw_nand_i32; case AtomicRMWInst::Max: return Intrinsic::riscv_masked_atomicrmw_max_i32; case AtomicRMWInst::Min: return Intrinsic::riscv_masked_atomicrmw_min_i32; case AtomicRMWInst::UMax: return Intrinsic::riscv_masked_atomicrmw_umax_i32; case AtomicRMWInst::UMin: return Intrinsic::riscv_masked_atomicrmw_umin_i32; } } if (XLen == 64) { switch (BinOp) { default: llvm_unreachable("Unexpected AtomicRMW BinOp"); case AtomicRMWInst::Xchg: return Intrinsic::riscv_masked_atomicrmw_xchg_i64; case AtomicRMWInst::Add: return Intrinsic::riscv_masked_atomicrmw_add_i64; case AtomicRMWInst::Sub: return Intrinsic::riscv_masked_atomicrmw_sub_i64; case AtomicRMWInst::Nand: return Intrinsic::riscv_masked_atomicrmw_nand_i64; case AtomicRMWInst::Max: return Intrinsic::riscv_masked_atomicrmw_max_i64; case AtomicRMWInst::Min: return Intrinsic::riscv_masked_atomicrmw_min_i64; case AtomicRMWInst::UMax: return Intrinsic::riscv_masked_atomicrmw_umax_i64; case AtomicRMWInst::UMin: return Intrinsic::riscv_masked_atomicrmw_umin_i64; } } llvm_unreachable("Unexpected XLen\n"); } Value *RISCVTargetLowering::emitMaskedAtomicRMWIntrinsic( IRBuilder<> &Builder, AtomicRMWInst *AI, Value *AlignedAddr, Value *Incr, Value *Mask, Value *ShiftAmt, AtomicOrdering Ord) const { unsigned XLen = Subtarget.getXLen(); Value *Ordering = Builder.getIntN(XLen, static_cast(AI->getOrdering())); Type *Tys[] = {AlignedAddr->getType()}; Function *LrwOpScwLoop = Intrinsic::getDeclaration( AI->getModule(), getIntrinsicForMaskedAtomicRMWBinOp(XLen, AI->getOperation()), Tys); if (XLen == 64) { Incr = Builder.CreateSExt(Incr, Builder.getInt64Ty()); Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); ShiftAmt = Builder.CreateSExt(ShiftAmt, Builder.getInt64Ty()); } Value *Result; // Must pass the shift amount needed to sign extend the loaded value prior // to performing a signed comparison for min/max. ShiftAmt is the number of // bits to shift the value into position. Pass XLen-ShiftAmt-ValWidth, which // is the number of bits to left+right shift the value in order to // sign-extend. if (AI->getOperation() == AtomicRMWInst::Min || AI->getOperation() == AtomicRMWInst::Max) { const DataLayout &DL = AI->getModule()->getDataLayout(); unsigned ValWidth = DL.getTypeStoreSizeInBits(AI->getValOperand()->getType()); Value *SextShamt = Builder.CreateSub(Builder.getIntN(XLen, XLen - ValWidth), ShiftAmt); Result = Builder.CreateCall(LrwOpScwLoop, {AlignedAddr, Incr, Mask, SextShamt, Ordering}); } else { Result = Builder.CreateCall(LrwOpScwLoop, {AlignedAddr, Incr, Mask, Ordering}); } if (XLen == 64) Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); return Result; } TargetLowering::AtomicExpansionKind RISCVTargetLowering::shouldExpandAtomicCmpXchgInIR( AtomicCmpXchgInst *CI) const { unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits(); if (Size == 8 || Size == 16) return AtomicExpansionKind::MaskedIntrinsic; return AtomicExpansionKind::None; } Value *RISCVTargetLowering::emitMaskedAtomicCmpXchgIntrinsic( IRBuilder<> &Builder, AtomicCmpXchgInst *CI, Value *AlignedAddr, Value *CmpVal, Value *NewVal, Value *Mask, AtomicOrdering Ord) const { unsigned XLen = Subtarget.getXLen(); Value *Ordering = Builder.getIntN(XLen, static_cast(Ord)); Intrinsic::ID CmpXchgIntrID = Intrinsic::riscv_masked_cmpxchg_i32; if (XLen == 64) { CmpVal = Builder.CreateSExt(CmpVal, Builder.getInt64Ty()); NewVal = Builder.CreateSExt(NewVal, Builder.getInt64Ty()); Mask = Builder.CreateSExt(Mask, Builder.getInt64Ty()); CmpXchgIntrID = Intrinsic::riscv_masked_cmpxchg_i64; } Type *Tys[] = {AlignedAddr->getType()}; Function *MaskedCmpXchg = Intrinsic::getDeclaration(CI->getModule(), CmpXchgIntrID, Tys); Value *Result = Builder.CreateCall( MaskedCmpXchg, {AlignedAddr, CmpVal, NewVal, Mask, Ordering}); if (XLen == 64) Result = Builder.CreateTrunc(Result, Builder.getInt32Ty()); return Result; } unsigned RISCVTargetLowering::getExceptionPointerRegister( const Constant *PersonalityFn) const { return RISCV::X10; } unsigned RISCVTargetLowering::getExceptionSelectorRegister( const Constant *PersonalityFn) const { return RISCV::X11; } bool RISCVTargetLowering::shouldExtendTypeInLibCall(EVT Type) const { // Return false to suppress the unnecessary extensions if the LibCall // arguments or return value is f32 type for LP64 ABI. RISCVABI::ABI ABI = Subtarget.getTargetABI(); if (ABI == RISCVABI::ABI_LP64 && (Type == MVT::f32)) return false; return true; } #define GET_REGISTER_MATCHER #include "RISCVGenAsmMatcher.inc" Register RISCVTargetLowering::getRegisterByName(const char *RegName, LLT VT, const MachineFunction &MF) const { Register Reg = MatchRegisterAltName(RegName); if (Reg == RISCV::NoRegister) Reg = MatchRegisterName(RegName); if (Reg == RISCV::NoRegister) report_fatal_error( Twine("Invalid register name \"" + StringRef(RegName) + "\".")); BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF); if (!ReservedRegs.test(Reg) && !Subtarget.isRegisterReservedByUser(Reg)) report_fatal_error(Twine("Trying to obtain non-reserved register \"" + StringRef(RegName) + "\".")); return Reg; } Index: head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.cpp =================================================================== --- head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.cpp (nonexistent) +++ head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.cpp (revision 362719) @@ -0,0 +1,3 @@ +#include "DWPError.h" +using namespace llvm; +char DWPError::ID; Property changes on: head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.h =================================================================== --- head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.h (nonexistent) +++ head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.h (revision 362719) @@ -0,0 +1,23 @@ +#ifndef TOOLS_LLVM_DWP_DWPERROR +#define TOOLS_LLVM_DWP_DWPERROR + +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include + +namespace llvm { +class DWPError : public ErrorInfo { +public: + DWPError(std::string Info) : Info(std::move(Info)) {} + void log(raw_ostream &OS) const override { OS << Info; } + std::error_code convertToErrorCode() const override { + llvm_unreachable("Not implemented"); + } + static char ID; + +private: + std::string Info; +}; +} + +#endif Property changes on: head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPError.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPStringPool.h =================================================================== --- head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPStringPool.h (nonexistent) +++ head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPStringPool.h (revision 362719) @@ -0,0 +1,56 @@ +#ifndef TOOLS_LLVM_DWP_DWPSTRINGPOOL +#define TOOLS_LLVM_DWP_DWPSTRINGPOOL + +#include "llvm/ADT/DenseMap.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCStreamer.h" +#include + +namespace llvm { +class DWPStringPool { + + struct CStrDenseMapInfo { + static inline const char *getEmptyKey() { + return reinterpret_cast(~static_cast(0)); + } + static inline const char *getTombstoneKey() { + return reinterpret_cast(~static_cast(1)); + } + static unsigned getHashValue(const char *Val) { + assert(Val != getEmptyKey() && "Cannot hash the empty key!"); + assert(Val != getTombstoneKey() && "Cannot hash the tombstone key!"); + return (unsigned)hash_value(StringRef(Val)); + } + static bool isEqual(const char *LHS, const char *RHS) { + if (RHS == getEmptyKey()) + return LHS == getEmptyKey(); + if (RHS == getTombstoneKey()) + return LHS == getTombstoneKey(); + return strcmp(LHS, RHS) == 0; + } + }; + + MCStreamer &Out; + MCSection *Sec; + DenseMap Pool; + uint32_t Offset = 0; + +public: + DWPStringPool(MCStreamer &Out, MCSection *Sec) : Out(Out), Sec(Sec) {} + + uint32_t getOffset(const char *Str, unsigned Length) { + assert(strlen(Str) + 1 == Length && "Ensure length hint is correct"); + + auto Pair = Pool.insert(std::make_pair(Str, Offset)); + if (Pair.second) { + Out.SwitchSection(Sec); + Out.EmitBytes(StringRef(Str, Length)); + Offset += Length; + } + + return Pair.first->second; + } +}; +} + +#endif Property changes on: head/contrib/llvm-project/llvm/tools/llvm-dwp/DWPStringPool.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp =================================================================== --- head/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp (nonexistent) +++ head/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp (revision 362719) @@ -0,0 +1,749 @@ +//===-- llvm-dwp.cpp - Split DWARF merging tool for llvm ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A utility for merging DWARF 5 Split DWARF .dwo files into .dwp (DWARF +// package files). +// +//===----------------------------------------------------------------------===// +#include "DWPError.h" +#include "DWPStringPool.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.inc" +#include "llvm/Object/Decompressor.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; + +cl::OptionCategory DwpCategory("Specific Options"); +static cl::list InputFiles(cl::Positional, cl::ZeroOrMore, + cl::desc(""), + cl::cat(DwpCategory)); + +static cl::list ExecFilenames( + "e", cl::ZeroOrMore, + cl::desc("Specify the executable/library files to get the list of *.dwo from"), + cl::value_desc("filename"), cl::cat(DwpCategory)); + +static cl::opt OutputFilename(cl::Required, "o", + cl::desc("Specify the output file."), + cl::value_desc("filename"), + cl::cat(DwpCategory)); + +static void writeStringsAndOffsets(MCStreamer &Out, DWPStringPool &Strings, + MCSection *StrOffsetSection, + StringRef CurStrSection, + StringRef CurStrOffsetSection) { + // Could possibly produce an error or warning if one of these was non-null but + // the other was null. + if (CurStrSection.empty() || CurStrOffsetSection.empty()) + return; + + DenseMap OffsetRemapping; + + DataExtractor Data(CurStrSection, true, 0); + uint64_t LocalOffset = 0; + uint64_t PrevOffset = 0; + while (const char *s = Data.getCStr(&LocalOffset)) { + OffsetRemapping[PrevOffset] = + Strings.getOffset(s, LocalOffset - PrevOffset); + PrevOffset = LocalOffset; + } + + Data = DataExtractor(CurStrOffsetSection, true, 0); + + Out.SwitchSection(StrOffsetSection); + + uint64_t Offset = 0; + uint64_t Size = CurStrOffsetSection.size(); + while (Offset < Size) { + auto OldOffset = Data.getU32(&Offset); + auto NewOffset = OffsetRemapping[OldOffset]; + Out.EmitIntValue(NewOffset, 4); + } +} + +static uint64_t getCUAbbrev(StringRef Abbrev, uint64_t AbbrCode) { + uint64_t CurCode; + uint64_t Offset = 0; + DataExtractor AbbrevData(Abbrev, true, 0); + while ((CurCode = AbbrevData.getULEB128(&Offset)) != AbbrCode) { + // Tag + AbbrevData.getULEB128(&Offset); + // DW_CHILDREN + AbbrevData.getU8(&Offset); + // Attributes + while (AbbrevData.getULEB128(&Offset) | AbbrevData.getULEB128(&Offset)) + ; + } + return Offset; +} + +struct CompileUnitIdentifiers { + uint64_t Signature = 0; + const char *Name = ""; + const char *DWOName = ""; +}; + +static Expected +getIndexedString(dwarf::Form Form, DataExtractor InfoData, + uint64_t &InfoOffset, StringRef StrOffsets, StringRef Str) { + if (Form == dwarf::DW_FORM_string) + return InfoData.getCStr(&InfoOffset); + if (Form != dwarf::DW_FORM_GNU_str_index) + return make_error( + "string field encoded without DW_FORM_string or DW_FORM_GNU_str_index"); + auto StrIndex = InfoData.getULEB128(&InfoOffset); + DataExtractor StrOffsetsData(StrOffsets, true, 0); + uint64_t StrOffsetsOffset = 4 * StrIndex; + uint64_t StrOffset = StrOffsetsData.getU32(&StrOffsetsOffset); + DataExtractor StrData(Str, true, 0); + return StrData.getCStr(&StrOffset); +} + +static Expected getCUIdentifiers(StringRef Abbrev, + StringRef Info, + StringRef StrOffsets, + StringRef Str) { + uint64_t Offset = 0; + DataExtractor InfoData(Info, true, 0); + dwarf::DwarfFormat Format = dwarf::DwarfFormat::DWARF32; + uint64_t Length = InfoData.getU32(&Offset); + // If the length is 0xffffffff, then this indictes that this is a DWARF 64 + // stream and the length is actually encoded into a 64 bit value that follows. + if (Length == 0xffffffffU) { + Format = dwarf::DwarfFormat::DWARF64; + Length = InfoData.getU64(&Offset); + } + uint16_t Version = InfoData.getU16(&Offset); + InfoData.getU32(&Offset); // Abbrev offset (should be zero) + uint8_t AddrSize = InfoData.getU8(&Offset); + + uint32_t AbbrCode = InfoData.getULEB128(&Offset); + + DataExtractor AbbrevData(Abbrev, true, 0); + uint64_t AbbrevOffset = getCUAbbrev(Abbrev, AbbrCode); + auto Tag = static_cast(AbbrevData.getULEB128(&AbbrevOffset)); + if (Tag != dwarf::DW_TAG_compile_unit) + return make_error("top level DIE is not a compile unit"); + // DW_CHILDREN + AbbrevData.getU8(&AbbrevOffset); + uint32_t Name; + dwarf::Form Form; + CompileUnitIdentifiers ID; + Optional Signature = None; + while ((Name = AbbrevData.getULEB128(&AbbrevOffset)) | + (Form = static_cast(AbbrevData.getULEB128(&AbbrevOffset))) && + (Name != 0 || Form != 0)) { + switch (Name) { + case dwarf::DW_AT_name: { + Expected EName = + getIndexedString(Form, InfoData, Offset, StrOffsets, Str); + if (!EName) + return EName.takeError(); + ID.Name = *EName; + break; + } + case dwarf::DW_AT_GNU_dwo_name: { + Expected EName = + getIndexedString(Form, InfoData, Offset, StrOffsets, Str); + if (!EName) + return EName.takeError(); + ID.DWOName = *EName; + break; + } + case dwarf::DW_AT_GNU_dwo_id: + Signature = InfoData.getU64(&Offset); + break; + default: + DWARFFormValue::skipValue(Form, InfoData, &Offset, + dwarf::FormParams({Version, AddrSize, Format})); + } + } + if (!Signature) + return make_error("compile unit missing dwo_id"); + ID.Signature = *Signature; + return ID; +} + +struct UnitIndexEntry { + DWARFUnitIndex::Entry::SectionContribution Contributions[8]; + std::string Name; + std::string DWOName; + StringRef DWPName; +}; + +static StringRef getSubsection(StringRef Section, + const DWARFUnitIndex::Entry &Entry, + DWARFSectionKind Kind) { + const auto *Off = Entry.getOffset(Kind); + if (!Off) + return StringRef(); + return Section.substr(Off->Offset, Off->Length); +} + +static void addAllTypesFromDWP( + MCStreamer &Out, MapVector &TypeIndexEntries, + const DWARFUnitIndex &TUIndex, MCSection *OutputTypes, StringRef Types, + const UnitIndexEntry &TUEntry, uint32_t &TypesOffset) { + Out.SwitchSection(OutputTypes); + for (const DWARFUnitIndex::Entry &E : TUIndex.getRows()) { + auto *I = E.getOffsets(); + if (!I) + continue; + auto P = TypeIndexEntries.insert(std::make_pair(E.getSignature(), TUEntry)); + if (!P.second) + continue; + auto &Entry = P.first->second; + // Zero out the debug_info contribution + Entry.Contributions[0] = {}; + for (auto Kind : TUIndex.getColumnKinds()) { + auto &C = Entry.Contributions[Kind - DW_SECT_INFO]; + C.Offset += I->Offset; + C.Length = I->Length; + ++I; + } + auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; + Out.EmitBytes(Types.substr( + C.Offset - TUEntry.Contributions[DW_SECT_TYPES - DW_SECT_INFO].Offset, + C.Length)); + C.Offset = TypesOffset; + TypesOffset += C.Length; + } +} + +static void addAllTypes(MCStreamer &Out, + MapVector &TypeIndexEntries, + MCSection *OutputTypes, + const std::vector &TypesSections, + const UnitIndexEntry &CUEntry, uint32_t &TypesOffset) { + for (StringRef Types : TypesSections) { + Out.SwitchSection(OutputTypes); + uint64_t Offset = 0; + DataExtractor Data(Types, true, 0); + while (Data.isValidOffset(Offset)) { + UnitIndexEntry Entry = CUEntry; + // Zero out the debug_info contribution + Entry.Contributions[0] = {}; + auto &C = Entry.Contributions[DW_SECT_TYPES - DW_SECT_INFO]; + C.Offset = TypesOffset; + auto PrevOffset = Offset; + // Length of the unit, including the 4 byte length field. + C.Length = Data.getU32(&Offset) + 4; + + Data.getU16(&Offset); // Version + Data.getU32(&Offset); // Abbrev offset + Data.getU8(&Offset); // Address size + auto Signature = Data.getU64(&Offset); + Offset = PrevOffset + C.Length; + + auto P = TypeIndexEntries.insert(std::make_pair(Signature, Entry)); + if (!P.second) + continue; + + Out.EmitBytes(Types.substr(PrevOffset, C.Length)); + TypesOffset += C.Length; + } + } +} + +static void +writeIndexTable(MCStreamer &Out, ArrayRef ContributionOffsets, + const MapVector &IndexEntries, + uint32_t DWARFUnitIndex::Entry::SectionContribution::*Field) { + for (const auto &E : IndexEntries) + for (size_t i = 0; i != array_lengthof(E.second.Contributions); ++i) + if (ContributionOffsets[i]) + Out.EmitIntValue(E.second.Contributions[i].*Field, 4); +} + +static void +writeIndex(MCStreamer &Out, MCSection *Section, + ArrayRef ContributionOffsets, + const MapVector &IndexEntries) { + if (IndexEntries.empty()) + return; + + unsigned Columns = 0; + for (auto &C : ContributionOffsets) + if (C) + ++Columns; + + std::vector Buckets(NextPowerOf2(3 * IndexEntries.size() / 2)); + uint64_t Mask = Buckets.size() - 1; + size_t i = 0; + for (const auto &P : IndexEntries) { + auto S = P.first; + auto H = S & Mask; + auto HP = ((S >> 32) & Mask) | 1; + while (Buckets[H]) { + assert(S != IndexEntries.begin()[Buckets[H] - 1].first && + "Duplicate unit"); + H = (H + HP) & Mask; + } + Buckets[H] = i + 1; + ++i; + } + + Out.SwitchSection(Section); + Out.EmitIntValue(2, 4); // Version + Out.EmitIntValue(Columns, 4); // Columns + Out.EmitIntValue(IndexEntries.size(), 4); // Num Units + Out.EmitIntValue(Buckets.size(), 4); // Num Buckets + + // Write the signatures. + for (const auto &I : Buckets) + Out.EmitIntValue(I ? IndexEntries.begin()[I - 1].first : 0, 8); + + // Write the indexes. + for (const auto &I : Buckets) + Out.EmitIntValue(I, 4); + + // Write the column headers (which sections will appear in the table) + for (size_t i = 0; i != ContributionOffsets.size(); ++i) + if (ContributionOffsets[i]) + Out.EmitIntValue(i + DW_SECT_INFO, 4); + + // Write the offsets. + writeIndexTable(Out, ContributionOffsets, IndexEntries, + &DWARFUnitIndex::Entry::SectionContribution::Offset); + + // Write the lengths. + writeIndexTable(Out, ContributionOffsets, IndexEntries, + &DWARFUnitIndex::Entry::SectionContribution::Length); +} + +std::string buildDWODescription(StringRef Name, StringRef DWPName, StringRef DWOName) { + std::string Text = "\'"; + Text += Name; + Text += '\''; + if (!DWPName.empty()) { + Text += " (from "; + if (!DWOName.empty()) { + Text += '\''; + Text += DWOName; + Text += "' in "; + } + Text += '\''; + Text += DWPName; + Text += "')"; + } + return Text; +} + +static Error createError(StringRef Name, Error E) { + return make_error( + ("failure while decompressing compressed section: '" + Name + "', " + + llvm::toString(std::move(E))) + .str()); +} + +static Error +handleCompressedSection(std::deque> &UncompressedSections, + StringRef &Name, StringRef &Contents) { + if (!Decompressor::isGnuStyle(Name)) + return Error::success(); + + Expected Dec = + Decompressor::create(Name, Contents, false /*IsLE*/, false /*Is64Bit*/); + if (!Dec) + return createError(Name, Dec.takeError()); + + UncompressedSections.emplace_back(); + if (Error E = Dec->resizeAndDecompress(UncompressedSections.back())) + return createError(Name, std::move(E)); + + Name = Name.substr(2); // Drop ".z" + Contents = UncompressedSections.back(); + return Error::success(); +} + +static Error handleSection( + const StringMap> &KnownSections, + const MCSection *StrSection, const MCSection *StrOffsetSection, + const MCSection *TypesSection, const MCSection *CUIndexSection, + const MCSection *TUIndexSection, const SectionRef &Section, MCStreamer &Out, + std::deque> &UncompressedSections, + uint32_t (&ContributionOffsets)[8], UnitIndexEntry &CurEntry, + StringRef &CurStrSection, StringRef &CurStrOffsetSection, + std::vector &CurTypesSection, StringRef &InfoSection, + StringRef &AbbrevSection, StringRef &CurCUIndexSection, + StringRef &CurTUIndexSection) { + if (Section.isBSS()) + return Error::success(); + + if (Section.isVirtual()) + return Error::success(); + + Expected NameOrErr = Section.getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef Name = *NameOrErr; + + Expected ContentsOrErr = Section.getContents(); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + StringRef Contents = *ContentsOrErr; + + if (auto Err = handleCompressedSection(UncompressedSections, Name, Contents)) + return Err; + + Name = Name.substr(Name.find_first_not_of("._")); + + auto SectionPair = KnownSections.find(Name); + if (SectionPair == KnownSections.end()) + return Error::success(); + + if (DWARFSectionKind Kind = SectionPair->second.second) { + auto Index = Kind - DW_SECT_INFO; + if (Kind != DW_SECT_TYPES) { + CurEntry.Contributions[Index].Offset = ContributionOffsets[Index]; + ContributionOffsets[Index] += + (CurEntry.Contributions[Index].Length = Contents.size()); + } + + switch (Kind) { + case DW_SECT_INFO: + InfoSection = Contents; + break; + case DW_SECT_ABBREV: + AbbrevSection = Contents; + break; + default: + break; + } + } + + MCSection *OutSection = SectionPair->second.first; + if (OutSection == StrOffsetSection) + CurStrOffsetSection = Contents; + else if (OutSection == StrSection) + CurStrSection = Contents; + else if (OutSection == TypesSection) + CurTypesSection.push_back(Contents); + else if (OutSection == CUIndexSection) + CurCUIndexSection = Contents; + else if (OutSection == TUIndexSection) + CurTUIndexSection = Contents; + else { + Out.SwitchSection(OutSection); + Out.EmitBytes(Contents); + } + return Error::success(); +} + +static Error +buildDuplicateError(const std::pair &PrevE, + const CompileUnitIdentifiers &ID, StringRef DWPName) { + return make_error( + std::string("Duplicate DWO ID (") + utohexstr(PrevE.first) + ") in " + + buildDWODescription(PrevE.second.Name, PrevE.second.DWPName, + PrevE.second.DWOName) + + " and " + buildDWODescription(ID.Name, DWPName, ID.DWOName)); +} + +static Expected> +getDWOFilenames(StringRef ExecFilename) { + auto ErrOrObj = object::ObjectFile::createObjectFile(ExecFilename); + if (!ErrOrObj) + return ErrOrObj.takeError(); + + const ObjectFile &Obj = *ErrOrObj.get().getBinary(); + std::unique_ptr DWARFCtx = DWARFContext::create(Obj); + + SmallVector DWOPaths; + for (const auto &CU : DWARFCtx->compile_units()) { + const DWARFDie &Die = CU->getUnitDIE(); + std::string DWOName = dwarf::toString( + Die.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); + if (DWOName.empty()) + continue; + std::string DWOCompDir = + dwarf::toString(Die.find(dwarf::DW_AT_comp_dir), ""); + if (!DWOCompDir.empty()) { + SmallString<16> DWOPath; + sys::path::append(DWOPath, DWOCompDir, DWOName); + DWOPaths.emplace_back(DWOPath.data(), DWOPath.size()); + } else { + DWOPaths.push_back(std::move(DWOName)); + } + } + return std::move(DWOPaths); +} + +static Error write(MCStreamer &Out, ArrayRef Inputs) { + const auto &MCOFI = *Out.getContext().getObjectFileInfo(); + MCSection *const StrSection = MCOFI.getDwarfStrDWOSection(); + MCSection *const StrOffsetSection = MCOFI.getDwarfStrOffDWOSection(); + MCSection *const TypesSection = MCOFI.getDwarfTypesDWOSection(); + MCSection *const CUIndexSection = MCOFI.getDwarfCUIndexSection(); + MCSection *const TUIndexSection = MCOFI.getDwarfTUIndexSection(); + const StringMap> KnownSections = { + {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, + {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_TYPES}}, + {"debug_str_offsets.dwo", {StrOffsetSection, DW_SECT_STR_OFFSETS}}, + {"debug_str.dwo", {StrSection, static_cast(0)}}, + {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_LOC}}, + {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, + {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, + {"debug_cu_index", {CUIndexSection, static_cast(0)}}, + {"debug_tu_index", {TUIndexSection, static_cast(0)}}}; + + MapVector IndexEntries; + MapVector TypeIndexEntries; + + uint32_t ContributionOffsets[8] = {}; + + DWPStringPool Strings(Out, StrSection); + + SmallVector, 128> Objects; + Objects.reserve(Inputs.size()); + + std::deque> UncompressedSections; + + for (const auto &Input : Inputs) { + auto ErrOrObj = object::ObjectFile::createObjectFile(Input); + if (!ErrOrObj) + return ErrOrObj.takeError(); + + auto &Obj = *ErrOrObj->getBinary(); + Objects.push_back(std::move(*ErrOrObj)); + + UnitIndexEntry CurEntry = {}; + + StringRef CurStrSection; + StringRef CurStrOffsetSection; + std::vector CurTypesSection; + StringRef InfoSection; + StringRef AbbrevSection; + StringRef CurCUIndexSection; + StringRef CurTUIndexSection; + + for (const auto &Section : Obj.sections()) + if (auto Err = handleSection( + KnownSections, StrSection, StrOffsetSection, TypesSection, + CUIndexSection, TUIndexSection, Section, Out, + UncompressedSections, ContributionOffsets, CurEntry, + CurStrSection, CurStrOffsetSection, CurTypesSection, InfoSection, + AbbrevSection, CurCUIndexSection, CurTUIndexSection)) + return Err; + + if (InfoSection.empty()) + continue; + + writeStringsAndOffsets(Out, Strings, StrOffsetSection, CurStrSection, + CurStrOffsetSection); + + if (CurCUIndexSection.empty()) { + Expected EID = getCUIdentifiers( + AbbrevSection, InfoSection, CurStrOffsetSection, CurStrSection); + if (!EID) + return createFileError(Input, EID.takeError()); + const auto &ID = *EID; + auto P = IndexEntries.insert(std::make_pair(ID.Signature, CurEntry)); + if (!P.second) + return buildDuplicateError(*P.first, ID, ""); + P.first->second.Name = ID.Name; + P.first->second.DWOName = ID.DWOName; + addAllTypes(Out, TypeIndexEntries, TypesSection, CurTypesSection, + CurEntry, ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); + continue; + } + + DWARFUnitIndex CUIndex(DW_SECT_INFO); + DataExtractor CUIndexData(CurCUIndexSection, Obj.isLittleEndian(), 0); + if (!CUIndex.parse(CUIndexData)) + return make_error("Failed to parse cu_index"); + + for (const DWARFUnitIndex::Entry &E : CUIndex.getRows()) { + auto *I = E.getOffsets(); + if (!I) + continue; + auto P = IndexEntries.insert(std::make_pair(E.getSignature(), CurEntry)); + Expected EID = getCUIdentifiers( + getSubsection(AbbrevSection, E, DW_SECT_ABBREV), + getSubsection(InfoSection, E, DW_SECT_INFO), + getSubsection(CurStrOffsetSection, E, DW_SECT_STR_OFFSETS), + CurStrSection); + if (!EID) + return createFileError(Input, EID.takeError()); + const auto &ID = *EID; + if (!P.second) + return buildDuplicateError(*P.first, ID, Input); + auto &NewEntry = P.first->second; + NewEntry.Name = ID.Name; + NewEntry.DWOName = ID.DWOName; + NewEntry.DWPName = Input; + for (auto Kind : CUIndex.getColumnKinds()) { + auto &C = NewEntry.Contributions[Kind - DW_SECT_INFO]; + C.Offset += I->Offset; + C.Length = I->Length; + ++I; + } + } + + if (!CurTypesSection.empty()) { + if (CurTypesSection.size() != 1) + return make_error("multiple type unit sections in .dwp file"); + DWARFUnitIndex TUIndex(DW_SECT_TYPES); + DataExtractor TUIndexData(CurTUIndexSection, Obj.isLittleEndian(), 0); + if (!TUIndex.parse(TUIndexData)) + return make_error("Failed to parse tu_index"); + addAllTypesFromDWP(Out, TypeIndexEntries, TUIndex, TypesSection, + CurTypesSection.front(), CurEntry, + ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO]); + } + } + + // Lie about there being no info contributions so the TU index only includes + // the type unit contribution + ContributionOffsets[0] = 0; + writeIndex(Out, MCOFI.getDwarfTUIndexSection(), ContributionOffsets, + TypeIndexEntries); + + // Lie about the type contribution + ContributionOffsets[DW_SECT_TYPES - DW_SECT_INFO] = 0; + // Unlie about the info contribution + ContributionOffsets[0] = 1; + + writeIndex(Out, MCOFI.getDwarfCUIndexSection(), ContributionOffsets, + IndexEntries); + + return Error::success(); +} + +static int error(const Twine &Error, const Twine &Context) { + errs() << Twine("while processing ") + Context + ":\n"; + errs() << Twine("error: ") + Error + "\n"; + return 1; +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv, "merge split dwarf (.dwo) files\n"); + + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + + std::string ErrorStr; + StringRef Context = "dwarf streamer init"; + + Triple TheTriple("x86_64-linux-gnu"); + + // Get the target. + const Target *TheTarget = + TargetRegistry::lookupTarget("", TheTriple, ErrorStr); + if (!TheTarget) + return error(ErrorStr, Context); + std::string TripleName = TheTriple.getTriple(); + + // Create all the MC Objects. + std::unique_ptr MRI(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return error(Twine("no register info for target ") + TripleName, Context); + + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); + std::unique_ptr MAI( + TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); + if (!MAI) + return error("no asm info for target " + TripleName, Context); + + MCObjectFileInfo MOFI; + MCContext MC(MAI.get(), MRI.get(), &MOFI); + MOFI.InitMCObjectFileInfo(TheTriple, /*PIC*/ false, MC); + + std::unique_ptr MSTI( + TheTarget->createMCSubtargetInfo(TripleName, "", "")); + if (!MSTI) + return error("no subtarget info for target " + TripleName, Context); + + MCTargetOptions Options; + auto MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, Options); + if (!MAB) + return error("no asm backend for target " + TripleName, Context); + + std::unique_ptr MII(TheTarget->createMCInstrInfo()); + if (!MII) + return error("no instr info info for target " + TripleName, Context); + + MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, MC); + if (!MCE) + return error("no code emitter for target " + TripleName, Context); + + // Create the output file. + std::error_code EC; + ToolOutputFile OutFile(OutputFilename, EC, sys::fs::OF_None); + Optional BOS; + raw_pwrite_stream *OS; + if (EC) + return error(Twine(OutputFilename) + ": " + EC.message(), Context); + if (OutFile.os().supportsSeeking()) { + OS = &OutFile.os(); + } else { + BOS.emplace(OutFile.os()); + OS = BOS.getPointer(); + } + + std::unique_ptr MS(TheTarget->createMCObjectStreamer( + TheTriple, MC, std::unique_ptr(MAB), + MAB->createObjectWriter(*OS), std::unique_ptr(MCE), *MSTI, + MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false)); + if (!MS) + return error("no object streamer for target " + TripleName, Context); + + std::vector DWOFilenames = InputFiles; + for (const auto &ExecFilename : ExecFilenames) { + auto DWOs = getDWOFilenames(ExecFilename); + if (!DWOs) { + logAllUnhandledErrors(DWOs.takeError(), WithColor::error()); + return 1; + } + DWOFilenames.insert(DWOFilenames.end(), + std::make_move_iterator(DWOs->begin()), + std::make_move_iterator(DWOs->end())); + } + + if (auto Err = write(*MS, DWOFilenames)) { + logAllUnhandledErrors(std::move(Err), WithColor::error()); + return 1; + } + + MS->Finish(); + OutFile.keep(); + return 0; +} Property changes on: head/contrib/llvm-project/llvm/tools/llvm-dwp/llvm-dwp.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp =================================================================== --- head/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp (nonexistent) +++ head/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp (revision 362719) @@ -0,0 +1,894 @@ +//===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like traditional Unix "size", +// that is, it prints out the size of each section, and the total size of all +// sections. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APInt.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include + +using namespace llvm; +using namespace object; + +cl::OptionCategory SizeCat("llvm-size Options"); + +enum OutputFormatTy { berkeley, sysv, darwin }; +static cl::opt + OutputFormat("format", cl::desc("Specify output format"), + cl::values(clEnumVal(sysv, "System V format"), + clEnumVal(berkeley, "Berkeley format"), + clEnumVal(darwin, "Darwin -m format")), + cl::init(berkeley), cl::cat(SizeCat)); + +static cl::opt + OutputFormatShort(cl::desc("Specify output format"), + cl::values(clEnumValN(sysv, "A", "System V format"), + clEnumValN(berkeley, "B", "Berkeley format"), + clEnumValN(darwin, "m", "Darwin -m format")), + cl::init(berkeley), cl::cat(SizeCat)); + +static bool BerkeleyHeaderPrinted = false; +static bool MoreThanOneFile = false; +static uint64_t TotalObjectText = 0; +static uint64_t TotalObjectData = 0; +static uint64_t TotalObjectBss = 0; +static uint64_t TotalObjectTotal = 0; + +cl::opt + DarwinLongFormat("l", + cl::desc("When format is darwin, use long format " + "to include addresses and offsets."), + cl::cat(SizeCat)); + +cl::opt + ELFCommons("common", + cl::desc("Print common symbols in the ELF file. When using " + "Berkeley format, this is added to bss."), + cl::init(false), cl::cat(SizeCat)); + +static cl::list + ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), + cl::ZeroOrMore, cl::cat(SizeCat)); +static bool ArchAll = false; + +enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; +static cl::opt Radix( + "radix", cl::desc("Print size in radix"), cl::init(decimal), + cl::values(clEnumValN(octal, "8", "Print size in octal"), + clEnumValN(decimal, "10", "Print size in decimal"), + clEnumValN(hexadecimal, "16", "Print size in hexadecimal")), + cl::cat(SizeCat)); + +static cl::opt RadixShort( + cl::desc("Print size in radix:"), + cl::values(clEnumValN(octal, "o", "Print size in octal"), + clEnumValN(decimal, "d", "Print size in decimal"), + clEnumValN(hexadecimal, "x", "Print size in hexadecimal")), + cl::init(decimal), cl::cat(SizeCat)); + +static cl::opt + TotalSizes("totals", + cl::desc("Print totals of all objects - Berkeley format only"), + cl::init(false), cl::cat(SizeCat)); + +static cl::alias TotalSizesShort("t", cl::desc("Short for --totals"), + cl::aliasopt(TotalSizes)); + +static cl::list + InputFilenames(cl::Positional, cl::desc(""), cl::ZeroOrMore); + +static cl::extrahelp + HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); + +static bool HadError = false; + +static std::string ToolName; + +static void error(const Twine &Message, StringRef File) { + HadError = true; + WithColor::error(errs(), ToolName) << "'" << File << "': " << Message << "\n"; +} + +// This version of error() prints the archive name and member name, for example: +// "libx.a(foo.o)" after the ToolName before the error message. It sets +// HadError but returns allowing the code to move on to other archive members. +static void error(llvm::Error E, StringRef FileName, const Archive::Child &C, + StringRef ArchitectureName = StringRef()) { + HadError = true; + WithColor::error(errs(), ToolName) << "'" << FileName << "'"; + + Expected 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()); + errs() << "(" << "???" << ")"; + } else + errs() << "(" << NameOrErr.get() << ")"; + + if (!ArchitectureName.empty()) + errs() << " (for architecture " << ArchitectureName << ") "; + + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(std::move(E), OS); + OS.flush(); + errs() << ": " << Buf << "\n"; +} + +// This version of error() prints the file name and which architecture slice it // is from, for example: "foo.o (for architecture i386)" after the ToolName +// before the error message. It sets HadError but returns allowing the code to +// move on to other architecture slices. +static void error(llvm::Error E, StringRef FileName, + StringRef ArchitectureName = StringRef()) { + HadError = true; + WithColor::error(errs(), ToolName) << "'" << 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 << "\n"; +} + +/// Get the length of the string that represents @p num in Radix including the +/// leading 0x or 0 for hexadecimal and octal respectively. +static size_t getNumLengthAsString(uint64_t num) { + APInt conv(64, num); + SmallString<32> result; + conv.toString(result, Radix, false, true); + return result.size(); +} + +/// Return the printing format for the Radix. +static const char *getRadixFmt() { + switch (Radix) { + case octal: + return PRIo64; + case decimal: + return PRIu64; + case hexadecimal: + return PRIx64; + } + return nullptr; +} + +/// Remove unneeded ELF sections from calculation +static bool considerForSize(ObjectFile *Obj, SectionRef Section) { + if (!Obj->isELF()) + return true; + switch (static_cast(Section).getType()) { + case ELF::SHT_NULL: + case ELF::SHT_SYMTAB: + case ELF::SHT_STRTAB: + case ELF::SHT_REL: + case ELF::SHT_RELA: + return false; + } + return true; +} + +/// Total size of all ELF common symbols +static uint64_t getCommonSize(ObjectFile *Obj) { + uint64_t TotalCommons = 0; + for (auto &Sym : Obj->symbols()) + if (Obj->getSymbolFlags(Sym.getRawDataRefImpl()) & SymbolRef::SF_Common) + TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl()); + return TotalCommons; +} + +/// Print the size of each Mach-O segment and section in @p MachO. +/// +/// This is when used when @c OutputFormat is darwin and produces the same +/// output as darwin's size(1) -m output. +static void printDarwinSectionSizes(MachOObjectFile *MachO) { + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + const char *radix_fmt = getRadixFmt(); + if (Radix == hexadecimal) + fmt << "0x"; + fmt << "%" << radix_fmt; + + uint32_t Filetype = MachO->getHeader().filetype; + + uint64_t total = 0; + for (const auto &Load : MachO->load_commands()) { + if (Load.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); + outs() << "Segment " << Seg.segname << ": " + << format(fmt.str().c_str(), Seg.vmsize); + if (DarwinLongFormat) + outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff " + << Seg.fileoff << ")"; + outs() << "\n"; + total += Seg.vmsize; + uint64_t sec_total = 0; + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section_64 Sec = MachO->getSection64(Load, J); + if (Filetype == MachO::MH_OBJECT) + outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " + << format("%.16s", &Sec.sectname) << "): "; + else + outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; + outs() << format(fmt.str().c_str(), Sec.size); + if (DarwinLongFormat) + outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset " + << Sec.offset << ")"; + outs() << "\n"; + sec_total += Sec.size; + } + if (Seg.nsects != 0) + outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); + uint64_t Seg_vmsize = Seg.vmsize; + outs() << "Segment " << Seg.segname << ": " + << format(fmt.str().c_str(), Seg_vmsize); + if (DarwinLongFormat) + outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff " + << Seg.fileoff << ")"; + outs() << "\n"; + total += Seg.vmsize; + uint64_t sec_total = 0; + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section Sec = MachO->getSection(Load, J); + if (Filetype == MachO::MH_OBJECT) + outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " + << format("%.16s", &Sec.sectname) << "): "; + else + outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; + uint64_t Sec_size = Sec.size; + outs() << format(fmt.str().c_str(), Sec_size); + if (DarwinLongFormat) + outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset " + << Sec.offset << ")"; + outs() << "\n"; + sec_total += Sec.size; + } + if (Seg.nsects != 0) + outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; + } + } + outs() << "total " << format(fmt.str().c_str(), total) << "\n"; +} + +/// Print the summary sizes of the standard Mach-O segments in @p MachO. +/// +/// This is when used when @c OutputFormat is berkeley with a Mach-O file and +/// produces the same output as darwin's size(1) default output. +static void printDarwinSegmentSizes(MachOObjectFile *MachO) { + uint64_t total_text = 0; + uint64_t total_data = 0; + uint64_t total_objc = 0; + uint64_t total_others = 0; + for (const auto &Load : MachO->load_commands()) { + if (Load.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); + if (MachO->getHeader().filetype == MachO::MH_OBJECT) { + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section_64 Sec = MachO->getSection64(Load, J); + StringRef SegmentName = StringRef(Sec.segname); + if (SegmentName == "__TEXT") + total_text += Sec.size; + else if (SegmentName == "__DATA") + total_data += Sec.size; + else if (SegmentName == "__OBJC") + total_objc += Sec.size; + else + total_others += Sec.size; + } + } else { + StringRef SegmentName = StringRef(Seg.segname); + if (SegmentName == "__TEXT") + total_text += Seg.vmsize; + else if (SegmentName == "__DATA") + total_data += Seg.vmsize; + else if (SegmentName == "__OBJC") + total_objc += Seg.vmsize; + else + total_others += Seg.vmsize; + } + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); + if (MachO->getHeader().filetype == MachO::MH_OBJECT) { + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section Sec = MachO->getSection(Load, J); + StringRef SegmentName = StringRef(Sec.segname); + if (SegmentName == "__TEXT") + total_text += Sec.size; + else if (SegmentName == "__DATA") + total_data += Sec.size; + else if (SegmentName == "__OBJC") + total_objc += Sec.size; + else + total_others += Sec.size; + } + } else { + StringRef SegmentName = StringRef(Seg.segname); + if (SegmentName == "__TEXT") + total_text += Seg.vmsize; + else if (SegmentName == "__DATA") + total_data += Seg.vmsize; + else if (SegmentName == "__OBJC") + total_objc += Seg.vmsize; + else + total_others += Seg.vmsize; + } + } + } + uint64_t total = total_text + total_data + total_objc + total_others; + + if (!BerkeleyHeaderPrinted) { + outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n"; + BerkeleyHeaderPrinted = true; + } + outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t" + << total_others << "\t" << total << "\t" << format("%" PRIx64, total) + << "\t"; +} + +/// Print the size of each section in @p Obj. +/// +/// The format used is determined by @c OutputFormat and @c Radix. +static void printObjectSectionSizes(ObjectFile *Obj) { + uint64_t total = 0; + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + const char *radix_fmt = getRadixFmt(); + + // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's + // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object + // let it fall through to OutputFormat berkeley. + MachOObjectFile *MachO = dyn_cast(Obj); + if (OutputFormat == darwin && MachO) + printDarwinSectionSizes(MachO); + // If we have a MachOObjectFile and the OutputFormat is berkeley print as + // darwin's default berkeley format for Mach-O files. + else if (MachO && OutputFormat == berkeley) + printDarwinSegmentSizes(MachO); + else if (OutputFormat == sysv) { + // Run two passes over all sections. The first gets the lengths needed for + // formatting the output. The second actually does the output. + std::size_t max_name_len = strlen("section"); + std::size_t max_size_len = strlen("size"); + std::size_t max_addr_len = strlen("addr"); + for (const SectionRef &Section : Obj->sections()) { + if (!considerForSize(Obj, Section)) + continue; + uint64_t size = Section.getSize(); + total += size; + + Expected name_or_err = Section.getName(); + if (!name_or_err) { + error(name_or_err.takeError(), Obj->getFileName()); + return; + } + + uint64_t addr = Section.getAddress(); + max_name_len = std::max(max_name_len, name_or_err->size()); + max_size_len = std::max(max_size_len, getNumLengthAsString(size)); + max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr)); + } + + // Add extra padding. + max_name_len += 2; + max_size_len += 2; + max_addr_len += 2; + + // Setup header format. + fmt << "%-" << max_name_len << "s " + << "%" << max_size_len << "s " + << "%" << max_addr_len << "s\n"; + + // Print header + outs() << format(fmt.str().c_str(), static_cast("section"), + static_cast("size"), + static_cast("addr")); + fmtbuf.clear(); + + // Setup per section format. + fmt << "%-" << max_name_len << "s " + << "%#" << max_size_len << radix_fmt << " " + << "%#" << max_addr_len << radix_fmt << "\n"; + + // Print each section. + for (const SectionRef &Section : Obj->sections()) { + if (!considerForSize(Obj, Section)) + continue; + + Expected name_or_err = Section.getName(); + if (!name_or_err) { + error(name_or_err.takeError(), Obj->getFileName()); + return; + } + + uint64_t size = Section.getSize(); + uint64_t addr = Section.getAddress(); + outs() << format(fmt.str().c_str(), name_or_err->str().c_str(), size, addr); + } + + if (ELFCommons) { + uint64_t CommonSize = getCommonSize(Obj); + total += CommonSize; + outs() << format(fmt.str().c_str(), std::string("*COM*").c_str(), + CommonSize, static_cast(0)); + } + + // Print total. + fmtbuf.clear(); + fmt << "%-" << max_name_len << "s " + << "%#" << max_size_len << radix_fmt << "\n"; + outs() << format(fmt.str().c_str(), static_cast("Total"), + total) + << "\n\n"; + } else { + // The Berkeley format does not display individual section sizes. It + // displays the cumulative size for each section type. + uint64_t total_text = 0; + uint64_t total_data = 0; + uint64_t total_bss = 0; + + // Make one pass over the section table to calculate sizes. + for (const SectionRef &Section : Obj->sections()) { + uint64_t size = Section.getSize(); + bool isText = Section.isBerkeleyText(); + bool isData = Section.isBerkeleyData(); + bool isBSS = Section.isBSS(); + if (isText) + total_text += size; + else if (isData) + total_data += size; + else if (isBSS) + total_bss += size; + } + + if (ELFCommons) + total_bss += getCommonSize(Obj); + + total = total_text + total_data + total_bss; + + if (TotalSizes) { + TotalObjectText += total_text; + TotalObjectData += total_data; + TotalObjectBss += total_bss; + TotalObjectTotal += total; + } + + if (!BerkeleyHeaderPrinted) { + outs() << " text\t" + " data\t" + " bss\t" + " " + << (Radix == octal ? "oct" : "dec") + << "\t" + " hex\t" + "filename\n"; + BerkeleyHeaderPrinted = true; + } + + // Print result. + fmt << "%#7" << radix_fmt << "\t" + << "%#7" << radix_fmt << "\t" + << "%#7" << radix_fmt << "\t"; + outs() << format(fmt.str().c_str(), total_text, total_data, total_bss); + fmtbuf.clear(); + fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" + << "%7" PRIx64 "\t"; + outs() << format(fmt.str().c_str(), total, total); + } +} + +/// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there +/// is a list of architecture flags specified then check to make sure this +/// Mach-O file is one of those architectures or all architectures was +/// specificed. If not then an error is generated and this routine returns +/// false. Else it returns true. +static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { + auto *MachO = dyn_cast(O); + + if (!MachO || ArchAll || ArchFlags.empty()) + return true; + + MachO::mach_header H; + MachO::mach_header_64 H_64; + Triple T; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype); + } else { + H = MachO->MachOObjectFile::getHeader(); + T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype); + } + if (none_of(ArchFlags, [&](const std::string &Name) { + return Name == T.getArchName(); + })) { + error("no architecture specified", Filename); + return false; + } + return true; +} + +/// Print the section sizes for @p file. If @p file is an archive, print the +/// section sizes for each archive member. +static void printFileSectionSizes(StringRef file) { + + // Attempt to open the binary. + Expected> BinaryOrErr = createBinary(file); + if (!BinaryOrErr) { + error(BinaryOrErr.takeError(), file); + return; + } + Binary &Bin = *BinaryOrErr.get().getBinary(); + + if (Archive *a = dyn_cast(&Bin)) { + // This is an archive. Iterate over each member and display its sizes. + Error Err = Error::success(); + for (auto &C : a->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) + error(std::move(E), a->getFileName(), C); + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (!checkMachOAndArchFlags(o, file)) + return; + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; + else + outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; + } + } + } + if (Err) + error(std::move(Err), a->getFileName()); + } else if (MachOUniversalBinary *UB = + dyn_cast(&Bin)) { + // If we have a list of architecture flags specified dump only those. + if (!ArchAll && !ArchFlags.empty()) { + // Look for a slice in the universal binary that matches each ArchFlag. + bool ArchFound; + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + ArchFound = false; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (ArchFlags[i] == I->getArchFlagName()) { + ArchFound = true; + Expected> UO = I->getAsObjectFile(); + if (UO) { + if (ObjectFile *o = dyn_cast(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (MoreThanOneFile || ArchFlags.size() > 1) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << "): \n"; + } + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || MoreThanOneFile || ArchFlags.size() > 1) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << ")"; + outs() << "\n"; + } + } + } else if (auto E = isNotObjectErrorInvalidFileType( + UO.takeError())) { + error(std::move(E), file, ArchFlags.size() > 1 ? + StringRef(I->getArchFlagName()) : StringRef()); + return; + } else if (Expected> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; + // This is an archive. Iterate over each member and display its + // sizes. + Error Err = Error::success(); + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C, + ArchFlags.size() > 1 ? + StringRef(I->getArchFlagName()) : StringRef()); + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() + << ")" + << " (for architecture " << I->getArchFlagName() + << "):\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) { + outs() << UA->getFileName() << "(" << o->getFileName() + << ")"; + if (ArchFlags.size() > 1) + outs() << " (for architecture " << I->getArchFlagName() + << ")"; + outs() << "\n"; + } else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("mach-o universal file for architecture " + + StringRef(I->getArchFlagName()) + + " is not a mach-o file or an archive file", + file); + } + } + } + if (!ArchFound) { + error("file does not contain architecture " + ArchFlags[i], file); + return; + } + } + return; + } + // No architecture flags were specified so if this contains a slice that + // matches the host architecture dump only that. + if (!ArchAll) { + StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (HostArchName == I->getArchFlagName()) { + Expected> UO = I->getAsObjectFile(); + if (UO) { + if (ObjectFile *o = dyn_cast(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (MoreThanOneFile) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << "):\n"; + } + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || MoreThanOneFile) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << ")"; + outs() << "\n"; + } + } + } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { + error(std::move(E), file); + return; + } else if (Expected> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; + // This is an archive. Iterate over each member and display its + // sizes. + Error Err = Error::success(); + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C); + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchFlagName() + << "):\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << UA->getFileName() << "(" << o->getFileName() + << ")\n"; + else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("mach-o universal file for architecture " + + StringRef(I->getArchFlagName()) + + " is not a mach-o file or an archive file", + file); + } + return; + } + } + } + // Either all architectures have been specified or none have been specified + // and this does not contain the host architecture so dump all the slices. + bool MoreThanOneArch = UB->getNumberOfObjects() > 1; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + Expected> UO = I->getAsObjectFile(); + if (UO) { + if (ObjectFile *o = dyn_cast(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (MoreThanOneFile || MoreThanOneArch) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << "):"; + outs() << "\n"; + } + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || MoreThanOneFile || MoreThanOneArch) + outs() << o->getFileName() << " (for architecture " + << I->getArchFlagName() << ")"; + outs() << "\n"; + } + } + } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) { + error(std::move(E), file, MoreThanOneArch ? + StringRef(I->getArchFlagName()) : StringRef()); + return; + } else if (Expected> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; + // This is an archive. Iterate over each member and display its sizes. + Error Err = Error::success(); + for (auto &C : UA->children(Err)) { + Expected> ChildOrErr = C.getAsBinary(); + if (!ChildOrErr) { + if (auto E = isNotObjectErrorInvalidFileType( + ChildOrErr.takeError())) + error(std::move(E), UA->getFileName(), C, MoreThanOneArch ? + StringRef(I->getArchFlagName()) : StringRef()); + continue; + } + if (ObjectFile *o = dyn_cast(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchFlagName() << "):\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchFlagName() + << ")\n"; + else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + if (Err) + error(std::move(Err), UA->getFileName()); + } else { + consumeError(AOrErr.takeError()); + error("mach-o universal file for architecture " + + StringRef(I->getArchFlagName()) + + " is not a mach-o file or an archive file", + file); + } + } + } else if (ObjectFile *o = dyn_cast(&Bin)) { + if (!checkMachOAndArchFlags(o, file)) + return; + MachOObjectFile *MachO = dyn_cast(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin && MoreThanOneFile) + outs() << o->getFileName() << ":\n"; + printObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || MoreThanOneFile) + outs() << o->getFileName(); + outs() << "\n"; + } + } else { + error("unsupported file type", file); + } +} + +static void printBerkeleyTotals() { + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + const char *radix_fmt = getRadixFmt(); + fmt << "%#7" << radix_fmt << "\t" + << "%#7" << radix_fmt << "\t" + << "%#7" << radix_fmt << "\t"; + outs() << format(fmt.str().c_str(), TotalObjectText, TotalObjectData, + TotalObjectBss); + fmtbuf.clear(); + fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t" + << "%7" PRIx64 "\t"; + outs() << format(fmt.str().c_str(), TotalObjectTotal, TotalObjectTotal) + << "(TOTALS)\n"; +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + cl::HideUnrelatedOptions(SizeCat); + cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); + + ToolName = argv[0]; + if (OutputFormatShort.getNumOccurrences()) + OutputFormat = static_cast(OutputFormatShort); + if (RadixShort.getNumOccurrences()) + Radix = RadixShort.getValue(); + + for (StringRef Arch : ArchFlags) { + if (Arch == "all") { + ArchAll = true; + } else { + if (!MachOObjectFile::isValidArch(Arch)) { + outs() << ToolName << ": for the -arch option: Unknown architecture " + << "named '" << Arch << "'"; + return 1; + } + } + } + + if (InputFilenames.empty()) + InputFilenames.push_back("a.out"); + + MoreThanOneFile = InputFilenames.size() > 1; + llvm::for_each(InputFilenames, printFileSectionSizes); + if (OutputFormat == berkeley && TotalSizes) + printBerkeleyTotals(); + + if (HadError) + return 1; +} Property changes on: head/contrib/llvm-project/llvm/tools/llvm-size/llvm-size.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp =================================================================== --- head/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp (nonexistent) +++ head/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp (revision 362719) @@ -0,0 +1,120 @@ +//===-- llvm-strings.cpp - Printable String dumping utility ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like binutils "strings", that is, it +// prints out printable strings in a binary, objdump, or archive file. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Binary.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Program.h" +#include +#include + +using namespace llvm; +using namespace llvm::object; + +static cl::list InputFileNames(cl::Positional, + cl::desc(""), + cl::ZeroOrMore); + +static cl::opt + PrintFileName("print-file-name", + cl::desc("Print the name of the file before each string")); +static cl::alias PrintFileNameShort("f", cl::desc(""), + cl::aliasopt(PrintFileName)); + +static cl::opt + MinLength("bytes", cl::desc("Print sequences of the specified length"), + cl::init(4)); +static cl::alias MinLengthShort("n", cl::desc(""), cl::aliasopt(MinLength)); + +static cl::opt + AllSections("all", + cl::desc("Check all sections, not just the data section")); +static cl::alias AllSectionsShort("a", cl::desc(""), + cl::aliasopt(AllSections)); + +enum radix { none, octal, hexadecimal, decimal }; +static cl::opt + Radix("radix", cl::desc("print the offset within the file"), + cl::values(clEnumValN(octal, "o", "octal"), + clEnumValN(hexadecimal, "x", "hexadecimal"), + clEnumValN(decimal, "d", "decimal")), + cl::init(none)); +static cl::alias RadixShort("t", cl::desc(""), cl::aliasopt(Radix)); + +static cl::extrahelp + HelpResponse("\nPass @FILE as argument to read options from FILE.\n"); + +static void strings(raw_ostream &OS, StringRef FileName, StringRef Contents) { + auto print = [&OS, FileName](unsigned Offset, StringRef L) { + if (L.size() < static_cast(MinLength)) + return; + if (PrintFileName) + OS << FileName << ": "; + switch (Radix) { + case none: + break; + case octal: + OS << format("%7o ", Offset); + break; + case hexadecimal: + OS << format("%7x ", Offset); + break; + case decimal: + OS << format("%7u ", Offset); + break; + } + OS << L << '\n'; + }; + + const char *B = Contents.begin(); + const char *P = nullptr, *E = nullptr, *S = nullptr; + for (P = Contents.begin(), E = Contents.end(); P < E; ++P) { + if (isPrint(*P) || *P == '\t') { + if (S == nullptr) + S = P; + } else if (S) { + print(S - B, StringRef(S, P - S)); + S = nullptr; + } + } + if (S) + print(S - B, StringRef(S, E - S)); +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv, "llvm string dumper\n"); + if (MinLength == 0) { + errs() << "invalid minimum string length 0\n"; + return EXIT_FAILURE; + } + + if (InputFileNames.empty()) + InputFileNames.push_back("-"); + + for (const auto &File : InputFileNames) { + ErrorOr> Buffer = + MemoryBuffer::getFileOrSTDIN(File); + if (std::error_code EC = Buffer.getError()) + errs() << File << ": " << EC.message() << '\n'; + else + strings(llvm::outs(), File == "-" ? "{standard input}" : File, + Buffer.get()->getMemBufferRef().getBuffer()); + } + + return EXIT_SUCCESS; +} Property changes on: head/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/contrib/llvm-project/llvm =================================================================== --- head/contrib/llvm-project/llvm (revision 362718) +++ head/contrib/llvm-project/llvm (revision 362719) Property changes on: head/contrib/llvm-project/llvm ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/llvm-project/release-10.x/llvm:r362595-362704 Index: head/contrib/llvm-project =================================================================== --- head/contrib/llvm-project (revision 362718) +++ head/contrib/llvm-project (revision 362719) Property changes on: head/contrib/llvm-project ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /vendor/llvm-project/release-10.x:r362595-362704 Index: head/lib/clang/include/VCSVersion.inc =================================================================== --- head/lib/clang/include/VCSVersion.inc (revision 362718) +++ head/lib/clang/include/VCSVersion.inc (revision 362719) @@ -1,14 +1,14 @@ // $FreeBSD$ -#define LLVM_REVISION "llvmorg-10.0.0-129-gd24d5c8e308" +#define LLVM_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d" #define LLVM_REPOSITORY "git@github.com:llvm/llvm-project.git" -#define CLANG_REVISION "llvmorg-10.0.0-129-gd24d5c8e308" +#define CLANG_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d" #define CLANG_REPOSITORY "git@github.com:llvm/llvm-project.git" // - -#define LLD_REVISION "llvmorg-10.0.0-129-gd24d5c8e308-1300007" +#define LLD_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d-1300007" #define LLD_REPOSITORY "FreeBSD" -#define LLDB_REVISION "llvmorg-10.0.0-129-gd24d5c8e308" +#define LLDB_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d" #define LLDB_REPOSITORY "git@github.com:llvm/llvm-project.git" Index: head/lib/clang/include/llvm/Support/VCSRevision.h =================================================================== --- head/lib/clang/include/llvm/Support/VCSRevision.h (revision 362718) +++ head/lib/clang/include/llvm/Support/VCSRevision.h (revision 362719) @@ -1,3 +1,3 @@ /* $FreeBSD$ */ -#define LLVM_REVISION "llvmorg-10.0.0-129-gd24d5c8e308" +#define LLVM_REVISION "llvmorg-10.0.1-rc2-0-g77d76b71d7d" #define LLVM_REPOSITORY "git@github.com:llvm/llvm-project.git" Index: head/tools/build/mk/OptionalObsoleteFiles.inc =================================================================== --- head/tools/build/mk/OptionalObsoleteFiles.inc (revision 362718) +++ head/tools/build/mk/OptionalObsoleteFiles.inc (revision 362719) @@ -1,10137 +1,10143 @@ # # $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_ACPI} == no && ${MK_APM} == no OLD_FILES+=etc/rc.d/powerd .endif .if ${MK_APM} == no OLD_FILES+=etc/rc.d/apm OLD_FILES+=etc/rc.d/apmd OLD_FILES+=etc/apmd.conf OLD_FILES+=usr/sbin/apm OLD_FILES+=usr/share/examples/etc/apmd.conf OLD_FILES+=usr/share/man/man8/amd64/apm.8.gz OLD_FILES+=usr/share/man/man8/amd64/apmconf.8.gz .endif .if ${MK_AT} == no OLD_FILES+=etc/pam.d/atrun OLD_FILES+=usr/bin/at OLD_FILES+=usr/bin/atq OLD_FILES+=usr/bin/atrm OLD_FILES+=usr/bin/batch OLD_FILES+=usr/libexec/atrun OLD_FILES+=usr/share/man/man1/at.1.gz OLD_FILES+=usr/share/man/man1/atq.1.gz OLD_FILES+=usr/share/man/man1/atrm.1.gz OLD_FILES+=usr/share/man/man1/batch.1.gz OLD_FILES+=usr/share/man/man8/atrun.8.gz .endif .if ${MK_ATM} == no OLD_FILES+=usr/bin/sscop OLD_FILES+=usr/include/netnatm/addr.h OLD_FILES+=usr/include/netnatm/api/atmapi.h OLD_FILES+=usr/include/netnatm/api/ccatm.h OLD_FILES+=usr/include/netnatm/api/unisap.h OLD_DIRS+=usr/include/netnatm/api OLD_FILES+=usr/include/netnatm/msg/uni_config.h OLD_FILES+=usr/include/netnatm/msg/uni_hdr.h OLD_FILES+=usr/include/netnatm/msg/uni_ie.h OLD_FILES+=usr/include/netnatm/msg/uni_msg.h OLD_FILES+=usr/include/netnatm/msg/unimsglib.h OLD_FILES+=usr/include/netnatm/msg/uniprint.h OLD_FILES+=usr/include/netnatm/msg/unistruct.h OLD_DIRS+=usr/include/netnatm/msg OLD_FILES+=usr/include/netnatm/saal/sscfu.h OLD_FILES+=usr/include/netnatm/saal/sscfudef.h OLD_FILES+=usr/include/netnatm/saal/sscop.h OLD_FILES+=usr/include/netnatm/saal/sscopdef.h OLD_DIRS+=usr/include/netnatm/saal OLD_FILES+=usr/include/netnatm/sig/uni.h OLD_FILES+=usr/include/netnatm/sig/unidef.h OLD_FILES+=usr/include/netnatm/sig/unisig.h OLD_DIRS+=usr/include/netnatm/sig OLD_FILES+=usr/include/netnatm/unimsg.h OLD_FILES+=usr/lib/libngatm.a OLD_FILES+=usr/lib/libngatm.so OLD_LIBS+=usr/lib/libngatm.so.4 OLD_FILES+=usr/lib/libngatm_p.a .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/man/man1/sscop.1.gz OLD_FILES+=usr/share/man/man3/libngatm.3.gz OLD_FILES+=usr/share/man/man3/uniaddr.3.gz OLD_FILES+=usr/share/man/man3/unifunc.3.gz OLD_FILES+=usr/share/man/man3/unimsg.3.gz OLD_FILES+=usr/share/man/man3/unisap.3.gz OLD_FILES+=usr/share/man/man3/unistruct.3.gz .endif .if ${MK_AUDIT} == no OLD_FILES+=etc/rc.d/auditd OLD_FILES+=etc/rc.d/auditdistd OLD_FILES+=usr/sbin/audit OLD_FILES+=usr/sbin/auditd OLD_FILES+=usr/sbin/auditdistd OLD_FILES+=usr/sbin/auditreduce OLD_FILES+=usr/sbin/praudit OLD_FILES+=usr/share/man/man1/auditreduce.1.gz OLD_FILES+=usr/share/man/man1/praudit.1.gz OLD_FILES+=usr/share/man/man5/auditdistd.conf.5.gz OLD_FILES+=usr/share/man/man8/audit.8.gz OLD_FILES+=usr/share/man/man8/auditd.8.gz OLD_FILES+=usr/share/man/man8/auditdistd.8.gz OLD_FILES+=usr/tests/sys/audit/process-control OLD_FILES+=usr/tests/sys/audit/open OLD_FILES+=usr/tests/sys/audit/network OLD_FILES+=usr/tests/sys/audit/miscellaneous OLD_FILES+=usr/tests/sys/audit/Kyuafile OLD_FILES+=usr/tests/sys/audit/ioctl OLD_FILES+=usr/tests/sys/audit/inter-process OLD_FILES+=usr/tests/sys/audit/file-write OLD_FILES+=usr/tests/sys/audit/file-read OLD_FILES+=usr/tests/sys/audit/file-delete OLD_FILES+=usr/tests/sys/audit/file-create OLD_FILES+=usr/tests/sys/audit/file-close OLD_FILES+=usr/tests/sys/audit/file-attribute-modify OLD_FILES+=usr/tests/sys/audit/file-attribute-access OLD_FILES+=usr/tests/sys/audit/administrative OLD_DIRS+=usr/tests/sys/audit .endif .if ${MK_AUTHPF} == no OLD_FILES+=usr/sbin/authpf OLD_FILES+=usr/sbin/authpf-noip OLD_FILES+=usr/share/man/man8/authpf.8.gz OLD_FILES+=usr/share/man/man8/authpf-noip.8.gz .endif .if ${MK_AUTOFS} == no OLD_FILES+=etc/autofs/include_ldap OLD_FILES+=etc/autofs/special_hosts OLD_FILES+=etc/autofs/special_media OLD_FILES+=etc/autofs/special_noauto OLD_FILES+=etc/autofs/special_null OLD_FILES+=etc/auto_master OLD_FILES+=etc/rc.d/automount OLD_FILES+=etc/rc.d/automountd OLD_FILES+=etc/rc.d/autounmountd OLD_FILES+=usr/sbin/automount OLD_FILES+=usr/sbin/automountd OLD_FILES+=usr/sbin/autounmountd OLD_FILES+=usr/share/man/man5/autofs.5.gz OLD_FILES+=usr/share/man/man5/auto_master.5.gz OLD_FILES+=usr/share/man/man8/automount.8.gz OLD_FILES+=usr/share/man/man8/automountd.8.gz OLD_FILES+=usr/share/man/man8/autounmountd.8.gz OLD_DIRS+=etc/autofs .endif .if ${MK_BHYVE} == no OLD_FILES+=usr/lib/libvmmapi.a OLD_FILES+=usr/lib/libvmmapi.so OLD_LIBS+=usr/lib/libvmmapi.so.5 OLD_FILES+=usr/include/vmmapi.h OLD_FILES+=usr/sbin/bhyve OLD_FILES+=usr/sbin/bhyvectl OLD_FILES+=usr/sbin/bhyveload OLD_FILES+=usr/share/examples/bhyve/vmrun.sh OLD_FILES+=usr/share/man/man8/bhyve.8.gz OLD_FILES+=usr/share/man/man8/bhyveload.8.gz OLD_DIRS+=usr/share/examples/bhyve .endif .if !defined(WITH_PORT_BASE_BINUTILS) .if ${MK_LLD_IS_LD} == no OLD_FILES+=usr/bin/ld OLD_FILES+=usr/share/man/man1/ld.1.gz .endif .endif .if ${MK_BLACKLIST} == no OLD_FILES+=etc/blacklistd.conf OLD_FILES+=etc/rc.d/blacklistd OLD_FILES+=usr/include/blacklist.h OLD_FILES+=usr/lib/libblacklist.a OLD_FILES+=usr/lib/libblacklist_p.a OLD_FILES+=usr/lib/libblacklist.so OLD_LIBS+=usr/lib/libblacklist.so.0 OLD_FILES+=usr/libexec/blacklistd-helper OLD_FILES+=usr/sbin/blacklistctl OLD_FILES+=usr/sbin/blacklistd OLD_FILES+=usr/share/man/man3/blacklist.3.gz OLD_FILES+=usr/share/man/man3/blacklist_close.3.gz OLD_FILES+=usr/share/man/man3/blacklist_open.3.gz OLD_FILES+=usr/share/man/man3/blacklist_r.3.gz OLD_FILES+=usr/share/man/man3/blacklist_sa.3.gz OLD_FILES+=usr/share/man/man3/blacklist_sa_r.3.gz OLD_FILES+=usr/share/man/man5/blacklistd.conf.5.gz OLD_FILES+=usr/share/man/man8/blacklistctl.8.gz OLD_FILES+=usr/share/man/man8/blacklistd.8.gz .endif .if ${MK_BLUETOOTH} == no OLD_FILES+=etc/bluetooth/hcsecd.conf OLD_FILES+=etc/bluetooth/hosts OLD_FILES+=etc/bluetooth/protocols OLD_FILES+=etc/defaults/bluetooth.device.conf OLD_FILES+=etc/devd/iwmbtfw.conf OLD_DIRS+=etc/bluetooth OLD_FILES+=etc/rc.d/bluetooth OLD_FILES+=etc/rc.d/bthidd OLD_FILES+=etc/rc.d/hcsecd OLD_FILES+=etc/rc.d/rfcomm_pppd_server OLD_FILES+=etc/rc.d/sdpd OLD_FILES+=etc/rc.d/ubthidhci OLD_FILES+=usr/bin/bthost OLD_FILES+=usr/bin/btsockstat OLD_FILES+=usr/bin/rfcomm_sppd OLD_FILES+=usr/include/bluetooth.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_bluetooth.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_bt3c.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_hci_raw.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_l2cap.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_rfcomm.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_btsocket_sco.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_h4.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_hci.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_l2cap.h OLD_FILES+=usr/include/netgraph/bluetooth/include/ng_ubt.h OLD_DIRS+=usr/include/netgraph/bluetooth/include OLD_DIRS+=usr/include/netgraph/bluetooth OLD_FILES+=usr/include/sdp.h OLD_FILES+=usr/lib/libbluetooth.a OLD_FILES+=usr/lib/libbluetooth.so OLD_LIBS+=usr/lib/libbluetooth.so.4 OLD_FILES+=usr/lib/libbluetooth_p.a OLD_FILES+=usr/lib/libsdp.a OLD_FILES+=usr/lib/libsdp.so OLD_LIBS+=usr/lib/libsdp.so.4 OLD_FILES+=usr/lib/libsdp_p.a .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/bluetooth-config OLD_FILES+=usr/sbin/bt3cfw OLD_FILES+=usr/sbin/bthidcontrol OLD_FILES+=usr/sbin/bthidd OLD_FILES+=usr/sbin/btpand OLD_FILES+=usr/sbin/hccontrol OLD_FILES+=usr/sbin/hcsecd OLD_FILES+=usr/sbin/hcseriald OLD_FILES+=usr/sbin/iwmbtfw OLD_FILES+=usr/sbin/l2control OLD_FILES+=usr/sbin/l2ping OLD_FILES+=usr/sbin/rfcomm_pppd OLD_FILES+=usr/sbin/sdpcontrol OLD_FILES+=usr/sbin/sdpd OLD_FILES+=usr/share/examples/etc/defaults/bluetooth.device.conf OLD_FILES+=usr/share/man/man1/bthost.1.gz OLD_FILES+=usr/share/man/man1/btsockstat.1.gz OLD_FILES+=usr/share/man/man1/rfcomm_sppd.1.gz OLD_FILES+=usr/share/man/man3/SDP_GET128.3.gz OLD_FILES+=usr/share/man/man3/SDP_GET16.3.gz OLD_FILES+=usr/share/man/man3/SDP_GET32.3.gz OLD_FILES+=usr/share/man/man3/SDP_GET64.3.gz OLD_FILES+=usr/share/man/man3/SDP_GET8.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT128.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT16.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT32.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT64.3.gz OLD_FILES+=usr/share/man/man3/SDP_PUT8.3.gz OLD_FILES+=usr/share/man/man3/bdaddr_any.3.gz OLD_FILES+=usr/share/man/man3/bdaddr_copy.3.gz OLD_FILES+=usr/share/man/man3/bdaddr_same.3.gz OLD_FILES+=usr/share/man/man3/bluetooth.3.gz OLD_FILES+=usr/share/man/man3/bt_aton.3.gz OLD_FILES+=usr/share/man/man3/bt_devaddr.3.gz OLD_FILES+=usr/share/man/man3/bt_devclose.3.gz OLD_FILES+=usr/share/man/man3/bt_devenum.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_clr.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_set.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_evt_tst.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_clr.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_set.3.gz OLD_FILES+=usr/share/man/man3/bt_devfilter_pkt_tst.3.gz OLD_FILES+=usr/share/man/man3/bt_devinfo.3.gz OLD_FILES+=usr/share/man/man3/bt_devinquiry.3.gz OLD_FILES+=usr/share/man/man3/bt_devname.3.gz OLD_FILES+=usr/share/man/man3/bt_devopen.3.gz OLD_FILES+=usr/share/man/man3/bt_devreq.3.gz OLD_FILES+=usr/share/man/man3/bt_devsend.3.gz OLD_FILES+=usr/share/man/man3/bt_endhostent.3.gz OLD_FILES+=usr/share/man/man3/bt_endprotoent.3.gz OLD_FILES+=usr/share/man/man3/bt_gethostbyaddr.3.gz OLD_FILES+=usr/share/man/man3/bt_gethostbyname.3.gz OLD_FILES+=usr/share/man/man3/bt_gethostent.3.gz OLD_FILES+=usr/share/man/man3/bt_getprotobyname.3.gz OLD_FILES+=usr/share/man/man3/bt_getprotobynumber.3.gz OLD_FILES+=usr/share/man/man3/bt_getprotoent.3.gz OLD_FILES+=usr/share/man/man3/bt_ntoa.3.gz OLD_FILES+=usr/share/man/man3/bt_sethostent.3.gz OLD_FILES+=usr/share/man/man3/bt_setprotoent.3.gz OLD_FILES+=usr/share/man/man3/sdp.3.gz OLD_FILES+=usr/share/man/man3/sdp_attr2desc.3.gz OLD_FILES+=usr/share/man/man3/sdp_change_service.3.gz OLD_FILES+=usr/share/man/man3/sdp_close.3.gz OLD_FILES+=usr/share/man/man3/sdp_error.3.gz OLD_FILES+=usr/share/man/man3/sdp_open.3.gz OLD_FILES+=usr/share/man/man3/sdp_open_local.3.gz OLD_FILES+=usr/share/man/man3/sdp_register_service.3.gz OLD_FILES+=usr/share/man/man3/sdp_search.3.gz OLD_FILES+=usr/share/man/man3/sdp_unregister_service.3.gz OLD_FILES+=usr/share/man/man3/sdp_uuid2desc.3.gz OLD_FILES+=usr/share/man/man4/ng_bluetooth.4.gz OLD_FILES+=usr/share/man/man5/bluetooth.device.conf.5.gz OLD_FILES+=usr/share/man/man5/bluetooth.hosts.5.gz OLD_FILES+=usr/share/man/man5/bluetooth.protocols.5.gz OLD_FILES+=usr/share/man/man5/hcsecd.conf.5.gz OLD_FILES+=usr/share/man/man8/ath3kfw.8.gz OLD_FILES+=usr/share/man/man8/bcmfw.8.gz OLD_FILES+=usr/share/man/man8/bluetooth-config.8.gz OLD_FILES+=usr/share/man/man8/bt3cfw.8.gz OLD_FILES+=usr/share/man/man8/bthidcontrol.8.gz OLD_FILES+=usr/share/man/man8/bthidd.8.gz OLD_FILES+=usr/share/man/man8/btpand.8.gz OLD_FILES+=usr/share/man/man8/hccontrol.8.gz OLD_FILES+=usr/share/man/man8/hcsecd.8.gz OLD_FILES+=usr/share/man/man8/hcseriald.8.gz OLD_FILES+=usr/share/man/man8/iwmbtfw.8.gz OLD_FILES+=usr/share/man/man8/l2control.8.gz OLD_FILES+=usr/share/man/man8/l2ping.8.gz OLD_FILES+=usr/share/man/man8/rfcomm_pppd.8.gz OLD_FILES+=usr/share/man/man8/sdpcontrol.8.gz OLD_FILES+=usr/share/man/man8/sdpd.8.gz .endif .if ${MK_BOOT} == no OLD_FILES+=boot/beastie.4th OLD_FILES+=boot/boot OLD_FILES+=boot/boot0 OLD_FILES+=boot/boot0sio OLD_FILES+=boot/boot1 OLD_FILES+=boot/boot1.efi OLD_FILES+=boot/boot2 OLD_FILES+=boot/brand.4th OLD_FILES+=boot/cdboot OLD_FILES+=boot/check-password.4th OLD_FILES+=boot/color.4th OLD_FILES+=boot/defaults/loader.conf OLD_FILES+=boot/delay.4th OLD_FILES+=boot/device.hints OLD_FILES+=boot/frames.4th OLD_FILES+=boot/gptboot OLD_FILES+=boot/gptzfsboot OLD_FILES+=boot/loader OLD_FILES+=boot/loader.4th OLD_FILES+=boot/loader.efi OLD_FILES+=boot/loader.help OLD_FILES+=boot/loader.rc OLD_FILES+=boot/mbr OLD_FILES+=boot/menu-commands.4th OLD_FILES+=boot/menu.4th OLD_FILES+=boot/menu.rc OLD_FILES+=boot/menusets.4th OLD_FILES+=boot/pcibios.4th OLD_FILES+=boot/pmbr OLD_FILES+=boot/pxeboot OLD_FILES+=boot/screen.4th OLD_FILES+=boot/shortcuts.4th OLD_FILES+=boot/support.4th OLD_FILES+=boot/userboot.so OLD_FILES+=boot/version.4th OLD_FILES+=boot/zfsboot OLD_FILES+=boot/zfsloader OLD_FILES+=usr/lib/kgzldr.o OLD_FILES+=usr/share/man/man5/loader.conf.5.gz OLD_FILES+=usr/share/man/man8/beastie.4th.8.gz OLD_FILES+=usr/share/man/man8/brand.4th.8.gz OLD_FILES+=usr/share/man/man8/check-password.4th.8.gz OLD_FILES+=usr/share/man/man8/color.4th.8.gz OLD_FILES+=usr/share/man/man8/delay.4th.8.gz OLD_FILES+=usr/share/man/man8/gptboot.8.gz OLD_FILES+=usr/share/man/man8/gptzfsboot.8.gz OLD_FILES+=usr/share/man/man8/loader.4th.8.gz OLD_FILES+=usr/share/man/man8/loader.8.gz OLD_FILES+=usr/share/man/man8/menu.4th.8.gz OLD_FILES+=usr/share/man/man8/menusets.4th.8.gz OLD_FILES+=usr/share/man/man8/pxeboot.8.gz OLD_FILES+=usr/share/man/man8/version.4th.8.gz OLD_FILES+=usr/share/man/man8/zfsboot.8.gz OLD_FILES+=usr/share/man/man8/zfsloader.8.gz .endif .if ${MK_BOOTPARAMD} == no OLD_FILES+=etc/rc.d/bootparams OLD_FILES+=usr/sbin/bootparamd OLD_FILES+=usr/share/man/man5/bootparams.5.gz OLD_FILES+=usr/share/man/man8/bootparamd.8.gz OLD_FILES+=usr/sbin/callbootd .endif .if ${MK_BOOTPD} == no OLD_FILES+=usr/libexec/bootpd OLD_FILES+=usr/share/man/man5/bootptab.5.gz OLD_FILES+=usr/share/man/man8/bootpd.8.gz OLD_FILES+=usr/libexec/bootpgw OLD_FILES+=usr/sbin/bootpef OLD_FILES+=usr/share/man/man8/bootpef.8.gz OLD_FILES+=usr/sbin/bootptest OLD_FILES+=usr/share/man/man8/bootptest.8.gz .endif .if ${MK_BSD_CPIO} == no OLD_FILES+=usr/bin/bsdcpio OLD_FILES+=usr/bin/cpio OLD_FILES+=usr/share/man/man1/bsdcpio.1.gz OLD_FILES+=usr/share/man/man1/cpio.1.gz .endif .if ${MK_BSDINSTALL} == no OLD_FILES+=usr/libexec/bsdinstall/adduser OLD_FILES+=usr/libexec/bsdinstall/auto OLD_FILES+=usr/libexec/bsdinstall/autopart OLD_FILES+=usr/libexec/bsdinstall/bootconfig OLD_FILES+=usr/libexec/bsdinstall/checksum OLD_FILES+=usr/libexec/bsdinstall/config OLD_FILES+=usr/libexec/bsdinstall/distextract OLD_FILES+=usr/libexec/bsdinstall/distfetch OLD_FILES+=usr/libexec/bsdinstall/docsinstall OLD_FILES+=usr/libexec/bsdinstall/entropy OLD_FILES+=usr/libexec/bsdinstall/hardening OLD_FILES+=usr/libexec/bsdinstall/hostname OLD_FILES+=usr/libexec/bsdinstall/jail OLD_FILES+=usr/libexec/bsdinstall/keymap OLD_FILES+=usr/libexec/bsdinstall/mirrorselect OLD_FILES+=usr/libexec/bsdinstall/mount OLD_FILES+=usr/libexec/bsdinstall/netconfig OLD_FILES+=usr/libexec/bsdinstall/netconfig_ipv4 OLD_FILES+=usr/libexec/bsdinstall/netconfig_ipv6 OLD_FILES+=usr/libexec/bsdinstall/partedit OLD_FILES+=usr/libexec/bsdinstall/rootpass OLD_FILES+=usr/libexec/bsdinstall/script OLD_FILES+=usr/libexec/bsdinstall/scriptedpart OLD_FILES+=usr/libexec/bsdinstall/services OLD_FILES+=usr/libexec/bsdinstall/time OLD_FILES+=usr/libexec/bsdinstall/umount OLD_FILES+=usr/libexec/bsdinstall/wlanconfig OLD_FILES+=usr/libexec/bsdinstall/zfsboot OLD_FILES+=usr/sbin/bsdinstall OLD_FILES+=usr/share/man/man8/bsdinstall.8.gz OLD_FILES+=usr/share/man/man8/sade.8.gz OLD_DIRS+=usr/libexec/bsdinstall .endif .if ${MK_BSNMP} == no OLD_FILES+=etc/snmpd.config OLD_FILES+=etc/rc.d/bsnmpd OLD_FILES+=usr/bin/bsnmpget OLD_FILES+=usr/bin/bsnmpset OLD_FILES+=usr/bin/bsnmpwalk OLD_FILES+=usr/include/bsnmp/asn1.h OLD_FILES+=usr/include/bsnmp/bridge_snmp.h OLD_FILES+=usr/include/bsnmp/snmp.h OLD_FILES+=usr/include/bsnmp/snmp_mibII.h OLD_FILES+=usr/include/bsnmp/snmp_netgraph.h OLD_FILES+=usr/include/bsnmp/snmpagent.h OLD_FILES+=usr/include/bsnmp/snmpclient.h OLD_FILES+=usr/include/bsnmp/snmpmod.h OLD_FILES+=usr/lib/libbsnmp.a OLD_FILES+=usr/lib/libbsnmp.so OLD_LIBS+=usr/lib/libbsnmp.so.6 OLD_FILES+=usr/lib/libbsnmp_p.a OLD_FILES+=usr/lib/libbsnmptools.a OLD_FILES+=usr/lib/libbsnmptools.so OLD_LIBS+=usr/lib/libbsnmptools.so.0 OLD_FILES+=usr/lib/libbsnmptools_p.a OLD_FILES+=usr/lib/snmp_bridge.so OLD_LIBS+=usr/lib/snmp_bridge.so.6 OLD_FILES+=usr/lib/snmp_hast.so OLD_LIBS+=usr/lib/snmp_hast.so.6 OLD_FILES+=usr/lib/snmp_hostres.so OLD_LIBS+=usr/lib/snmp_hostres.so.6 OLD_FILES+=usr/lib/snmp_lm75.so OLD_LIBS+=usr/lib/snmp_lm75.so.6 OLD_FILES+=usr/lib/snmp_mibII.so OLD_LIBS+=usr/lib/snmp_mibII.so.6 OLD_FILES+=usr/lib/snmp_netgraph.so OLD_LIBS+=usr/lib/snmp_netgraph.so.6 OLD_FILES+=usr/lib/snmp_pf.so OLD_LIBS+=usr/lib/snmp_pf.so.6 OLD_FILES+=usr/lib/snmp_target.so OLD_LIBS+=usr/lib/snmp_target.so.6 OLD_FILES+=usr/lib/snmp_usm.so OLD_LIBS+=usr/lib/snmp_usm.so.6 OLD_FILES+=usr/lib/snmp_vacm.so OLD_LIBS+=usr/lib/snmp_vacm.so.6 OLD_FILES+=usr/lib/snmp_wlan.so OLD_LIBS+=usr/lib/snmp_wlan.so.6 OLD_FILES+=usr/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_bridge.3.gz OLD_FILES+=usr/share/man/man3/snmp_hast.3.gz OLD_FILES+=usr/share/man/man3/snmp_hostres.3.gz OLD_FILES+=usr/share/man/man3/snmp_input_finish.3.gz OLD_FILES+=usr/share/man/man3/snmp_input_start.3.gz OLD_FILES+=usr/share/man/man3/snmp_lm75.3.gz OLD_FILES+=usr/share/man/man3/snmp_mibII.3.gz OLD_FILES+=usr/share/man/man3/snmp_netgraph.3.gz OLD_FILES+=usr/share/man/man3/snmp_output.3.gz OLD_FILES+=usr/share/man/man3/snmp_pdu_auth_access.3.gz OLD_FILES+=usr/share/man/man3/snmp_send_port.3.gz OLD_FILES+=usr/share/man/man3/snmp_send_trap.3.gz OLD_FILES+=usr/share/man/man3/snmp_target.3.gz OLD_FILES+=usr/share/man/man3/snmp_usm.3.gz OLD_FILES+=usr/share/man/man3/snmp_vacm.3.gz OLD_FILES+=usr/share/man/man3/snmp_wlan.3.gz OLD_FILES+=usr/share/man/man3/snmpd_target_stat.3.gz OLD_FILES+=usr/share/man/man3/snmpd_usmstats.3.gz OLD_FILES+=usr/share/man/man3/snmpmod.3.gz OLD_FILES+=usr/share/man/man3/start_tick.3.gz OLD_FILES+=usr/share/man/man3/string_commit.3.gz OLD_FILES+=usr/share/man/man3/string_free.3.gz OLD_FILES+=usr/share/man/man3/string_get.3.gz OLD_FILES+=usr/share/man/man3/string_get_max.3.gz OLD_FILES+=usr/share/man/man3/string_rollback.3.gz OLD_FILES+=usr/share/man/man3/string_save.3.gz OLD_FILES+=usr/share/man/man3/systemg.3.gz OLD_FILES+=usr/share/man/man3/this_tick.3.gz OLD_FILES+=usr/share/man/man3/timer_start.3.gz OLD_FILES+=usr/share/man/man3/timer_start_repeat.3.gz OLD_FILES+=usr/share/man/man3/timer_stop.3.gz OLD_FILES+=usr/share/man/man3/target_activate_address.3.gz OLD_FILES+=usr/share/man/man3/target_address.3.gz OLD_FILES+=usr/share/man/man3/target_delete_address.3.gz OLD_FILES+=usr/share/man/man3/target_delete_notify.3.gz OLD_FILES+=usr/share/man/man3/target_delete_param.3.gz OLD_FILES+=usr/share/man/man3/target_first_address.3.gz OLD_FILES+=usr/share/man/man3/target_first_notify.3.gz OLD_FILES+=usr/share/man/man3/target_first_param.3.gz OLD_FILES+=usr/share/man/man3/target_flush_all.3.gz OLD_FILES+=usr/share/man/man3/target_next_address.3.gz OLD_FILES+=usr/share/man/man3/target_next_notify.3.gz OLD_FILES+=usr/share/man/man3/target_next_param.3.gz OLD_FILES+=usr/share/man/man3/target_new_address.3.gz OLD_FILES+=usr/share/man/man3/target_new_notify.3.gz OLD_FILES+=usr/share/man/man3/target_new_param.3.gz OLD_FILES+=usr/share/man/man3/target_notify.3.gz OLD_FILES+=usr/share/man/man3/target_param.3.gz OLD_FILES+=usr/share/man/man3/usm_delete_user.3.gz OLD_FILES+=usr/share/man/man3/usm_find_user.3.gz OLD_FILES+=usr/share/man/man3/usm_first_user.3.gz OLD_FILES+=usr/share/man/man3/usm_flush_users.3.gz OLD_FILES+=usr/share/man/man3/usm_next_user.3.gz OLD_FILES+=usr/share/man/man3/usm_new_user.3.gz OLD_FILES+=usr/share/man/man3/usm_user.3.gz OLD_FILES+=usr/share/snmp/defs/bridge_tree.def OLD_FILES+=usr/share/snmp/defs/hast_tree.def OLD_FILES+=usr/share/snmp/defs/hostres_tree.def OLD_FILES+=usr/share/snmp/defs/lm75_tree.def OLD_FILES+=usr/share/snmp/defs/mibII_tree.def OLD_FILES+=usr/share/snmp/defs/netgraph_tree.def OLD_FILES+=usr/share/snmp/defs/pf_tree.def OLD_FILES+=usr/share/snmp/defs/target_tree.def OLD_FILES+=usr/share/snmp/defs/tc.def OLD_FILES+=usr/share/snmp/defs/tree.def OLD_FILES+=usr/share/snmp/defs/usm_tree.def OLD_FILES+=usr/share/snmp/defs/vacm_tree.def OLD_FILES+=usr/share/snmp/defs/wlan_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM-FREEBSD-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-ATM.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-BRIDGE-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HAST-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HOSTRES-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-IP-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-LM75-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-MIB2-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-NETGRAPH.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-PF-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-SNMPD.txt OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt OLD_FILES+=usr/share/snmp/mibs/BRIDGE-MIB.txt OLD_FILES+=usr/share/snmp/mibs/FOKUS-MIB.txt OLD_FILES+=usr/share/snmp/mibs/FREEBSD-MIB.txt OLD_FILES+=usr/share/snmp/mibs/RSTP-MIB.txt OLD_DIRS+=usr/include/bsnmp OLD_DIRS+=usr/share/snmp OLD_DIRS+=usr/share/snmp/defs OLD_DIRS+=usr/share/snmp/mibs .endif .if ${MK_CALENDAR} == no OLD_FILES+=etc/periodic/daily/300.calendar OLD_FILES+=usr/bin/calendar OLD_FILES+=usr/share/calendar/calendar.all OLD_FILES+=usr/share/calendar/calendar.australia OLD_FILES+=usr/share/calendar/calendar.birthday OLD_FILES+=usr/share/calendar/calendar.brazilian OLD_FILES+=usr/share/calendar/calendar.christian OLD_FILES+=usr/share/calendar/calendar.computer OLD_FILES+=usr/share/calendar/calendar.croatian OLD_FILES+=usr/share/calendar/calendar.dutch OLD_FILES+=usr/share/calendar/calendar.freebsd OLD_FILES+=usr/share/calendar/calendar.french OLD_FILES+=usr/share/calendar/calendar.german OLD_FILES+=usr/share/calendar/calendar.history OLD_FILES+=usr/share/calendar/calendar.holiday OLD_FILES+=usr/share/calendar/calendar.hungarian OLD_FILES+=usr/share/calendar/calendar.judaic OLD_FILES+=usr/share/calendar/calendar.lotr OLD_FILES+=usr/share/calendar/calendar.music OLD_FILES+=usr/share/calendar/calendar.newzealand OLD_FILES+=usr/share/calendar/calendar.russian OLD_FILES+=usr/share/calendar/calendar.southafrica OLD_FILES+=usr/share/calendar/calendar.ukrainian OLD_FILES+=usr/share/calendar/calendar.usholiday OLD_FILES+=usr/share/calendar/calendar.world OLD_FILES+=usr/share/calendar/de_AT.ISO_8859-15/calendar.feiertag OLD_DIRS+=usr/share/calendar/de_AT.ISO_8859-15 OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.feiertag OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.geschichte OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.kirche OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.literatur OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.musik OLD_FILES+=usr/share/calendar/de_DE.ISO8859-1/calendar.wissenschaft OLD_DIRS+=usr/share/calendar/de_DE.ISO8859-1 OLD_FILES+=usr/share/calendar/de_DE.ISO8859-15 OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.fetes OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.french OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.jferies OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-1/calendar.proverbes OLD_DIRS+=usr/share/calendar/fr_FR.ISO8859-1 OLD_FILES+=usr/share/calendar/fr_FR.ISO8859-15 OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.all OLD_FILES+=usr/share/calendar/hr_HR.ISO8859-2/calendar.praznici OLD_DIRS+=usr/share/calendar/hr_HR.ISO8859-2 OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.all OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.nevnapok OLD_FILES+=usr/share/calendar/hu_HU.ISO8859-2/calendar.unnepek OLD_DIRS+=usr/share/calendar/hu_HU.ISO8859-2 OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.all OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.commemorative OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.holidays OLD_FILES+=usr/share/calendar/pt_BR.ISO8859-1/calendar.mcommemorative OLD_DIRS+=usr/share/calendar/pt_BR.ISO8859-1 OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.all OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.commemorative OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.holidays OLD_FILES+=usr/share/calendar/pt_BR.UTF-8/calendar.mcommemorative OLD_DIRS+=usr/share/calendar/pt_BR.UTF-8 OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.all OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.common OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.holiday OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.military OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.orthodox OLD_FILES+=usr/share/calendar/ru_RU.KOI8-R/calendar.pagan OLD_DIRS+=usr/share/calendar/ru_RU.KOI8-R OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.all OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.common OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.holiday OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.military OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.orthodox OLD_FILES+=usr/share/calendar/ru_RU.UTF-8/calendar.pagan OLD_DIRS+=usr/share/calendar/ru_RU.UTF-8 OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.all OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.holiday OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.misc OLD_FILES+=usr/share/calendar/uk_UA.KOI8-U/calendar.orthodox OLD_DIRS+=usr/share/calendar/uk_UA.KOI8-U OLD_DIRS+=usr/share/calendar OLD_FILES+=usr/share/man/man1/calendar.1.gz OLD_FILES+=usr/tests/usr.bin/calendar/Kyuafile OLD_FILES+=usr/tests/usr.bin/calendar/calendar.calibrate OLD_FILES+=usr/tests/usr.bin/calendar/legacy_test OLD_FILES+=usr/tests/usr.bin/calendar/regress.a1.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.a2.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.a3.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.a4.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.a5.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.b1.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.b2.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.b3.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.b4.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.b5.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.s1.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.s2.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.s3.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.s4.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.sh OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-1.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-2.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-3.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-4.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-5.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-6.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.w0-7.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-1.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-2.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-3.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-4.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-5.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-6.out OLD_FILES+=usr/tests/usr.bin/calendar/regress.wn-7.out OLD_DIRS+=usr/tests/usr.bin/calendar .endif .if ${MK_CASPER} == no OLD_LIBS+=lib/libcasper.so.1 OLD_LIBS+=lib/casper/libcap_dns.so.2 OLD_LIBS+=lib/casper/libcap_fileargs.so.1 OLD_LIBS+=lib/casper/libcap_grp.so.1 OLD_LIBS+=lib/casper/libcap_net.so.1 OLD_LIBS+=lib/casper/libcap_pwd.so.1 OLD_LIBS+=lib/casper/libcap_sysctl.so.1 OLD_LIBS+=lib/casper/libcap_sysctl.so.2 OLD_LIBS+=lib/casper/libcap_syslog.so.1 .endif .if ${MK_CCD} == no OLD_FILES+=etc/rc.d/ccd OLD_FILES+=rescue/ccdconfig OLD_FILES+=sbin/ccdconfig OLD_FILES+=usr/share/man/man4/ccd.4.gz OLD_FILES+=usr/share/man/man8/ccdconfig.8.gz .endif .if ${MK_CDDL} == no OLD_LIBS+=lib/libavl.so.2 OLD_LIBS+=lib/libctf.so.2 OLD_LIBS+=lib/libdtrace.so.2 OLD_LIBS+=lib/libnvpair.so.2 OLD_LIBS+=lib/libumem.so.2 OLD_LIBS+=lib/libuutil.so.2 OLD_FILES+=usr/bin/ctfconvert OLD_FILES+=usr/bin/ctfdump OLD_FILES+=usr/bin/ctfmerge OLD_FILES+=usr/lib/dtrace/drti.o OLD_FILES+=usr/lib/dtrace/errno.d OLD_FILES+=usr/lib/dtrace/io.d OLD_FILES+=usr/lib/dtrace/ip.d OLD_FILES+=usr/lib/dtrace/mbuf.d OLD_FILES+=usr/lib/dtrace/psinfo.d .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "i386" OLD_FILES+=usr/lib/dtrace/regs_x86.d .endif OLD_FILES+=usr/lib/dtrace/sctp.d OLD_FILES+=usr/lib/dtrace/siftr.d OLD_FILES+=usr/lib/dtrace/signal.d OLD_FILES+=usr/lib/dtrace/socket.d OLD_FILES+=usr/lib/dtrace/tcp.d OLD_FILES+=usr/lib/dtrace/udp.d OLD_FILES+=usr/lib/dtrace/udplite.d OLD_FILES+=usr/lib/dtrace/unistd.d OLD_FILES+=usr/lib/libavl.a OLD_FILES+=usr/lib/libavl.so OLD_FILES+=usr/lib/libavl_p.a OLD_FILES+=usr/lib/libctf.a OLD_FILES+=usr/lib/libctf.so OLD_FILES+=usr/lib/libctf_p.a OLD_FILES+=usr/lib/libdtrace.a OLD_FILES+=usr/lib/libdtrace.so OLD_FILES+=usr/lib/libdtrace_p.a OLD_FILES+=usr/lib/libnvpair.a OLD_FILES+=usr/lib/libnvpair.so OLD_FILES+=usr/lib/libnvpair_p.a OLD_FILES+=usr/lib/libumem.a OLD_FILES+=usr/lib/libumem.so OLD_FILES+=usr/lib/libumem_p.a OLD_FILES+=usr/lib/libuutil.a OLD_FILES+=usr/lib/libuutil.so OLD_FILES+=usr/lib/libuutil_p.a .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/libexec/dwatch/chmod OLD_FILES+=usr/libexec/dwatch/errno OLD_FILES+=usr/libexec/dwatch/fchmodat OLD_FILES+=usr/libexec/dwatch/io OLD_FILES+=usr/libexec/dwatch/io-done OLD_FILES+=usr/libexec/dwatch/io-start OLD_FILES+=usr/libexec/dwatch/ip OLD_FILES+=usr/libexec/dwatch/ip-receive OLD_FILES+=usr/libexec/dwatch/ip-send OLD_FILES+=usr/libexec/dwatch/kill OLD_FILES+=usr/libexec/dwatch/lchmod OLD_FILES+=usr/libexec/dwatch/nanosleep OLD_FILES+=usr/libexec/dwatch/open OLD_FILES+=usr/libexec/dwatch/openat OLD_FILES+=usr/libexec/dwatch/proc OLD_FILES+=usr/libexec/dwatch/proc-create OLD_FILES+=usr/libexec/dwatch/proc-exec OLD_FILES+=usr/libexec/dwatch/proc-exec-failure OLD_FILES+=usr/libexec/dwatch/proc-exec-success OLD_FILES+=usr/libexec/dwatch/proc-exit OLD_FILES+=usr/libexec/dwatch/proc-signal OLD_FILES+=usr/libexec/dwatch/proc-signal-clear OLD_FILES+=usr/libexec/dwatch/proc-signal-discard OLD_FILES+=usr/libexec/dwatch/proc-signal-send OLD_FILES+=usr/libexec/dwatch/proc-status OLD_FILES+=usr/libexec/dwatch/read OLD_FILES+=usr/libexec/dwatch/recv OLD_FILES+=usr/libexec/dwatch/recvfrom OLD_FILES+=usr/libexec/dwatch/recvmsg OLD_FILES+=usr/libexec/dwatch/rw OLD_FILES+=usr/libexec/dwatch/sched OLD_FILES+=usr/libexec/dwatch/sched-change-pri OLD_FILES+=usr/libexec/dwatch/sched-cpu OLD_FILES+=usr/libexec/dwatch/sched-dequeue OLD_FILES+=usr/libexec/dwatch/sched-enqueue OLD_FILES+=usr/libexec/dwatch/sched-exec OLD_FILES+=usr/libexec/dwatch/sched-lend-pri OLD_FILES+=usr/libexec/dwatch/sched-load-change OLD_FILES+=usr/libexec/dwatch/sched-off-cpu OLD_FILES+=usr/libexec/dwatch/sched-on-cpu OLD_FILES+=usr/libexec/dwatch/sched-preempt OLD_FILES+=usr/libexec/dwatch/sched-pri OLD_FILES+=usr/libexec/dwatch/sched-queue OLD_FILES+=usr/libexec/dwatch/sched-remain-cpu OLD_FILES+=usr/libexec/dwatch/sched-sleep OLD_FILES+=usr/libexec/dwatch/sched-surrender OLD_FILES+=usr/libexec/dwatch/sched-tick OLD_FILES+=usr/libexec/dwatch/sched-wakeup OLD_FILES+=usr/libexec/dwatch/send OLD_FILES+=usr/libexec/dwatch/sendmsg OLD_FILES+=usr/libexec/dwatch/sendrecv OLD_FILES+=usr/libexec/dwatch/sendto OLD_FILES+=usr/libexec/dwatch/systop OLD_FILES+=usr/libexec/dwatch/tcp OLD_FILES+=usr/libexec/dwatch/tcp-accept OLD_FILES+=usr/libexec/dwatch/tcp-accept-established OLD_FILES+=usr/libexec/dwatch/tcp-accept-refused OLD_FILES+=usr/libexec/dwatch/tcp-connect OLD_FILES+=usr/libexec/dwatch/tcp-connect-established OLD_FILES+=usr/libexec/dwatch/tcp-connect-refused OLD_FILES+=usr/libexec/dwatch/tcp-connect-request OLD_FILES+=usr/libexec/dwatch/tcp-established OLD_FILES+=usr/libexec/dwatch/tcp-init OLD_FILES+=usr/libexec/dwatch/tcp-io OLD_FILES+=usr/libexec/dwatch/tcp-receive OLD_FILES+=usr/libexec/dwatch/tcp-refused OLD_FILES+=usr/libexec/dwatch/tcp-send OLD_FILES+=usr/libexec/dwatch/tcp-state-change OLD_FILES+=usr/libexec/dwatch/tcp-status OLD_FILES+=usr/libexec/dwatch/udp OLD_FILES+=usr/libexec/dwatch/udp-receive OLD_FILES+=usr/libexec/dwatch/udp-send OLD_FILES+=usr/libexec/dwatch/udplite OLD_FILES+=usr/libexec/dwatch/udplite-receive OLD_FILES+=usr/libexec/dwatch/udplite-send OLD_FILES+=usr/libexec/dwatch/vop_create OLD_FILES+=usr/libexec/dwatch/vop_lookup OLD_FILES+=usr/libexec/dwatch/vop_mkdir OLD_FILES+=usr/libexec/dwatch/vop_mknod OLD_FILES+=usr/libexec/dwatch/vop_readdir OLD_FILES+=usr/libexec/dwatch/vop_remove OLD_FILES+=usr/libexec/dwatch/vop_rename OLD_FILES+=usr/libexec/dwatch/vop_rmdir OLD_FILES+=usr/libexec/dwatch/vop_symlink OLD_FILES+=usr/libexec/dwatch/write OLD_FILES+=usr/sbin/dtrace OLD_FILES+=usr/sbin/dwatch OLD_FILES+=usr/sbin/lockstat OLD_FILES+=usr/sbin/plockstat OLD_FILES+=usr/share/man/man1/dtrace.1.gz OLD_FILES+=usr/share/man/man1/dtruss.1.gz OLD_FILES+=usr/share/man/man1/lockstat.1.gz OLD_FILES+=usr/share/man/man1/plockstat.1.gz OLD_FILES+=usr/share/dtrace/blocking OLD_FILES+=usr/share/dtrace/disklatency OLD_FILES+=usr/share/dtrace/disklatencycmd OLD_FILES+=usr/share/dtrace/hotopen OLD_FILES+=usr/share/dtrace/nfsattrstats OLD_FILES+=usr/share/dtrace/nfsclienttime OLD_FILES+=usr/share/dtrace/siftr OLD_FILES+=usr/share/dtrace/toolkit/execsnoop OLD_FILES+=usr/share/dtrace/toolkit/hotkernel OLD_FILES+=usr/share/dtrace/toolkit/hotuser OLD_FILES+=usr/share/dtrace/toolkit/opensnoop OLD_FILES+=usr/share/dtrace/toolkit/procsystime OLD_FILES+=usr/share/dtrace/tcpconn OLD_FILES+=usr/share/dtrace/tcpdebug OLD_FILES+=usr/share/dtrace/tcpstate OLD_FILES+=usr/share/dtrace/tcptrack OLD_FILES+=usr/share/dtrace/udptrack OLD_FILES+=usr/share/man/man1/dtrace.1.gz OLD_DIRS+=usr/lib/dtrace OLD_DIRS+=usr/lib32/dtrace OLD_DIRS+=usr/libexec/dwatch OLD_DIRS+=usr/share/dtrace/toolkit OLD_DIRS+=usr/share/dtrace .endif .if ${MK_ZFS} == no OLD_FILES+=boot/gptzfsboot OLD_FILES+=boot/zfsboot OLD_FILES+=boot/zfsloader OLD_FILES+=etc/rc.d/zfs OLD_FILES+=etc/rc.d/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_FILES+=etc/zfs/exports OLD_DIRS+=etc/zfs OLD_LIBS+=lib/libzfs.so.2 OLD_LIBS+=lib/libzfs.so.3 OLD_LIBS+=lib/libzfs_core.so.2 OLD_LIBS+=lib/libzpool.so.2 OLD_FILES+=rescue/zdb OLD_FILES+=rescue/zfs OLD_FILES+=rescue/zpool OLD_FILES+=sbin/bectl OLD_FILES+=sbin/zfs OLD_FILES+=sbin/zpool OLD_FILES+=sbin/zfsbootcfg OLD_FILES+=usr/bin/zinject OLD_FILES+=usr/bin/zstreamdump OLD_FILES+=usr/bin/ztest OLD_FILES+=usr/lib/libbe.a OLD_FILES+=usr/lib/libbe_p.a OLD_FILES+=usr/lib/libbe.so OLD_LIBS+=lib/libbe.so.1 OLD_FILES+=usr/lib/libzfs.a OLD_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-addr2line OLD_FILES+=usr/bin/llvm-ar OLD_FILES+=usr/bin/llvm-nm OLD_FILES+=usr/bin/llvm-objdump OLD_FILES+=usr/bin/llvm-ranlib OLD_FILES+=usr/bin/llvm-symbolizer OLD_FILES+=usr/bin/llvm-tblgen OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/algorithm OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/complex OLD_FILES+=usr/lib/clang/10.0.1/include/cuda_wrappers/new OLD_DIRS+=usr/lib/clang/10.0.1/include/cuda_wrappers OLD_FILES+=usr/lib/clang/10.0.1/include/fuzzer/FuzzedDataProvider.h OLD_DIRS+=usr/lib/clang/10.0.1/include/fuzzer OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/__clang_openmp_math.h OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/__clang_openmp_math_declares.h OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/cmath OLD_FILES+=usr/lib/clang/10.0.1/include/openmp_wrappers/math.h OLD_DIRS+=usr/lib/clang/10.0.1/include/openmp_wrappers OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/emmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/mm_malloc.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/mmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/pmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/smmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/tmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ppc_wrappers/xmmintrin.h OLD_DIRS+=usr/lib/clang/10.0.1/include/ppc_wrappers OLD_FILES+=usr/lib/clang/10.0.1/include/profile/InstrProfData.inc OLD_DIRS+=usr/lib/clang/10.0.1/include/profile OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/asan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/common_interface_defs.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/coverage_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/dfsan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/hwasan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/linux_syscall_hooks.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/lsan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/msan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/netbsd_syscall_hooks.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/scudo_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/tsan_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/tsan_interface_atomic.h OLD_FILES+=usr/lib/clang/10.0.1/include/sanitizer/ubsan_interface.h OLD_DIRS+=usr/lib/clang/10.0.1/include/sanitizer OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_log_interface.h OLD_FILES+=usr/lib/clang/10.0.1/include/xray/xray_records.h OLD_DIRS+=usr/lib/clang/10.0.1/include/xray OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_builtin_vars.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_cmath.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_complex_builtins.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_device_functions.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_intrinsics.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_libdevice_declares.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_math_forward_declares.h OLD_FILES+=usr/lib/clang/10.0.1/include/__clang_cuda_runtime_wrapper.h OLD_FILES+=usr/lib/clang/10.0.1/include/__stddef_max_align_t.h OLD_FILES+=usr/lib/clang/10.0.1/include/__wmmintrin_aes.h OLD_FILES+=usr/lib/clang/10.0.1/include/__wmmintrin_pclmul.h OLD_FILES+=usr/lib/clang/10.0.1/include/adxintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/altivec.h OLD_FILES+=usr/lib/clang/10.0.1/include/ammintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm64intr.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_acle.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_cmse.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_fp16.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_mve.h OLD_FILES+=usr/lib/clang/10.0.1/include/arm_neon.h OLD_FILES+=usr/lib/clang/10.0.1/include/armintr.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx2intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bf16intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bitalgintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512bwintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512cdintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512dqintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512erintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512fintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512ifmaintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512ifmavlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512pfintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmiintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vbmivlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbf16intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbitalgintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlbwintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlcdintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vldqintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvbmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvnniintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vlvp2intersectintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vnniintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vp2intersectintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vpopcntdqintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avx512vpopcntdqvlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/avxintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/bmi2intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/bmiintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/cetintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/cldemoteintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/clflushoptintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/clwbintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/clzerointrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/cpuid.h OLD_FILES+=usr/lib/clang/10.0.1/include/emmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/enqcmdintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/f16cintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/float.h OLD_FILES+=usr/lib/clang/10.0.1/include/fma4intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/fmaintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/fxsrintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/gfniintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/htmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/htmxlintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ia32intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/immintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/inttypes.h OLD_FILES+=usr/lib/clang/10.0.1/include/invpcidintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/iso646.h OLD_FILES+=usr/lib/clang/10.0.1/include/limits.h OLD_FILES+=usr/lib/clang/10.0.1/include/lwpintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/lzcntintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/mm3dnow.h OLD_FILES+=usr/lib/clang/10.0.1/include/mm_malloc.h OLD_FILES+=usr/lib/clang/10.0.1/include/mmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/module.modulemap OLD_FILES+=usr/lib/clang/10.0.1/include/movdirintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/msa.h OLD_FILES+=usr/lib/clang/10.0.1/include/mwaitxintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/nmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/omp-tools.h OLD_FILES+=usr/lib/clang/10.0.1/include/omp.h OLD_FILES+=usr/lib/clang/10.0.1/include/ompt.h OLD_FILES+=usr/lib/clang/10.0.1/include/opencl-c-base.h OLD_FILES+=usr/lib/clang/10.0.1/include/opencl-c.h OLD_FILES+=usr/lib/clang/10.0.1/include/pconfigintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/pkuintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/pmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/popcntintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/prfchwintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/ptwriteintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/rdseedintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/rtmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/s390intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/sgxintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/shaintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/smmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/stdalign.h OLD_FILES+=usr/lib/clang/10.0.1/include/stdarg.h OLD_FILES+=usr/lib/clang/10.0.1/include/stdatomic.h OLD_FILES+=usr/lib/clang/10.0.1/include/stdbool.h OLD_FILES+=usr/lib/clang/10.0.1/include/stddef.h OLD_FILES+=usr/lib/clang/10.0.1/include/stdint.h OLD_FILES+=usr/lib/clang/10.0.1/include/stdnoreturn.h OLD_FILES+=usr/lib/clang/10.0.1/include/tbmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/tgmath.h OLD_FILES+=usr/lib/clang/10.0.1/include/tmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/unwind.h OLD_FILES+=usr/lib/clang/10.0.1/include/vadefs.h OLD_FILES+=usr/lib/clang/10.0.1/include/vaesintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/varargs.h OLD_FILES+=usr/lib/clang/10.0.1/include/vecintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/vpclmulqdqintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/waitpkgintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/wbnoinvdintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/wmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/x86intrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xmmintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xopintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xsavecintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xsaveintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xsaveoptintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xsavesintrin.h OLD_FILES+=usr/lib/clang/10.0.1/include/xtestintrin.h OLD_DIRS+=usr/lib/clang/10.0.1/include OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-aarch64.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-arm.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-armhf.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-i386.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-preinit-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan-x86_64.so OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.asan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.cfi_diag-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.dd-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.dd-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.msan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-powerpc.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-powerpc64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.profile-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.safestack-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.stats_client-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-basic-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-fdr-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-aarch64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-arm.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-armhf.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-profiling-x86_64.a OLD_FILES+=usr/lib/clang/10.0.1/lib/freebsd/libclang_rt.xray-x86_64.a OLD_DIRS+=usr/lib/clang/10.0.1/lib/freebsd OLD_DIRS+=usr/lib/clang/10.0.1/lib OLD_DIRS+=usr/lib/clang/10.0.1 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-addr2line.1.gz OLD_FILES+=usr/share/man/man1/llvm-ar.1.gz OLD_FILES+=usr/share/man/man1/llvm-nm.1.gz OLD_FILES+=usr/share/man/man1/llvm-ranlib.1.gz OLD_FILES+=usr/share/man/man1/llvm-symbolizer.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/llc OLD_FILES+=usr/bin/lli OLD_FILES+=usr/bin/llvm-as OLD_FILES+=usr/bin/llvm-bcanalyzer OLD_FILES+=usr/bin/llvm-cxxdump OLD_FILES+=usr/bin/llvm-cxxfilt OLD_FILES+=usr/bin/llvm-diff OLD_FILES+=usr/bin/llvm-dis OLD_FILES+=usr/bin/llvm-dwarfdump +OLD_FILES+=usr/bin/llvm-dwp OLD_FILES+=usr/bin/llvm-extract OLD_FILES+=usr/bin/llvm-link OLD_FILES+=usr/bin/llvm-lto OLD_FILES+=usr/bin/llvm-lto2 OLD_FILES+=usr/bin/llvm-mc OLD_FILES+=usr/bin/llvm-mca OLD_FILES+=usr/bin/llvm-modextract OLD_FILES+=usr/bin/llvm-objcopy OLD_FILES+=usr/bin/llvm-pdbutil OLD_FILES+=usr/bin/llvm-rtdyld +OLD_FILES+=usr/bin/llvm-size +OLD_FILES+=usr/bin/llvm-strings OLD_FILES+=usr/bin/llvm-xray OLD_FILES+=usr/bin/opt OLD_FILES+=usr/share/man/man1/bugpoint.1.gz OLD_FILES+=usr/share/man/man1/llc.1.gz OLD_FILES+=usr/share/man/man1/lli.1.gz OLD_FILES+=usr/share/man/man1/llvm-as.1.gz OLD_FILES+=usr/share/man/man1/llvm-bcanalyzer.1.gz OLD_FILES+=usr/share/man/man1/llvm-cxxfilt.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-objcopy.1.gz OLD_FILES+=usr/share/man/man1/llvm-pdbutil.1.gz +OLD_FILES+=usr/share/man/man1/llvm-size.1.gz +OLD_FILES+=usr/share/man/man1/llvm-strings.1.gz OLD_FILES+=usr/share/man/man1/opt.1.gz .endif .if ${MK_CLANG_EXTRAS} == no && ${MK_CLANG_FORMAT} == no OLD_FILES+=usr/bin/clang-format .endif .if ${MK_CPP} == no OLD_FILES+=usr/bin/cpp OLD_FILES+=usr/share/man/man1/cpp.1.gz .endif .if ${MK_CUSE} == no OLD_FILES+=usr/include/fs/cuse/cuse_defs.h OLD_FILES+=usr/include/fs/cuse/cuse_ioctl.h OLD_FILES+=usr/include/cuse.h OLD_FILES+=usr/lib/libcuse.a OLD_LIBS+=usr/lib/libcuse.so.1 OLD_FILES+=usr/lib/libcuse_p.a OLD_FILES+=usr/share/man/man3/cuse.3.gz OLD_FILES+=usr/share/man/man3/cuse_alloc_unit_number.3.gz OLD_FILES+=usr/share/man/man3/cuse_alloc_unit_number_by_id.3.gz OLD_FILES+=usr/share/man/man3/cuse_copy_in.3.gz OLD_FILES+=usr/share/man/man3/cuse_copy_out.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_create.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_destroy.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_get_current.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_get_per_file_handle.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_get_priv0.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_get_priv1.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_set_per_file_handle.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_set_priv0.3.gz OLD_FILES+=usr/share/man/man3/cuse_dev_set_priv1.3.gz OLD_FILES+=usr/share/man/man3/cuse_free_unit_number.3.gz OLD_FILES+=usr/share/man/man3/cuse_free_unit_number_by_id.3.gz OLD_FILES+=usr/share/man/man3/cuse_get_local.3.gz OLD_FILES+=usr/share/man/man3/cuse_got_peer_signal.3.gz OLD_FILES+=usr/share/man/man3/cuse_init.3.gz OLD_FILES+=usr/share/man/man3/cuse_is_vmalloc_addr.3.gz OLD_FILES+=usr/share/man/man3/cuse_poll_wakeup.3.gz OLD_FILES+=usr/share/man/man3/cuse_set_local.3.gz OLD_FILES+=usr/share/man/man3/cuse_uninit.3.gz OLD_FILES+=usr/share/man/man3/cuse_vmalloc.3.gz OLD_FILES+=usr/share/man/man3/cuse_vmfree.3.gz OLD_FILES+=usr/share/man/man3/cuse_vmoffset.3.gz OLD_FILES+=usr/share/man/man3/cuse_wait_and_process.3.gz OLD_DIRS+=usr/include/fs/cuse .endif # 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 OLD_DIRS+=usr/share/bsdconfig OLD_DIRS+=usr/share/bsdconfig/media OLD_DIRS+=usr/share/bsdconfig/networking OLD_DIRS+=usr/share/bsdconfig/packages OLD_DIRS+=usr/share/bsdconfig/password OLD_DIRS+=usr/share/bsdconfig/startup OLD_DIRS+=usr/share/bsdconfig/timezone OLD_DIRS+=usr/share/bsdconfig/usermgmt .endif .if ${MK_EFI} == no OLD_FILES+=usr/sbin/efibootmgr OLD_FILES+=usr/sbin/efidp OLD_FILES+=usr/sbin/efivar OLD_FILES+=usr/sbin/uefisign OLD_FILES+=usr/share/examples/uefisign/uefikeys .endif .if ${MK_FMTREE} == no OLD_FILES+=usr/sbin/fmtree OLD_FILES+=usr/share/man/man8/fmtree.8.gz .endif .if ${MK_FTP} == no OLD_FILES+=etc/ftpusers OLD_FILES+=etc/newsyslog.conf.d/ftp.conf OLD_FILES+=etc/pam.d/ftp OLD_FILES+=etc/pam.d/ftpd OLD_FILES+=etc/rc.d/ftpd OLD_FILES+=etc/syslog.d/ftp.conf OLD_FILES+=usr/bin/ftp OLD_FILES+=usr/bin/gate-ftp OLD_FILES+=usr/bin/pftp OLD_FILES+=usr/libexec/ftpd OLD_FILES+=usr/share/man/man1/ftp.1.gz OLD_FILES+=usr/share/man/man1/gate-ftp.1.gz OLD_FILES+=usr/share/man/man1/pftp.1.gz OLD_FILES+=usr/share/man/man5/ftpchroot.5.gz OLD_FILES+=usr/share/man/man8/ftpd.8.gz .endif .if ${MK_DICT} == no OLD_FILES+=usr/share/dict/README OLD_FILES+=usr/share/dict/freebsd OLD_FILES+=usr/share/dict/propernames OLD_FILES+=usr/share/dict/web2 OLD_FILES+=usr/share/dict/web2a OLD_FILES+=usr/share/dict/words OLD_DIRS+=usr/share/dict .endif .if ${MK_DMAGENT} == no OLD_FILES+=etc/dma/dma.conf OLD_DIRS+=etc/dma OLD_FILES+=usr/libexec/dma OLD_FILES+=usr/libexec/dma-mbox-create OLD_FILES+=usr/share/man/man8/dma.8.gz OLD_FILES+=usr/share/examples/dma/mailer.conf .endif .if ${MK_EE} == no OLD_FILES+=usr/bin/edit OLD_FILES+=usr/bin/ee OLD_FILES+=usr/bin/ree OLD_FILES+=usr/share/man/man1/edit.1.gz OLD_FILES+=usr/share/man/man1/ee.1.gz OLD_FILES+=usr/share/man/man1/ree.1.gz OLD_FILES+=usr/share/nls/C/ee.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/ee.cat OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/ee.cat OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/ee.cat OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/ee.cat .endif .if ${MK_EXAMPLES} == no OLD_FILES+=usr/share/examples/BSD_daemon/FreeBSD.pfa OLD_FILES+=usr/share/examples/BSD_daemon/README OLD_FILES+=usr/share/examples/BSD_daemon/beastie.eps OLD_FILES+=usr/share/examples/BSD_daemon/beastie.fig OLD_FILES+=usr/share/examples/BSD_daemon/eps.patch OLD_FILES+=usr/share/examples/BSD_daemon/poster.sh OLD_FILES+=usr/share/examples/FreeBSD_version/FreeBSD_version.c OLD_FILES+=usr/share/examples/FreeBSD_version/Makefile OLD_FILES+=usr/share/examples/FreeBSD_version/README OLD_FILES+=usr/share/examples/IPv6/USAGE OLD_FILES+=usr/share/examples/bhyve/vmrun.sh OLD_FILES+=usr/share/examples/bootforth/README OLD_FILES+=usr/share/examples/bootforth/boot.4th OLD_FILES+=usr/share/examples/bootforth/frames.4th OLD_FILES+=usr/share/examples/bootforth/loader.rc OLD_FILES+=usr/share/examples/bootforth/menu.4th OLD_FILES+=usr/share/examples/bootforth/menuconf.4th OLD_FILES+=usr/share/examples/bootforth/screen.4th OLD_FILES+=usr/share/examples/bsdconfig/add_some_packages.sh OLD_FILES+=usr/share/examples/bsdconfig/browse_packages_http.sh OLD_FILES+=usr/share/examples/bsdconfig/bsdconfigrc OLD_FILES+=usr/share/examples/csh/dot.cshrc OLD_FILES+=usr/share/examples/diskless/ME OLD_FILES+=usr/share/examples/diskless/README.BOOTP OLD_FILES+=usr/share/examples/diskless/README.TEMPLATING OLD_FILES+=usr/share/examples/diskless/clone_root OLD_FILES+=usr/share/examples/dma/mailer.conf OLD_FILES+=usr/share/examples/drivers/README OLD_FILES+=usr/share/examples/drivers/make_device_driver.sh OLD_FILES+=usr/share/examples/drivers/make_pseudo_driver.sh OLD_FILES+=usr/share/examples/dwatch/profile_template OLD_FILES+=usr/share/examples/etc/README.examples OLD_FILES+=usr/share/examples/etc/bsd-style-copyright OLD_FILES+=usr/share/examples/etc/group OLD_FILES+=usr/share/examples/etc/login.access OLD_FILES+=usr/share/examples/etc/make.conf OLD_FILES+=usr/share/examples/etc/rc.bsdextended OLD_FILES+=usr/share/examples/etc/rc.firewall OLD_FILES+=usr/share/examples/etc/rc.sendmail OLD_FILES+=usr/share/examples/etc/termcap.small OLD_FILES+=usr/share/examples/etc/wpa_supplicant.conf OLD_FILES+=usr/share/examples/find_interface/Makefile OLD_FILES+=usr/share/examples/find_interface/README OLD_FILES+=usr/share/examples/find_interface/find_interface.c OLD_FILES+=usr/share/examples/hast/ucarp.sh OLD_FILES+=usr/share/examples/hast/ucarp_down.sh OLD_FILES+=usr/share/examples/hast/ucarp_up.sh OLD_FILES+=usr/share/examples/hast/vip-down.sh OLD_FILES+=usr/share/examples/hast/vip-up.sh OLD_FILES+=usr/share/examples/hostapd/hostapd.conf OLD_FILES+=usr/share/examples/hostapd/hostapd.eap_user OLD_FILES+=usr/share/examples/hostapd/hostapd.wpa_psk OLD_FILES+=usr/share/examples/indent/indent.pro OLD_FILES+=usr/share/examples/ipfilter/BASIC.NAT OLD_FILES+=usr/share/examples/ipfilter/BASIC_1.FW OLD_FILES+=usr/share/examples/ipfilter/BASIC_2.FW OLD_FILES+=usr/share/examples/ipfilter/README OLD_FILES+=usr/share/examples/ipfilter/example.1 OLD_FILES+=usr/share/examples/ipfilter/example.10 OLD_FILES+=usr/share/examples/ipfilter/example.11 OLD_FILES+=usr/share/examples/ipfilter/example.12 OLD_FILES+=usr/share/examples/ipfilter/example.13 OLD_FILES+=usr/share/examples/ipfilter/example.14 OLD_FILES+=usr/share/examples/ipfilter/example.2 OLD_FILES+=usr/share/examples/ipfilter/example.3 OLD_FILES+=usr/share/examples/ipfilter/example.4 OLD_FILES+=usr/share/examples/ipfilter/example.5 OLD_FILES+=usr/share/examples/ipfilter/example.6 OLD_FILES+=usr/share/examples/ipfilter/example.7 OLD_FILES+=usr/share/examples/ipfilter/example.8 OLD_FILES+=usr/share/examples/ipfilter/example.9 OLD_FILES+=usr/share/examples/ipfilter/example.sr OLD_FILES+=usr/share/examples/ipfilter/examples.txt OLD_FILES+=usr/share/examples/ipfilter/firewall OLD_FILES+=usr/share/examples/ipfilter/firewall.1 OLD_FILES+=usr/share/examples/ipfilter/firewall.2 OLD_FILES+=usr/share/examples/ipfilter/ftp-proxy OLD_FILES+=usr/share/examples/ipfilter/ftppxy OLD_FILES+=usr/share/examples/ipfilter/ipf-howto.txt OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.permissive OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.restrictive OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.sample OLD_FILES+=usr/share/examples/ipfilter/ipnat.conf.sample OLD_FILES+=usr/share/examples/ipfilter/mkfilters OLD_FILES+=usr/share/examples/ipfilter/nat-setup OLD_FILES+=usr/share/examples/ipfilter/nat.eg OLD_FILES+=usr/share/examples/ipfilter/rules.txt OLD_FILES+=usr/share/examples/ipfilter/server OLD_FILES+=usr/share/examples/ipfilter/tcpstate OLD_FILES+=usr/share/examples/ipfw/change_rules.sh OLD_FILES+=usr/share/examples/jails/README OLD_FILES+=usr/share/examples/jails/VIMAGE OLD_FILES+=usr/share/examples/jails/jail.xxx.conf OLD_FILES+=usr/share/examples/jails/jib OLD_FILES+=usr/share/examples/jails/jng OLD_FILES+=usr/share/examples/jails/rc.conf.jails OLD_FILES+=usr/share/examples/jails/rcjail.xxx.conf OLD_FILES+=usr/share/examples/kld/Makefile OLD_FILES+=usr/share/examples/kld/cdev/Makefile OLD_FILES+=usr/share/examples/kld/cdev/README OLD_FILES+=usr/share/examples/kld/cdev/module/Makefile OLD_FILES+=usr/share/examples/kld/cdev/module/cdev.c OLD_FILES+=usr/share/examples/kld/cdev/module/cdev.h OLD_FILES+=usr/share/examples/kld/cdev/module/cdevmod.c OLD_FILES+=usr/share/examples/kld/cdev/test/Makefile OLD_FILES+=usr/share/examples/kld/cdev/test/testcdev.c OLD_FILES+=usr/share/examples/kld/dyn_sysctl/Makefile OLD_FILES+=usr/share/examples/kld/dyn_sysctl/README OLD_FILES+=usr/share/examples/kld/dyn_sysctl/dyn_sysctl.c OLD_FILES+=usr/share/examples/kld/firmware/Makefile OLD_FILES+=usr/share/examples/kld/firmware/README OLD_FILES+=usr/share/examples/kld/firmware/fwconsumer/Makefile OLD_FILES+=usr/share/examples/kld/firmware/fwconsumer/fw_consumer.c OLD_FILES+=usr/share/examples/kld/firmware/fwimage/Makefile OLD_FILES+=usr/share/examples/kld/firmware/fwimage/firmware.img.uu OLD_FILES+=usr/share/examples/kld/khelp/Makefile OLD_FILES+=usr/share/examples/kld/khelp/README OLD_FILES+=usr/share/examples/kld/khelp/h_example.c OLD_FILES+=usr/share/examples/kld/syscall/Makefile OLD_FILES+=usr/share/examples/kld/syscall/module/Makefile OLD_FILES+=usr/share/examples/kld/syscall/module/syscall.c OLD_FILES+=usr/share/examples/kld/syscall/test/Makefile OLD_FILES+=usr/share/examples/kld/syscall/test/call.c OLD_FILES+=usr/share/examples/libusb20/Makefile OLD_FILES+=usr/share/examples/libusb20/README OLD_FILES+=usr/share/examples/libusb20/bulk.c OLD_FILES+=usr/share/examples/libusb20/control.c OLD_FILES+=usr/share/examples/libusb20/util.c OLD_FILES+=usr/share/examples/libusb20/util.h OLD_FILES+=usr/share/examples/libvgl/Makefile OLD_FILES+=usr/share/examples/libvgl/demo.c OLD_FILES+=usr/share/examples/mdoc/POSIX-copyright OLD_FILES+=usr/share/examples/mdoc/deshallify.sh OLD_FILES+=usr/share/examples/mdoc/example.1 OLD_FILES+=usr/share/examples/mdoc/example.3 OLD_FILES+=usr/share/examples/mdoc/example.4 OLD_FILES+=usr/share/examples/mdoc/example.9 OLD_FILES+=usr/share/examples/netgraph/ether.bridge OLD_FILES+=usr/share/examples/netgraph/frame_relay OLD_FILES+=usr/share/examples/netgraph/ngctl OLD_FILES+=usr/share/examples/netgraph/raw OLD_FILES+=usr/share/examples/netgraph/udp.tunnel OLD_FILES+=usr/share/examples/netgraph/virtual.chain OLD_FILES+=usr/share/examples/netgraph/virtual.lan OLD_FILES+=usr/share/examples/perfmon/Makefile OLD_FILES+=usr/share/examples/perfmon/README OLD_FILES+=usr/share/examples/perfmon/perfmon.c OLD_FILES+=usr/share/examples/pf/ackpri OLD_FILES+=usr/share/examples/pf/faq-example1 OLD_FILES+=usr/share/examples/pf/faq-example2 OLD_FILES+=usr/share/examples/pf/faq-example3 OLD_FILES+=usr/share/examples/pf/pf.conf OLD_FILES+=usr/share/examples/pf/queue1 OLD_FILES+=usr/share/examples/pf/queue2 OLD_FILES+=usr/share/examples/pf/queue3 OLD_FILES+=usr/share/examples/pf/queue4 OLD_FILES+=usr/share/examples/pf/spamd OLD_FILES+=usr/share/examples/ppi/Makefile OLD_FILES+=usr/share/examples/ppi/ppilcd.c OLD_FILES+=usr/share/examples/ppp/chap-auth OLD_FILES+=usr/share/examples/ppp/login-auth OLD_FILES+=usr/share/examples/ppp/ppp.conf.sample OLD_FILES+=usr/share/examples/ppp/ppp.conf.span-isp OLD_FILES+=usr/share/examples/ppp/ppp.conf.span-isp.working OLD_FILES+=usr/share/examples/ppp/ppp.linkdown.sample OLD_FILES+=usr/share/examples/ppp/ppp.linkdown.span-isp OLD_FILES+=usr/share/examples/ppp/ppp.linkdown.span-isp.working OLD_FILES+=usr/share/examples/ppp/ppp.linkup.sample OLD_FILES+=usr/share/examples/ppp/ppp.linkup.span-isp OLD_FILES+=usr/share/examples/ppp/ppp.linkup.span-isp.working OLD_FILES+=usr/share/examples/ppp/ppp.secret.sample OLD_FILES+=usr/share/examples/ppp/ppp.secret.span-isp OLD_FILES+=usr/share/examples/ppp/ppp.secret.span-isp.working OLD_FILES+=usr/share/examples/printing/diablo-if-net OLD_FILES+=usr/share/examples/printing/hpdf OLD_FILES+=usr/share/examples/printing/hpif OLD_FILES+=usr/share/examples/printing/hpof OLD_FILES+=usr/share/examples/printing/hprf OLD_FILES+=usr/share/examples/printing/hpvf OLD_FILES+=usr/share/examples/printing/if-simple OLD_FILES+=usr/share/examples/printing/if-simpleX OLD_FILES+=usr/share/examples/printing/ifhp OLD_FILES+=usr/share/examples/printing/make-ps-header OLD_FILES+=usr/share/examples/printing/netprint OLD_FILES+=usr/share/examples/printing/psdf OLD_FILES+=usr/share/examples/printing/psdfX OLD_FILES+=usr/share/examples/printing/psif OLD_FILES+=usr/share/examples/printing/pstf OLD_FILES+=usr/share/examples/printing/pstfX OLD_FILES+=usr/share/examples/scsi_target/Makefile OLD_FILES+=usr/share/examples/scsi_target/scsi_cmds.c OLD_FILES+=usr/share/examples/scsi_target/scsi_target.8 OLD_FILES+=usr/share/examples/scsi_target/scsi_target.c OLD_FILES+=usr/share/examples/scsi_target/scsi_target.h OLD_FILES+=usr/share/examples/ses/Makefile OLD_FILES+=usr/share/examples/ses/Makefile.inc OLD_FILES+=usr/share/examples/ses/getencstat/Makefile OLD_FILES+=usr/share/examples/ses/getencstat/getencstat.0 OLD_FILES+=usr/share/examples/ses/sesd/Makefile OLD_FILES+=usr/share/examples/ses/sesd/sesd.0 OLD_FILES+=usr/share/examples/ses/setencstat/Makefile OLD_FILES+=usr/share/examples/ses/setencstat/setencstat.0 OLD_FILES+=usr/share/examples/ses/setobjstat/Makefile OLD_FILES+=usr/share/examples/ses/setobjstat/setobjstat.0 OLD_FILES+=usr/share/examples/ses/srcs/chpmon.c OLD_FILES+=usr/share/examples/ses/srcs/eltsub.c OLD_FILES+=usr/share/examples/ses/srcs/eltsub.h OLD_FILES+=usr/share/examples/ses/srcs/getencstat.c OLD_FILES+=usr/share/examples/ses/srcs/getnobj.c OLD_FILES+=usr/share/examples/ses/srcs/getobjmap.c OLD_FILES+=usr/share/examples/ses/srcs/getobjstat.c OLD_FILES+=usr/share/examples/ses/srcs/inienc.c OLD_FILES+=usr/share/examples/ses/srcs/sesd.c OLD_FILES+=usr/share/examples/ses/srcs/setencstat.c OLD_FILES+=usr/share/examples/ses/srcs/setobjstat.c OLD_FILES+=usr/share/examples/smbfs/dot.nsmbrc OLD_FILES+=usr/share/examples/smbfs/print/lj6l OLD_FILES+=usr/share/examples/smbfs/print/ljspool OLD_FILES+=usr/share/examples/smbfs/print/printcap.sample OLD_FILES+=usr/share/examples/smbfs/print/tolj OLD_FILES+=usr/share/examples/sunrpc/Makefile OLD_FILES+=usr/share/examples/sunrpc/dir/Makefile OLD_FILES+=usr/share/examples/sunrpc/dir/dir.x OLD_FILES+=usr/share/examples/sunrpc/dir/dir_proc.c OLD_FILES+=usr/share/examples/sunrpc/dir/rls.c OLD_FILES+=usr/share/examples/sunrpc/msg/Makefile OLD_FILES+=usr/share/examples/sunrpc/msg/msg.x OLD_FILES+=usr/share/examples/sunrpc/msg/msg_proc.c OLD_FILES+=usr/share/examples/sunrpc/msg/printmsg.c OLD_FILES+=usr/share/examples/sunrpc/msg/rprintmsg.c OLD_FILES+=usr/share/examples/sunrpc/sort/Makefile OLD_FILES+=usr/share/examples/sunrpc/sort/rsort.c OLD_FILES+=usr/share/examples/sunrpc/sort/sort.x OLD_FILES+=usr/share/examples/sunrpc/sort/sort_proc.c OLD_FILES+=usr/share/examples/tcsh/complete.tcsh OLD_FILES+=usr/share/examples/tcsh/csh-mode.el OLD_FILES+=usr/share/examples/uefisign/uefikeys OLD_FILES+=usr/share/examples/ypldap/ypldap.conf OLD_DIRS+=usr/share/examples OLD_DIRS+=usr/share/examples/BSD_daemon OLD_DIRS+=usr/share/examples/FreeBSD_version OLD_DIRS+=usr/share/examples/IPv6 OLD_DIRS+=usr/share/examples/bhyve OLD_DIRS+=usr/share/examples/bootforth OLD_DIRS+=usr/share/examples/bsdconfig OLD_DIRS+=usr/share/examples/csh OLD_DIRS+=usr/share/examples/diskless OLD_DIRS+=usr/share/examples/dma OLD_DIRS+=usr/share/examples/drivers OLD_DIRS+=usr/share/examples/dwatch OLD_DIRS+=usr/share/examples/etc OLD_DIRS+=usr/share/examples/etc/defaults OLD_DIRS+=usr/share/examples/find_interface OLD_DIRS+=usr/share/examples/hast OLD_DIRS+=usr/share/examples/ibcs2 OLD_DIRS+=usr/share/examples/hostapd OLD_DIRS+=usr/share/examples/indent OLD_DIRS+=usr/share/examples/ipfilter OLD_DIRS+=usr/share/examples/ipfw OLD_DIRS+=usr/share/examples/jails OLD_DIRS+=usr/share/examples/kld OLD_DIRS+=usr/share/examples/kld/cdev OLD_DIRS+=usr/share/examples/kld/cdev/module OLD_DIRS+=usr/share/examples/kld/cdev/test OLD_DIRS+=usr/share/examples/kld/dyn_sysctl OLD_DIRS+=usr/share/examples/kld/firmware OLD_DIRS+=usr/share/examples/kld/firmware/fwconsumer OLD_DIRS+=usr/share/examples/kld/firmware/fwimage OLD_DIRS+=usr/share/examples/kld/khelp OLD_DIRS+=usr/share/examples/kld/syscall OLD_DIRS+=usr/share/examples/kld/syscall/module OLD_DIRS+=usr/share/examples/kld/syscall/test OLD_DIRS+=usr/share/examples/libusb20 OLD_DIRS+=usr/share/examples/libvgl OLD_DIRS+=usr/share/examples/mdoc OLD_DIRS+=usr/share/examples/netgraph OLD_DIRS+=usr/share/examples/perfmon OLD_DIRS+=usr/share/examples/pf OLD_DIRS+=usr/share/examples/ppi OLD_DIRS+=usr/share/examples/ppp OLD_DIRS+=usr/share/examples/printing OLD_DIRS+=usr/share/examples/scsi_target OLD_DIRS+=usr/share/examples/ses OLD_DIRS+=usr/share/examples/ses/getencstat OLD_DIRS+=usr/share/examples/ses/sesd OLD_DIRS+=usr/share/examples/ses/setencstat OLD_DIRS+=usr/share/examples/ses/setobjstat OLD_DIRS+=usr/share/examples/ses/srcs OLD_DIRS+=usr/share/examples/smbfs OLD_DIRS+=usr/share/examples/smbfs/print OLD_DIRS+=usr/share/examples/sunrpc OLD_DIRS+=usr/share/examples/sunrpc/dir OLD_DIRS+=usr/share/examples/sunrpc/msg OLD_DIRS+=usr/share/examples/sunrpc/sort OLD_DIRS+=usr/share/examples/tcsh OLD_DIRS+=usr/share/examples/uefisign OLD_DIRS+=usr/share/examples/ypldap .endif .if ${MK_FINGER} == no OLD_FILES+=usr/bin/finger OLD_FILES+=usr/share/man/man1/finger.1.gz OLD_FILES+=usr/share/man/man5/finger.conf.5.gz OLD_FILES+=usr/libexec/fingerd OLD_FILES+=usr/share/man/man8/fingerd.8.gz .endif .if ${MK_FLOPPY} == no OLD_FILES+=usr/sbin/fdcontrol OLD_FILES+=usr/sbin/fdformat OLD_FILES+=usr/sbin/fdread OLD_FILES+=usr/sbin/fdwrite OLD_FILES+=usr/share/man/man1/fdformat.1.gz OLD_FILES+=usr/share/man/man1/fdread.1.gz OLD_FILES+=usr/share/man/man1/fdwrite.1.gz OLD_FILES+=usr/share/man/man8/fdcontrol.8.gz .endif .if ${MK_FORTH} == no OLD_FILES+=usr/share/man/man8/beastie.4th.8.gz OLD_FILES+=usr/share/man/man8/brand.4th.8.gz OLD_FILES+=usr/share/man/man8/check-password.4th.8.gz OLD_FILES+=usr/share/man/man8/color.4th.8.gz OLD_FILES+=usr/share/man/man8/delay.4th.8.gz OLD_FILES+=usr/share/man/man8/loader.4th.8.gz OLD_FILES+=usr/share/man/man8/menu.4th.8.gz OLD_FILES+=usr/share/man/man8/menusets.4th.8.gz OLD_FILES+=usr/share/man/man8/version.4th.8.gz .endif .if ${MK_FREEBSD_UPDATE} == no OLD_FILES+=etc/freebsd-update.conf OLD_FILES+=usr/sbin/freebsd-update OLD_FILES+=usr/share/examples/etc/freebsd-update.conf OLD_FILES+=usr/share/man/man5/freebsd-update.conf.5.gz OLD_FILES+=usr/share/man/man8/freebsd-update.8.gz .endif .if ${MK_GAMES} == no OLD_FILES+=usr/bin/caesar OLD_FILES+=usr/bin/factor OLD_FILES+=usr/bin/fortune OLD_FILES+=usr/bin/grdc OLD_FILES+=usr/bin/morse OLD_FILES+=usr/bin/number OLD_FILES+=usr/bin/pom OLD_FILES+=usr/bin/primes OLD_FILES+=usr/bin/random OLD_FILES+=usr/bin/rot13 OLD_FILES+=usr/bin/strfile OLD_FILES+=usr/bin/unstr OLD_FILES+=usr/share/games/fortune/fortunes OLD_FILES+=usr/share/games/fortune/fortunes.dat OLD_FILES+=usr/share/games/fortune/freebsd-tips OLD_FILES+=usr/share/games/fortune/freebsd-tips.dat OLD_FILES+=usr/share/games/fortune/gerrold.limerick OLD_FILES+=usr/share/games/fortune/gerrold.limerick.dat OLD_FILES+=usr/share/games/fortune/limerick OLD_FILES+=usr/share/games/fortune/limerick.dat OLD_FILES+=usr/share/games/fortune/murphy OLD_FILES+=usr/share/games/fortune/murphy-o OLD_FILES+=usr/share/games/fortune/murphy-o.dat OLD_FILES+=usr/share/games/fortune/murphy.dat OLD_FILES+=usr/share/games/fortune/startrek OLD_FILES+=usr/share/games/fortune/startrek.dat OLD_FILES+=usr/share/games/fortune/zippy OLD_FILES+=usr/share/games/fortune/zippy.dat OLD_DIRS+=usr/share/games/fortune OLD_DIRS+=usr/share/games OLD_FILES+=usr/share/man/man6/caesar.6.gz OLD_FILES+=usr/share/man/man6/factor.6.gz OLD_FILES+=usr/share/man/man6/fortune.6.gz OLD_FILES+=usr/share/man/man6/grdc.6.gz OLD_FILES+=usr/share/man/man6/morse.6.gz OLD_FILES+=usr/share/man/man6/number.6.gz OLD_FILES+=usr/share/man/man6/pom.6.gz OLD_FILES+=usr/share/man/man6/primes.6.gz OLD_FILES+=usr/share/man/man6/random.6.gz OLD_FILES+=usr/share/man/man6/rot13.6.gz OLD_FILES+=usr/share/man/man8/strfile.8.gz OLD_FILES+=usr/share/man/man8/unstr.8.gz .endif .if ${MK_LLVM_COV} == no && !defined(WITH_PORT_BASE_GCC) OLD_FILES+=usr/bin/gcov OLD_FILES+=usr/share/man/man1/gcov.1.gz .endif .if ${MK_LLVM_COV} == no OLD_FILES+=usr/bin/llvm-cov OLD_FILES+=usr/bin/llvm-profdata OLD_FILES+=usr/share/man/man1/llvm-cov.1.gz +OLD_FILES+=usr/share/man/man1/llvm-profdata.1.gz .endif .if ${MK_GDB} == no OLD_FILES+=usr/libexec/gdb OLD_FILES+=usr/libexec/kgdb .endif .if ${MK_GOOGLETEST} == no OLD_FILES+=usr/include/gmock/gmock-actions.h OLD_FILES+=usr/include/gmock/gmock-cardinalities.h OLD_FILES+=usr/include/gmock/gmock-generated-actions.h OLD_FILES+=usr/include/gmock/gmock-generated-function-mockers.h OLD_FILES+=usr/include/gmock/gmock-generated-matchers.h OLD_FILES+=usr/include/gmock/gmock-generated-nice-strict.h OLD_FILES+=usr/include/gmock/gmock-matchers.h OLD_FILES+=usr/include/gmock/gmock-more-actions.h OLD_FILES+=usr/include/gmock/gmock-more-matchers.h OLD_FILES+=usr/include/gmock/gmock-spec-builders.h OLD_FILES+=usr/include/gmock/gmock.h OLD_FILES+=usr/include/gmock/internal/custom/gmock-generated-actions.h OLD_FILES+=usr/include/gmock/internal/custom/gmock-matchers.h OLD_FILES+=usr/include/gmock/internal/custom/gmock-port.h OLD_FILES+=usr/include/gmock/internal/gmock-generated-internal-utils.h OLD_FILES+=usr/include/gmock/internal/gmock-internal-utils.h OLD_FILES+=usr/include/gmock/internal/gmock-port.h OLD_DIRS+=usr/include/gmock OLD_FILES+=usr/include/gtest/gtest_pred_impl.h OLD_FILES+=usr/include/gtest/gtest_prod.h OLD_FILES+=usr/include/gtest/gtest-death-test.h OLD_FILES+=usr/include/gtest/gtest-message.h OLD_FILES+=usr/include/gtest/gtest-param-test.h OLD_FILES+=usr/include/gtest/gtest-printers.h OLD_FILES+=usr/include/gtest/gtest-spi.h OLD_FILES+=usr/include/gtest/gtest-test-part.h OLD_FILES+=usr/include/gtest/gtest-typed-test.h OLD_FILES+=usr/include/gtest/gtest.h OLD_FILES+=usr/include/gtest/internal/custom/gtest-port.h OLD_FILES+=usr/include/gtest/internal/custom/gtest-printers.h OLD_FILES+=usr/include/gtest/internal/custom/gtest.h OLD_FILES+=usr/include/gtest/internal/gtest-death-test-internal.h OLD_FILES+=usr/include/gtest/internal/gtest-filepath.h OLD_FILES+=usr/include/gtest/internal/gtest-internal.h OLD_FILES+=usr/include/gtest/internal/gtest-linked_ptr.h OLD_FILES+=usr/include/gtest/internal/gtest-param-util-generated.h OLD_FILES+=usr/include/gtest/internal/gtest-param-util.h OLD_FILES+=usr/include/gtest/internal/gtest-port-arch.h OLD_FILES+=usr/include/gtest/internal/gtest-port.h OLD_FILES+=usr/include/gtest/internal/gtest-string.h OLD_FILES+=usr/include/gtest/internal/gtest-tuple.h OLD_FILES+=usr/include/gtest/internal/gtest-type-util.h OLD_DIRS+=usr/include/gtest OLD_FILES+=usr/lib/libprivategmock_main.a OLD_FILES+=usr/lib/libprivategmock_main.so OLD_LIBS+=usr/lib/libprivategmock_main.so.0 OLD_FILES+=usr/lib/libprivategmock_main_p.a OLD_FILES+=usr/lib/libprivategmock.a OLD_FILES+=usr/lib/libprivategmock.so OLD_LIBS+=usr/lib/libprivategmock.so.0 OLD_FILES+=usr/lib/libprivategmock_p.a OLD_FILES+=usr/lib/libprivategtest_main.a OLD_FILES+=usr/lib/libprivategtest_main.so OLD_LIBS+=usr/lib/libprivategtest_main.so.0 OLD_FILES+=usr/lib/libprivategtest_main_p.a OLD_FILES+=usr/lib/libprivategtest.a OLD_FILES+=usr/lib/libprivategtest.so OLD_LIBS+=usr/lib/libprivategtest.so.0 OLD_FILES+=usr/lib/libprivategtest_p.a OLD_FILES+=usr/tests/lib/googletest/gmock/gmock_stress_test OLD_FILES+=usr/tests/lib/googletest/gmock/Kyuafile OLD_DIRS+=usr/tests/lib/googletest/gmock OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock_ex_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock_link_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-actions_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-cardinalities_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-ex_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-actions_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-function-mockers_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-internal-utils_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-generated-matchers_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-internal-utils_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-matchers_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-more-actions_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-nice-strict_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-port_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/gmock-spec-builders_test OLD_FILES+=usr/tests/lib/googletest/gmock_main/Kyuafile OLD_DIRS+=usr/tests/lib/googletest/gmock_main OLD_FILES+=usr/tests/lib/googletest/gtest/googletest-param-test-test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_all_test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_environment_test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_no_test_unittest OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_premature_exit_test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_repeat_test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_stress_test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest_throw_on_failure_ex_test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest-death-test_ex_catch_test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest-death-test_ex_nocatch_test OLD_FILES+=usr/tests/lib/googletest/gtest/gtest-unittest-api_test OLD_FILES+=usr/tests/lib/googletest/gtest/Kyuafile OLD_DIRS+=usr/tests/lib/googletest/gtest OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-death-test-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-filepath-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-linked-ptr-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-listener-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-message-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-options-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-port-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-printers-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/googletest-test-part-test OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_help_test_ OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_main_unittest OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_pred_impl_unittest OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_prod_test OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_sole_header_test OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_unittest OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_xml_outfile1_test_ OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest_xml_outfile2_test_ OLD_FILES+=usr/tests/lib/googletest/gtest_main/gtest-typed-test_test OLD_FILES+=usr/tests/lib/googletest/gtest_main/Kyuafile OLD_DIRS+=usr/tests/lib/googletest/gtest_main OLD_FILES+=usr/tests/lib/googletest/Kyuafile OLD_DIRS+=usr/tests/lib/googletest/ OLD_FILES+=usr/tests/share/examples/tests/googletest/Kyuafile OLD_FILES+=usr/tests/share/examples/tests/googletest/sample1_unittest OLD_FILES+=usr/tests/share/examples/tests/googletest/sample10_unittest OLD_FILES+=usr/tests/share/examples/tests/googletest/sample2_unittest OLD_FILES+=usr/tests/share/examples/tests/googletest/sample3_unittest OLD_FILES+=usr/tests/share/examples/tests/googletest/sample4_unittest OLD_FILES+=usr/tests/share/examples/tests/googletest/sample5_unittest OLD_FILES+=usr/tests/share/examples/tests/googletest/sample6_unittest OLD_FILES+=usr/tests/share/examples/tests/googletest/sample7_unittest OLD_FILES+=usr/tests/share/examples/tests/googletest/sample8_unittest OLD_DIRS+=usr/tests/share/examples/tests/googletest .endif .if ${MK_GPIO} == no OLD_FILES+=usr/include/libgpio.h OLD_FILES+=usr/lib/libgpio.a OLD_FILES+=usr/lib/libgpio.so OLD_LIBS+=usr/lib/libgpio.so.0 OLD_FILES+=usr/lib/libgpio_p.a OLD_FILES+=usr/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/diff3 OLD_FILES+=usr/share/man/man1/diff3.1.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 .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+=etc/rc.d/hastd OLD_FILES+=sbin/hastctl OLD_FILES+=sbin/hastd OLD_FILES+=usr/share/examples/hast/ucarp.sh OLD_FILES+=usr/share/examples/hast/ucarp_down.sh OLD_FILES+=usr/share/examples/hast/ucarp_up.sh OLD_FILES+=usr/share/examples/hast/vip-down.sh OLD_FILES+=usr/share/examples/hast/vip-up.sh OLD_FILES+=usr/share/man/man5/hast.conf.5.gz OLD_FILES+=usr/share/man/man8/hastctl.8.gz OLD_FILES+=usr/share/man/man8/hastd.8.gz OLD_DIRS+=usr/share/examples/hast # bsnmp OLD_FILES+=usr/lib/snmp_hast.so OLD_LIBS+=usr/lib/snmp_hast.so.6 OLD_FILES+=usr/share/man/man3/snmp_hast.3.gz OLD_FILES+=usr/share/snmp/defs/hast_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-HAST-MIB.txt .endif .if ${MK_HESIOD} == no OLD_FILES+=usr/bin/hesinfo OLD_FILES+=usr/include/hesiod.h OLD_FILES+=usr/share/man/man1/hesinfo.1.gz OLD_FILES+=usr/share/man/man3/hesiod.3.gz OLD_FILES+=usr/share/man/man5/hesiod.conf.5.gz .endif .if ${MK_HTML} == no OLD_FILES+=usr/share/doc/ncurses/hackguide.html OLD_FILES+=usr/share/doc/ncurses/ncurses-intro.html OLD_DIRS+=usr/share/doc/ncurses OLD_FILES+=usr/share/doc/ntp/accopt.html OLD_FILES+=usr/share/doc/ntp/assoc.html OLD_FILES+=usr/share/doc/ntp/audio.html OLD_FILES+=usr/share/doc/ntp/authopt.html OLD_FILES+=usr/share/doc/ntp/build.html OLD_FILES+=usr/share/doc/ntp/clockopt.html OLD_FILES+=usr/share/doc/ntp/config.html OLD_FILES+=usr/share/doc/ntp/confopt.html OLD_FILES+=usr/share/doc/ntp/copyright.html OLD_FILES+=usr/share/doc/ntp/debug.html OLD_FILES+=usr/share/doc/ntp/driver1.html OLD_FILES+=usr/share/doc/ntp/driver10.html OLD_FILES+=usr/share/doc/ntp/driver11.html OLD_FILES+=usr/share/doc/ntp/driver12.html OLD_FILES+=usr/share/doc/ntp/driver16.html OLD_FILES+=usr/share/doc/ntp/driver18.html OLD_FILES+=usr/share/doc/ntp/driver19.html OLD_FILES+=usr/share/doc/ntp/driver2.html OLD_FILES+=usr/share/doc/ntp/driver20.html OLD_FILES+=usr/share/doc/ntp/driver22.html OLD_FILES+=usr/share/doc/ntp/driver26.html OLD_FILES+=usr/share/doc/ntp/driver27.html OLD_FILES+=usr/share/doc/ntp/driver28.html OLD_FILES+=usr/share/doc/ntp/driver29.html OLD_FILES+=usr/share/doc/ntp/driver3.html OLD_FILES+=usr/share/doc/ntp/driver30.html OLD_FILES+=usr/share/doc/ntp/driver32.html OLD_FILES+=usr/share/doc/ntp/driver33.html OLD_FILES+=usr/share/doc/ntp/driver34.html OLD_FILES+=usr/share/doc/ntp/driver35.html OLD_FILES+=usr/share/doc/ntp/driver36.html OLD_FILES+=usr/share/doc/ntp/driver37.html OLD_FILES+=usr/share/doc/ntp/driver4.html OLD_FILES+=usr/share/doc/ntp/driver5.html OLD_FILES+=usr/share/doc/ntp/driver6.html OLD_FILES+=usr/share/doc/ntp/driver7.html OLD_FILES+=usr/share/doc/ntp/driver8.html OLD_FILES+=usr/share/doc/ntp/driver9.html OLD_FILES+=usr/share/doc/ntp/extern.html OLD_FILES+=usr/share/doc/ntp/hints.html OLD_FILES+=usr/share/doc/ntp/howto.html OLD_FILES+=usr/share/doc/ntp/index.html OLD_FILES+=usr/share/doc/ntp/kern.html OLD_FILES+=usr/share/doc/ntp/ldisc.html OLD_FILES+=usr/share/doc/ntp/measure.html OLD_FILES+=usr/share/doc/ntp/miscopt.html OLD_FILES+=usr/share/doc/ntp/monopt.html OLD_FILES+=usr/share/doc/ntp/mx4200data.html OLD_FILES+=usr/share/doc/ntp/notes.html OLD_FILES+=usr/share/doc/ntp/ntpd.html OLD_FILES+=usr/share/doc/ntp/ntpdate.html OLD_FILES+=usr/share/doc/ntp/ntpdc.html OLD_FILES+=usr/share/doc/ntp/ntpq.html OLD_FILES+=usr/share/doc/ntp/ntptime.html OLD_FILES+=usr/share/doc/ntp/ntptrace.html OLD_FILES+=usr/share/doc/ntp/parsedata.html OLD_FILES+=usr/share/doc/ntp/parsenew.html OLD_FILES+=usr/share/doc/ntp/patches.html OLD_FILES+=usr/share/doc/ntp/porting.html OLD_FILES+=usr/share/doc/ntp/pps.html OLD_FILES+=usr/share/doc/ntp/prefer.html OLD_FILES+=usr/share/doc/ntp/quick.html OLD_FILES+=usr/share/doc/ntp/rdebug.html OLD_FILES+=usr/share/doc/ntp/refclock.html OLD_FILES+=usr/share/doc/ntp/release.html OLD_FILES+=usr/share/doc/ntp/tickadj.html .endif .if ${MK_ICONV} == no OLD_FILES+=usr/bin/iconv OLD_FILES+=usr/bin/mkcsmapper OLD_FILES+=usr/bin/mkesdb OLD_FILES+=usr/include/_libiconv_compat.h OLD_FILES+=usr/include/iconv.h OLD_FILES+=usr/share/man/man1/iconv.1.gz OLD_FILES+=usr/share/man/man1/mkcsmapper.1.gz OLD_FILES+=usr/share/man/man1/mkesdb.1.gz OLD_FILES+=usr/share/man/man3/__iconv.3.gz OLD_FILES+=usr/share/man/man3/__iconv_free_list.3.gz OLD_FILES+=usr/share/man/man3/__iconv_get_list.3.gz OLD_FILES+=usr/share/man/man3/iconv.3.gz OLD_FILES+=usr/share/man/man3/iconv_canonicalize.3.gz OLD_FILES+=usr/share/man/man3/iconv_close.3.gz OLD_FILES+=usr/share/man/man3/iconv_open.3.gz OLD_FILES+=usr/share/man/man3/iconv_open_into.3.gz OLD_FILES+=usr/share/man/man3/iconvctl.3.gz OLD_FILES+=usr/share/man/man3/iconvlist.3.gz OLD_DIRS+=usr/share/i18n OLD_DIRS+=usr/share/i18n/esdb OLD_DIRS+=usr/share/i18n/esdb/ISO-2022 OLD_DIRS+=usr/share/i18n/esdb/BIG5 OLD_DIRS+=usr/share/i18n/esdb/MISC OLD_DIRS+=usr/share/i18n/esdb/TCVN OLD_DIRS+=usr/share/i18n/esdb/EBCDIC OLD_DIRS+=usr/share/i18n/esdb/ISO-8859 OLD_DIRS+=usr/share/i18n/esdb/GEORGIAN OLD_DIRS+=usr/share/i18n/esdb/AST OLD_DIRS+=usr/share/i18n/esdb/KAZAKH OLD_DIRS+=usr/share/i18n/esdb/APPLE OLD_DIRS+=usr/share/i18n/esdb/EUC OLD_DIRS+=usr/share/i18n/esdb/CP OLD_DIRS+=usr/share/i18n/esdb/DEC OLD_DIRS+=usr/share/i18n/esdb/UTF OLD_DIRS+=usr/share/i18n/esdb/GB OLD_DIRS+=usr/share/i18n/esdb/ISO646 OLD_DIRS+=usr/share/i18n/esdb/KOI OLD_DIRS+=usr/share/i18n/csmapper OLD_DIRS+=usr/share/i18n/csmapper/KAZAKH OLD_DIRS+=usr/share/i18n/csmapper/CNS OLD_DIRS+=usr/share/i18n/csmapper/BIG5 OLD_DIRS+=usr/share/i18n/csmapper/JIS OLD_DIRS+=usr/share/i18n/csmapper/KOI OLD_DIRS+=usr/share/i18n/csmapper/TCVN OLD_DIRS+=usr/share/i18n/csmapper/MISC OLD_DIRS+=usr/share/i18n/csmapper/EBCDIC OLD_DIRS+=usr/share/i18n/csmapper/ISO646 OLD_DIRS+=usr/share/i18n/csmapper/CP OLD_DIRS+=usr/share/i18n/csmapper/GEORGIAN OLD_DIRS+=usr/share/i18n/csmapper/ISO-8859 OLD_DIRS+=usr/share/i18n/csmapper/AST OLD_DIRS+=usr/share/i18n/csmapper/APPLE OLD_DIRS+=usr/share/i18n/csmapper/KS OLD_DIRS+=usr/share/i18n/csmapper/GB .endif .if ${MK_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/inetd.conf OLD_FILES+=etc/rc.d/inetd OLD_FILES+=usr/sbin/inetd OLD_FILES+=usr/share/man/man5/inetd.conf.5.gz OLD_FILES+=usr/share/man/man8/inetd.8.gz .endif .if ${MK_IPFILTER} == no OLD_FILES+=etc/periodic/security/510.ipfdenied OLD_FILES+=etc/periodic/security/610.ipf6denied OLD_FILES+=etc/rc.d/ipfilter OLD_FILES+=etc/rc.d/ipfs OLD_FILES+=etc/rc.d/ipmon OLD_FILES+=etc/rc.d/ipnat OLD_FILES+=etc/rc.d/ippool OLD_FILES+=rescue/ipf OLD_FILES+=sbin/ipf OLD_FILES+=sbin/ipfs OLD_FILES+=sbin/ipfstat OLD_FILES+=sbin/ipftest OLD_FILES+=sbin/ipmon OLD_FILES+=sbin/ipnat OLD_FILES+=sbin/ippool OLD_FILES+=sbin/ipresend OLD_FILES+=usr/include/netinet/ip_auth.h OLD_FILES+=usr/include/netinet/ip_compat.h OLD_FILES+=usr/include/netinet/ip_fil.h OLD_FILES+=usr/include/netinet/ip_frag.h OLD_FILES+=usr/include/netinet/ip_htable.h OLD_FILES+=usr/include/netinet/ip_lookup.h OLD_FILES+=usr/include/netinet/ip_nat.h OLD_FILES+=usr/include/netinet/ip_pool.h OLD_FILES+=usr/include/netinet/ip_proxy.h OLD_FILES+=usr/include/netinet/ip_rules.h OLD_FILES+=usr/include/netinet/ip_scan.h OLD_FILES+=usr/include/netinet/ip_state.h OLD_FILES+=usr/include/netinet/ip_sync.h OLD_FILES+=usr/include/netinet/ipl.h OLD_FILES+=usr/share/examples/ipfilter/README OLD_FILES+=usr/share/examples/ipfilter/BASIC.NAT OLD_FILES+=usr/share/examples/ipfilter/BASIC_1.FW OLD_FILES+=usr/share/examples/ipfilter/BASIC_2.FW OLD_FILES+=usr/share/examples/ipfilter/example.1 OLD_FILES+=usr/share/examples/ipfilter/example.2 OLD_FILES+=usr/share/examples/ipfilter/example.3 OLD_FILES+=usr/share/examples/ipfilter/example.4 OLD_FILES+=usr/share/examples/ipfilter/example.5 OLD_FILES+=usr/share/examples/ipfilter/example.6 OLD_FILES+=usr/share/examples/ipfilter/example.7 OLD_FILES+=usr/share/examples/ipfilter/example.8 OLD_FILES+=usr/share/examples/ipfilter/example.9 OLD_FILES+=usr/share/examples/ipfilter/example.10 OLD_FILES+=usr/share/examples/ipfilter/example.11 OLD_FILES+=usr/share/examples/ipfilter/example.12 OLD_FILES+=usr/share/examples/ipfilter/example.13 OLD_FILES+=usr/share/examples/ipfilter/example.sr OLD_FILES+=usr/share/examples/ipfilter/firewall OLD_FILES+=usr/share/examples/ipfilter/ftp-proxy OLD_FILES+=usr/share/examples/ipfilter/ftppxy OLD_FILES+=usr/share/examples/ipfilter/nat-setup OLD_FILES+=usr/share/examples/ipfilter/nat.eg OLD_FILES+=usr/share/examples/ipfilter/server OLD_FILES+=usr/share/examples/ipfilter/tcpstate OLD_FILES+=usr/share/examples/ipfilter/example.14 OLD_FILES+=usr/share/examples/ipfilter/firewall.1 OLD_FILES+=usr/share/examples/ipfilter/firewall.2 OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.permissive OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.restrictive OLD_FILES+=usr/share/examples/ipfilter/ipf.conf.sample OLD_FILES+=usr/share/examples/ipfilter/ipnat.conf.sample OLD_FILES+=usr/share/examples/ipfilter/ipf-howto.txt OLD_FILES+=usr/share/examples/ipfilter/examples.txt OLD_FILES+=usr/share/examples/ipfilter/rules.txt OLD_FILES+=usr/share/examples/ipfilter/mkfilters OLD_DIRS+=usr/share/examples/ipfilter OLD_FILES+=usr/share/man/man1/ipftest.1.gz OLD_FILES+=usr/share/man/man1/ipresend.1.gz OLD_FILES+=usr/share/man/man4/ipf.4.gz OLD_FILES+=usr/share/man/man4/ipl.4.gz OLD_FILES+=usr/share/man/man4/ipfilter.4.gz OLD_FILES+=usr/share/man/man4/ipnat.4.gz OLD_FILES+=usr/share/man/man5/ipf.5.gz OLD_FILES+=usr/share/man/man5/ipf.conf.5.gz OLD_FILES+=usr/share/man/man5/ipf6.conf.5.gz OLD_FILES+=usr/share/man/man5/ipfilter.5.gz OLD_FILES+=usr/share/man/man8/ipmon.5.gz OLD_FILES+=usr/share/man/man5/ipmon.conf.5.gz OLD_FILES+=usr/share/man/man5/ipnat.5.gz OLD_FILES+=usr/share/man/man5/ipnat.conf.5.gz OLD_FILES+=usr/share/man/man5/ippool.5.gz OLD_FILES+=usr/share/man/man8/ipf.8.gz OLD_FILES+=usr/share/man/man8/ipfs.8.gz OLD_FILES+=usr/share/man/man8/ipfstat.8.gz OLD_FILES+=usr/share/man/man8/ipmon.8.gz OLD_FILES+=usr/share/man/man8/ipnat.8.gz OLD_FILES+=usr/share/man/man8/ippool.8.gz .endif .if ${MK_IPFW} == no OLD_FILES+=etc/rc.d/ipfw OLD_FILES+=etc/periodic/security/500.ipfwdenied OLD_FILES+=etc/periodic/security/550.ipfwlimit OLD_FILES+=sbin/ipfw OLD_FILES+=sbin/natd OLD_FILES+=usr/sbin/ipfwpcap OLD_FILES+=usr/share/man/man8/ipfw.8.gz OLD_FILES+=usr/share/man/man8/ipfwpcap.8.gz OLD_FILES+=usr/share/man/man8/natd.8.gz .endif .if ${MK_ISCSI} == no OLD_FILES+=etc/rc.d/iscsictl OLD_FILES+=etc/rc.d/iscsid OLD_FILES+=rescue/iscsictl OLD_FILES+=rescue/iscsid OLD_FILES+=sbin/iscontrol OLD_FILES+=usr/bin/iscsictl OLD_FILES+=usr/sbin/iscsid OLD_FILES+=usr/share/man/man4/iscsi.4.gz OLD_FILES+=usr/share/man/man4/iscsi_initiator.4.gz OLD_FILES+=usr/share/man/man5/iscsi.conf.5.gz OLD_FILES+=usr/share/man/man8/iscontrol.8.gz OLD_FILES+=usr/share/man/man8/iscsictl.8.gz OLD_FILES+=usr/share/man/man8/iscsid.8.gz .endif .if ${MK_JAIL} == no OLD_FILES+=etc/rc.d/jail OLD_FILES+=usr/sbin/jail OLD_FILES+=usr/sbin/jexec OLD_FILES+=usr/sbin/jls OLD_FILES+=usr/share/man/man5/jail.conf.5.gz OLD_FILES+=usr/share/man/man8/jail.8.gz OLD_FILES+=usr/share/man/man8/jexec.8.gz OLD_FILES+=usr/share/man/man8/jls.8.gz .endif .if ${MK_KDUMP} == no OLD_FILES+=usr/bin/kdump OLD_FILES+=usr/bin/truss OLD_FILES+=usr/share/man/man1/kdump.1.gz OLD_FILES+=usr/share/man/man1/truss.1.gz .endif .if ${MK_KERBEROS} == no OLD_FILES+=etc/rc.d/ipropd_master OLD_FILES+=etc/rc.d/ipropd_slave OLD_FILES+=usr/bin/asn1_compile OLD_FILES+=usr/bin/compile_et OLD_FILES+=usr/bin/hxtool OLD_FILES+=usr/bin/kadmin OLD_FILES+=usr/bin/kcc OLD_FILES+=usr/bin/kdestroy OLD_FILES+=usr/bin/kf OLD_FILES+=usr/bin/kgetcred OLD_FILES+=usr/bin/kinit OLD_FILES+=usr/bin/klist OLD_FILES+=usr/bin/kpasswd OLD_FILES+=usr/bin/krb5-config OLD_FILES+=usr/bin/ksu OLD_FILES+=usr/bin/kswitch OLD_FILES+=usr/bin/make-roken OLD_FILES+=usr/bin/slc OLD_FILES+=usr/bin/string2key OLD_FILES+=usr/bin/verify_krb5_conf OLD_FILES+=usr/include/asn1-common.h OLD_FILES+=usr/include/asn1_err.h OLD_FILES+=usr/include/base64.h OLD_FILES+=usr/include/cms_asn1.h OLD_FILES+=usr/include/crmf_asn1.h OLD_FILES+=usr/include/der-private.h OLD_FILES+=usr/include/der-protos.h OLD_FILES+=usr/include/der.h OLD_FILES+=usr/include/digest_asn1.h OLD_FILES+=usr/include/getarg.h OLD_FILES+=usr/include/gssapi/gssapi_krb5.h OLD_FILES+=usr/include/hdb-protos.h OLD_FILES+=usr/include/hdb.h OLD_FILES+=usr/include/hdb_asn1.h OLD_FILES+=usr/include/hdb_err.h OLD_FILES+=usr/include/heim_asn1.h OLD_FILES+=usr/include/heim_err.h OLD_FILES+=usr/include/heim_threads.h OLD_FILES+=usr/include/heimbase.h OLD_FILES+=usr/include/heimntlm-protos.h OLD_FILES+=usr/include/heimntlm.h OLD_FILES+=usr/include/hex.h OLD_FILES+=usr/include/hx509-private.h OLD_FILES+=usr/include/hx509-protos.h OLD_FILES+=usr/include/hx509.h OLD_FILES+=usr/include/hx509_err.h OLD_FILES+=usr/include/k524_err.h OLD_FILES+=usr/include/kadm5/admin.h OLD_FILES+=usr/include/kadm5/kadm5-private.h OLD_FILES+=usr/include/kadm5/kadm5-protos.h OLD_FILES+=usr/include/kadm5/kadm5-pwcheck.h OLD_FILES+=usr/include/kadm5/kadm5_err.h OLD_FILES+=usr/include/kadm5/private.h OLD_DIRS+=usr/include/kadm5 OLD_FILES+=usr/include/kafs.h OLD_FILES+=usr/include/kdc-protos.h OLD_FILES+=usr/include/kdc.h OLD_FILES+=usr/include/krb5-private.h OLD_FILES+=usr/include/krb5-protos.h OLD_FILES+=usr/include/krb5-types.h OLD_FILES+=usr/include/krb5.h OLD_FILES+=usr/include/krb5/ccache_plugin.h OLD_FILES+=usr/include/krb5/locate_plugin.h OLD_FILES+=usr/include/krb5/send_to_kdc_plugin.h OLD_FILES+=usr/include/krb5/windc_plugin.h OLD_DIRS+=usr/include/krb5 OLD_FILES+=usr/include/krb5_asn1.h OLD_FILES+=usr/include/krb5_ccapi.h OLD_FILES+=usr/include/krb5_err.h OLD_FILES+=usr/include/kx509_asn1.h OLD_FILES+=usr/include/ntlm_err.h OLD_FILES+=usr/include/ocsp_asn1.h OLD_FILES+=usr/include/parse_bytes.h OLD_FILES+=usr/include/parse_time.h OLD_FILES+=usr/include/parse_units.h OLD_FILES+=usr/include/pkcs10_asn1.h OLD_FILES+=usr/include/pkcs12_asn1.h OLD_FILES+=usr/include/pkcs8_asn1.h OLD_FILES+=usr/include/pkcs9_asn1.h OLD_FILES+=usr/include/pkinit_asn1.h OLD_FILES+=usr/include/resolve.h OLD_FILES+=usr/include/rfc2459_asn1.h OLD_FILES+=usr/include/roken-common.h OLD_FILES+=usr/include/rtbl.h OLD_FILES+=usr/include/wind.h OLD_FILES+=usr/include/wind_err.h OLD_FILES+=usr/include/xdbm.h OLD_FILES+=usr/lib/libasn1.a OLD_FILES+=usr/lib/libasn1.so OLD_LIBS+=usr/lib/libasn1.so.11 OLD_FILES+=usr/lib/libasn1_p.a OLD_FILES+=usr/lib/libcom_err.a OLD_FILES+=usr/lib/libcom_err.so OLD_LIBS+=usr/lib/libcom_err.so.5 OLD_FILES+=usr/lib/libcom_err_p.a OLD_FILES+=usr/lib/libgssapi_krb5.a OLD_FILES+=usr/lib/libgssapi_krb5.so OLD_LIBS+=usr/lib/libgssapi_krb5.so.10 OLD_FILES+=usr/lib/libgssapi_krb5_p.a OLD_FILES+=usr/lib/libgssapi_ntlm.a OLD_FILES+=usr/lib/libgssapi_ntlm.so OLD_LIBS+=usr/lib/libgssapi_ntlm.so.10 OLD_FILES+=usr/lib/libgssapi_ntlm_p.a OLD_FILES+=usr/lib/libgssapi_spnego.a OLD_FILES+=usr/lib/libgssapi_spnego.so OLD_LIBS+=usr/lib/libgssapi_spnego.so.10 OLD_FILES+=usr/lib/libgssapi_spnego_p.a OLD_FILES+=usr/lib/libhdb.a OLD_FILES+=usr/lib/libhdb.so OLD_LIBS+=usr/lib/libhdb.so.11 OLD_FILES+=usr/lib/libhdb_p.a OLD_FILES+=usr/lib/libheimbase.a OLD_FILES+=usr/lib/libheimbase.so OLD_LIBS+=usr/lib/libheimbase.so.11 OLD_FILES+=usr/lib/libheimbase_p.a OLD_FILES+=usr/lib/libheimntlm.a OLD_FILES+=usr/lib/libheimntlm.so OLD_LIBS+=usr/lib/libheimntlm.so.11 OLD_FILES+=usr/lib/libheimntlm_p.a OLD_FILES+=usr/lib/libheimsqlite.a OLD_FILES+=usr/lib/libheimsqlite.so OLD_LIBS+=usr/lib/libheimsqlite.so.11 OLD_FILES+=usr/lib/libheimsqlite_p.a OLD_FILES+=usr/lib/libhx509.a OLD_FILES+=usr/lib/libhx509.so OLD_LIBS+=usr/lib/libhx509.so.11 OLD_FILES+=usr/lib/libhx509_p.a OLD_FILES+=usr/lib/libkadm5clnt.a OLD_FILES+=usr/lib/libkadm5clnt.so OLD_LIBS+=usr/lib/libkadm5clnt.so.11 OLD_FILES+=usr/lib/libkadm5clnt_p.a OLD_FILES+=usr/lib/libkadm5srv.a OLD_FILES+=usr/lib/libkadm5srv.so OLD_LIBS+=usr/lib/libkadm5srv.so.11 OLD_FILES+=usr/lib/libkadm5srv_p.a OLD_FILES+=usr/lib/libkafs5.a OLD_FILES+=usr/lib/libkafs5.so OLD_LIBS+=usr/lib/libkafs5.so.11 OLD_FILES+=usr/lib/libkafs5_p.a OLD_FILES+=usr/lib/libkdc.a OLD_FILES+=usr/lib/libkdc.so OLD_LIBS+=usr/lib/libkdc.so.11 OLD_FILES+=usr/lib/libkdc_p.a OLD_FILES+=usr/lib/libkrb5.a OLD_FILES+=usr/lib/libkrb5.so OLD_LIBS+=usr/lib/libkrb5.so.11 OLD_FILES+=usr/lib/libkrb5_p.a OLD_FILES+=usr/lib/libroken.a OLD_FILES+=usr/lib/libroken.so OLD_LIBS+=usr/lib/libroken.so.11 OLD_FILES+=usr/lib/libroken_p.a OLD_FILES+=usr/lib/libwind.a OLD_FILES+=usr/lib/libwind.so OLD_LIBS+=usr/lib/libwind.so.11 OLD_FILES+=usr/lib/libwind_p.a OLD_FILES+=usr/lib/pam_krb5.so OLD_LIBS+=usr/lib/pam_krb5.so.6 OLD_FILES+=usr/lib/pam_ksu.so OLD_LIBS+=usr/lib/pam_ksu.so.6 OLD_FILES+=usr/lib/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+=etc/rc.d/moused OLD_FILES+=etc/rc.d/syscons OLD_FILES+=usr/sbin/kbdcontrol OLD_FILES+=usr/sbin/kbdmap OLD_FILES+=usr/sbin/moused OLD_FILES+=usr/sbin/vidcontrol OLD_FILES+=usr/sbin/vidfont OLD_FILES+=usr/share/man/man1/kbdcontrol.1.gz OLD_FILES+=usr/share/man/man1/kbdmap.1.gz OLD_FILES+=usr/share/man/man1/vidcontrol.1.gz OLD_FILES+=usr/share/man/man1/vidfont.1.gz OLD_FILES+=usr/share/man/man5/kbdmap.5.gz OLD_FILES+=usr/share/man/man5/keymap.5.gz OLD_FILES+=usr/share/man/man8/moused.8.gz .endif .if ${MK_LIB32} == no OLD_FILES+=etc/mtree/BSD.lib32.dist OLD_FILES+=libexec/ld-elf32.so.1 . if exists(${DESTDIR}/usr/lib32) LIB32_DIRS!=find ${DESTDIR}/usr/lib32 -type d \ | sed -e 's,^${DESTDIR}/,,'; echo LIB32_FILES!=find ${DESTDIR}/usr/lib32 \! -type d \ \! -name "lib*.so*" | sed -e 's,^${DESTDIR}/,,'; echo LIB32_LIBS!=find ${DESTDIR}/usr/lib32 \! -type d \ -name "lib*.so*" | sed -e 's,^${DESTDIR}/,,'; echo OLD_DIRS+=${LIB32_DIRS} OLD_FILES+=${LIB32_FILES} OLD_LIBS+=${LIB32_LIBS} . endif . if ${MK_DEBUG_FILES} == no . if exists(${DESTDIR}/usr/lib/debug/usr/lib32) DEBUG_LIB32_DIRS!=find ${DESTDIR}/usr/lib/debug/usr/lib32 -type d \ | sed -e 's,^${DESTDIR}/,,'; echo DEBUG_LIB32_FILES!=find ${DESTDIR}/usr/lib/debug/usr/lib32 \! -type d \ \! -name "lib*.so*" | sed -e 's,^${DESTDIR}/,,'; echo DEBUG_LIB32_LIBS!=find ${DESTDIR}/usr/lib/debug/usr/lib32 \! -type d \ -name "lib*.so*" | sed -e 's,^${DESTDIR}/,,'; echo OLD_DIRS+=${DEBUG_LIB32_DIRS} OLD_FILES+=${DEBUG_LIB32_FILES} OLD_LIBS+=${DEBUG_LIB32_LIBS} . endif . endif .endif .if ${MK_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_DIRS+=usr/share/locale/af_ZA.ISO8859-15 OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/af_ZA.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/af_ZA.ISO8859-1 OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/af_ZA.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/af_ZA.UTF-8 OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/af_ZA.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/am_ET.UTF-8 OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/am_ET.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ar_AE.UTF-8 OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ar_AE.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ar_EG.UTF-8 OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ar_EG.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ar_JO.UTF-8 OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ar_JO.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ar_MA.UTF-8 OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ar_MA.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ar_QA.UTF-8 OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ar_QA.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ar_SA.UTF-8 OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ar_SA.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/be_BY.CP1131 OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_COLLATE OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_CTYPE OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_MESSAGES OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_MONETARY OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_NUMERIC OLD_FILES+=usr/share/locale/be_BY.CP1131/LC_TIME OLD_DIRS+=usr/share/locale/be_BY.CP1251 OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_COLLATE OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_CTYPE OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_MESSAGES OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_MONETARY OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_NUMERIC OLD_FILES+=usr/share/locale/be_BY.CP1251/LC_TIME OLD_DIRS+=usr/share/locale/be_BY.ISO8859-5 OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_COLLATE OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_CTYPE OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_MESSAGES OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_MONETARY OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_NUMERIC OLD_FILES+=usr/share/locale/be_BY.ISO8859-5/LC_TIME OLD_DIRS+=usr/share/locale/be_BY.UTF-8 OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/be_BY.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/bg_BG.CP1251 OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_COLLATE OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_CTYPE OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_MESSAGES OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_MONETARY OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_NUMERIC OLD_FILES+=usr/share/locale/bg_BG.CP1251/LC_TIME OLD_DIRS+=usr/share/locale/bg_BG.UTF-8 OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/bg_BG.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ca_AD.ISO8859-1 OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_AD.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/ca_AD.ISO8859-15 OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_AD.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/ca_AD.UTF-8 OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_AD.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ca_ES.ISO8859-1 OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_ES.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/ca_ES.ISO8859-15 OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_ES.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/ca_ES.UTF-8 OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_ES.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ca_FR.ISO8859-1 OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_FR.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/ca_FR.ISO8859-15 OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_FR.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/ca_FR.UTF-8 OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_FR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ca_IT.ISO8859-1 OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_IT.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/ca_IT.ISO8859-15 OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_IT.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/ca_IT.UTF-8 OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ca_IT.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/cs_CZ.ISO8859-2 OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/cs_CZ.ISO8859-2/LC_TIME OLD_DIRS+=usr/share/locale/cs_CZ.UTF-8 OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/cs_CZ.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/da_DK.ISO8859-1 OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/da_DK.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/da_DK.ISO8859-15 OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/da_DK.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/da_DK.UTF-8 OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/da_DK.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/de_AT.ISO8859-1 OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/de_AT.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/de_AT.ISO8859-15 OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/de_AT.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/de_AT.UTF-8 OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/de_AT.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/de_CH.ISO8859-1 OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/de_CH.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/de_CH.ISO8859-15 OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/de_CH.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/de_CH.UTF-8 OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/de_CH.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/de_DE.ISO8859-1 OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/de_DE.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/de_DE.ISO8859-15 OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/de_DE.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/de_DE.UTF-8 OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/de_DE.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/el_GR.ISO8859-7 OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_COLLATE OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_CTYPE OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_MESSAGES OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_MONETARY OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_NUMERIC OLD_FILES+=usr/share/locale/el_GR.ISO8859-7/LC_TIME OLD_DIRS+=usr/share/locale/el_GR.UTF-8 OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/el_GR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_AU.ISO8859-1 OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_AU.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_AU.ISO8859-15 OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_AU.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/en_AU.US-ASCII OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_AU.US-ASCII/LC_TIME OLD_DIRS+=usr/share/locale/en_AU.UTF-8 OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_AU.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_CA.ISO8859-1 OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_CA.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_CA.ISO8859-15 OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_CA.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/en_CA.US-ASCII OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_CA.US-ASCII/LC_TIME OLD_DIRS+=usr/share/locale/en_CA.UTF-8 OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_CA.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_GB.ISO8859-1 OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_GB.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_GB.ISO8859-15 OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_GB.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/en_GB.US-ASCII OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_GB.US-ASCII/LC_TIME OLD_DIRS+=usr/share/locale/en_GB.UTF-8 OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_GB.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_HK.ISO8859-1 OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_HK.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_HK.UTF-8 OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_HK.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_IE.ISO8859-1 OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_IE.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_IE.ISO8859-15 OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_IE.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/en_IE.UTF-8 OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_IE.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_NZ.ISO8859-1 OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_NZ.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_NZ.ISO8859-15 OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_NZ.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/en_NZ.US-ASCII OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_NZ.US-ASCII/LC_TIME OLD_DIRS+=usr/share/locale/en_NZ.UTF-8 OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_NZ.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_PH.UTF-8 OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_PH.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_SG.ISO8859-1 OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_SG.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_SG.UTF-8 OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_SG.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_US.ISO8859-1 OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_US.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_US.ISO8859-15 OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_US.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/en_US.US-ASCII OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_US.US-ASCII/LC_TIME OLD_DIRS+=usr/share/locale/en_US.UTF-8 OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_US.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/en_ZA.ISO8859-1 OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/en_ZA.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/en_ZA.ISO8859-15 OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/en_ZA.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/en_ZA.US-ASCII OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_COLLATE OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_CTYPE OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_MESSAGES OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_MONETARY OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_NUMERIC OLD_FILES+=usr/share/locale/en_ZA.US-ASCII/LC_TIME OLD_DIRS+=usr/share/locale/en_ZA.UTF-8 OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/en_ZA.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/es_AR.ISO8859-1 OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/es_AR.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/es_AR.UTF-8 OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/es_AR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/es_CR.UTF-8 OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/es_CR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/es_ES.ISO8859-1 OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/es_ES.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/es_ES.ISO8859-15 OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/es_ES.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/es_ES.UTF-8 OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/es_ES.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/es_MX.ISO8859-1 OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/es_MX.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/es_MX.UTF-8 OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/es_MX.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/et_EE.ISO8859-1 OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/et_EE.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/et_EE.ISO8859-15 OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/et_EE.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/et_EE.UTF-8 OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/et_EE.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/eu_ES.ISO8859-1 OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/eu_ES.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/eu_ES.ISO8859-15 OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/eu_ES.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/eu_ES.UTF-8 OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/eu_ES.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/fi_FI.ISO8859-1 OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fi_FI.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/fi_FI.ISO8859-15 OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fi_FI.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/fi_FI.UTF-8 OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fi_FI.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/fr_BE.ISO8859-1 OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_BE.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/fr_BE.ISO8859-15 OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_BE.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/fr_BE.UTF-8 OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_BE.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/fr_CA.ISO8859-1 OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CA.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/fr_CA.ISO8859-15 OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CA.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/fr_CA.UTF-8 OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CA.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/fr_CH.ISO8859-1 OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CH.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/fr_CH.ISO8859-15 OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CH.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/fr_CH.UTF-8 OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_CH.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/fr_FR.ISO8859-1 OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_FR.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/fr_FR.ISO8859-15 OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_FR.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/fr_FR.UTF-8 OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/fr_FR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/he_IL.UTF-8 OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/he_IL.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/hi_IN.ISCII-DEV OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_COLLATE OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_CTYPE OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_MESSAGES OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_MONETARY OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_NUMERIC OLD_FILES+=usr/share/locale/hi_IN.ISCII-DEV/LC_TIME OLD_DIRS+=usr/share/locale/hi_IN.UTF-8 OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hi_IN.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/hr_HR.ISO8859-2 OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/hr_HR.ISO8859-2/LC_TIME OLD_DIRS+=usr/share/locale/hr_HR.UTF-8 OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hr_HR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/hu_HU.ISO8859-2 OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/hu_HU.ISO8859-2/LC_TIME OLD_DIRS+=usr/share/locale/hu_HU.UTF-8 OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hu_HU.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/hy_AM.ARMSCII-8 OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_COLLATE OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_CTYPE OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_MONETARY OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hy_AM.ARMSCII-8/LC_TIME OLD_DIRS+=usr/share/locale/hy_AM.UTF-8 OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/hy_AM.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/is_IS.ISO8859-1 OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/is_IS.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/is_IS.ISO8859-15 OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/is_IS.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/is_IS.UTF-8 OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/is_IS.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/it_CH.ISO8859-1 OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/it_CH.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/it_CH.ISO8859-15 OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/it_CH.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/it_CH.UTF-8 OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/it_CH.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/it_IT.ISO8859-1 OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/it_IT.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/it_IT.ISO8859-15 OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/it_IT.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/it_IT.UTF-8 OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/it_IT.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ja_JP.eucJP OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_COLLATE OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_CTYPE OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_MESSAGES OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_MONETARY OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_NUMERIC OLD_FILES+=usr/share/locale/ja_JP.eucJP/LC_TIME OLD_DIRS+=usr/share/locale/ja_JP.SJIS OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_COLLATE OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_CTYPE OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_MESSAGES OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_MONETARY OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_NUMERIC OLD_FILES+=usr/share/locale/ja_JP.SJIS/LC_TIME OLD_DIRS+=usr/share/locale/ja_JP.UTF-8 OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ja_JP.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/kk_KZ.UTF-8 OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/kk_KZ.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ko_KR.CP949 OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_COLLATE OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_CTYPE OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_MESSAGES OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_MONETARY OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_NUMERIC OLD_FILES+=usr/share/locale/ko_KR.CP949/LC_TIME OLD_DIRS+=usr/share/locale/ko_KR.eucKR OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_COLLATE OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_CTYPE OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_MESSAGES OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_MONETARY OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_NUMERIC OLD_FILES+=usr/share/locale/ko_KR.eucKR/LC_TIME OLD_DIRS+=usr/share/locale/ko_KR.UTF-8 OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ko_KR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/lt_LT.ISO8859-13 OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_COLLATE OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_CTYPE OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_MESSAGES OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_MONETARY OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_NUMERIC OLD_FILES+=usr/share/locale/lt_LT.ISO8859-13/LC_TIME OLD_DIRS+=usr/share/locale/lt_LT.UTF-8 OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/lt_LT.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/lv_LV.ISO8859-13 OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_COLLATE OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_CTYPE OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_MESSAGES OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_MONETARY OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_NUMERIC OLD_FILES+=usr/share/locale/lv_LV.ISO8859-13/LC_TIME OLD_DIRS+=usr/share/locale/lv_LV.UTF-8 OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/lv_LV.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/mn_MN.UTF-8 OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/mn_MN.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/nb_NO.ISO8859-1 OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/nb_NO.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/nb_NO.ISO8859-15 OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/nb_NO.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/nb_NO.UTF-8 OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/nb_NO.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/nl_BE.ISO8859-1 OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_BE.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/nl_BE.ISO8859-15 OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_BE.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/nl_BE.UTF-8 OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_BE.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/nl_NL.ISO8859-1 OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_NL.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/nl_NL.ISO8859-15 OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_NL.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/nl_NL.UTF-8 OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/nl_NL.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/nn_NO.ISO8859-1 OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/nn_NO.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/nn_NO.ISO8859-15 OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/nn_NO.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/nn_NO.UTF-8 OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/nn_NO.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/pl_PL.ISO8859-2 OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/pl_PL.ISO8859-2/LC_TIME OLD_DIRS+=usr/share/locale/pl_PL.UTF-8 OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/pl_PL.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/pt_BR.ISO8859-1 OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_BR.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/pt_BR.UTF-8 OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_BR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/pt_PT.ISO8859-1 OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_PT.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/pt_PT.ISO8859-15 OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_PT.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/pt_PT.UTF-8 OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/pt_PT.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ro_RO.ISO8859-2 OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/ro_RO.ISO8859-2/LC_TIME OLD_DIRS+=usr/share/locale/ro_RO.UTF-8 OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ro_RO.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/ru_RU.CP1251 OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.CP1251/LC_TIME OLD_DIRS+=usr/share/locale/ru_RU.CP866 OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.CP866/LC_TIME OLD_DIRS+=usr/share/locale/ru_RU.ISO8859-5 OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.ISO8859-5/LC_TIME OLD_DIRS+=usr/share/locale/ru_RU.KOI8-R OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.KOI8-R/LC_TIME OLD_DIRS+=usr/share/locale/ru_RU.UTF-8 OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/ru_RU.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/se_FI.UTF-8 OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/se_FI.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/se_NO.UTF-8 OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/se_NO.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/sk_SK.ISO8859-2 OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/sk_SK.ISO8859-2/LC_TIME OLD_DIRS+=usr/share/locale/sk_SK.UTF-8 OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sk_SK.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/sl_SI.ISO8859-2 OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/sl_SI.ISO8859-2/LC_TIME OLD_DIRS+=usr/share/locale/sl_SI.UTF-8 OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sl_SI.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/sr_RS.ISO8859-5 OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_COLLATE OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_CTYPE OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_MESSAGES OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_MONETARY OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_NUMERIC OLD_FILES+=usr/share/locale/sr_RS.ISO8859-5/LC_TIME OLD_DIRS+=usr/share/locale/sr_RS.UTF-8 OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sr_RS.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/sr_RS.ISO8859-2 OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_COLLATE OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_CTYPE OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_MESSAGES OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_MONETARY OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_NUMERIC OLD_FILES+=usr/share/locale/sr_RS.ISO8859-2/LC_TIME OLD_DIRS+=usr/share/locale/sr_RS.UTF-8@latin OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_COLLATE OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_CTYPE OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_MESSAGES OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_MONETARY OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_NUMERIC OLD_FILES+=usr/share/locale/sr_RS.UTF-8@latin/LC_TIME OLD_DIRS+=usr/share/locale/sv_FI.ISO8859-1 OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_FI.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/sv_FI.ISO8859-15 OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_FI.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/sv_FI.UTF-8 OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_FI.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/sv_SE.ISO8859-1 OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_COLLATE OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_CTYPE OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_MONETARY OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_SE.ISO8859-1/LC_TIME OLD_DIRS+=usr/share/locale/sv_SE.ISO8859-15 OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_COLLATE OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_CTYPE OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_MONETARY OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_SE.ISO8859-15/LC_TIME OLD_DIRS+=usr/share/locale/sv_SE.UTF-8 OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/sv_SE.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/tr_TR.ISO8859-9 OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_COLLATE OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_CTYPE OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_MESSAGES OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_MONETARY OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_NUMERIC OLD_FILES+=usr/share/locale/tr_TR.ISO8859-9/LC_TIME OLD_DIRS+=usr/share/locale/tr_TR.UTF-8 OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/tr_TR.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/uk_UA.CP1251 OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_COLLATE OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_CTYPE OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_MESSAGES OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_MONETARY OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_NUMERIC OLD_FILES+=usr/share/locale/uk_UA.CP1251/LC_TIME OLD_DIRS+=usr/share/locale/uk_UA.ISO8859-5 OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_COLLATE OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_CTYPE OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_MESSAGES OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_MONETARY OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_NUMERIC OLD_FILES+=usr/share/locale/uk_UA.ISO8859-5/LC_TIME OLD_DIRS+=usr/share/locale/uk_UA.KOI8-U OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_COLLATE OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_CTYPE OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_MESSAGES OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_MONETARY OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_NUMERIC OLD_FILES+=usr/share/locale/uk_UA.KOI8-U/LC_TIME OLD_DIRS+=usr/share/locale/uk_UA.UTF-8 OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/uk_UA.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/zh_CN.eucCN OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.eucCN/LC_TIME OLD_DIRS+=usr/share/locale/zh_CN.GB18030 OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.GB18030/LC_TIME OLD_DIRS+=usr/share/locale/zh_CN.GB2312 OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.GB2312/LC_TIME OLD_DIRS+=usr/share/locale/zh_CN.GBK OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.GBK/LC_TIME OLD_DIRS+=usr/share/locale/zh_CN.UTF-8 OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_CN.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/zh_HK.UTF-8 OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_HK.UTF-8/LC_TIME OLD_DIRS+=usr/share/locale/zh_TW.Big5 OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_COLLATE OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_CTYPE OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_MONETARY OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_TW.Big5/LC_TIME OLD_DIRS+=usr/share/locale/zh_TW.UTF-8 OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_COLLATE OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_CTYPE OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_MESSAGES OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_MONETARY OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_NUMERIC OLD_FILES+=usr/share/locale/zh_TW.UTF-8/LC_TIME .endif .if ${MK_LOCATE} == no OLD_FILES+=etc/locate.rc OLD_FILES+=etc/periodic/weekly/310.locate OLD_FILES+=usr/bin/locate OLD_FILES+=usr/libexec/locate.bigram OLD_FILES+=usr/libexec/locate.code OLD_FILES+=usr/libexec/locate.concatdb OLD_FILES+=usr/libexec/locate.mklocatedb OLD_FILES+=usr/libexec/locate.updatedb OLD_FILES+=usr/share/man/man1/locate.1.gz OLD_FILES+=usr/share/man/man8/locate.updatedb.8.gz OLD_FILES+=usr/share/man/man8/updatedb.8.gz .endif .if ${MK_LPR} == no OLD_FILES+=etc/hosts.lpd OLD_FILES+=etc/printcap OLD_FILES+=etc/newsyslog.conf.d/lpr.conf OLD_FILES+=etc/rc.d/lpd OLD_FILES+=etc/syslog.d/lpr.conf OLD_FILES+=usr/bin/lp OLD_FILES+=usr/bin/lpq OLD_FILES+=usr/bin/lpr OLD_FILES+=usr/bin/lprm OLD_FILES+=usr/libexec/lpr/ru/bjc-240.sh.sample OLD_FILES+=usr/libexec/lpr/ru/koi2alt OLD_FILES+=usr/libexec/lpr/ru/koi2855 OLD_DIRS+=usr/libexec/lpr/ru OLD_FILES+=usr/libexec/lpr/lpf OLD_DIRS+=usr/libexec/lpr OLD_FILES+=usr/sbin/chkprintcap OLD_FILES+=usr/sbin/lpc OLD_FILES+=usr/sbin/lpd OLD_FILES+=usr/sbin/lptest OLD_FILES+=usr/sbin/pac OLD_FILES+=usr/share/doc/smm/07.lpd/paper.ascii.gz OLD_DIRS+=usr/share/doc/smm/07.lpd OLD_FILES+=usr/share/examples/etc/hosts.lpd OLD_FILES+=usr/share/examples/etc/printcap OLD_FILES+=usr/share/man/man1/lp.1.gz OLD_FILES+=usr/share/man/man1/lpq.1.gz OLD_FILES+=usr/share/man/man1/lpr.1.gz OLD_FILES+=usr/share/man/man1/lprm.1.gz OLD_FILES+=usr/share/man/man1/lptest.1.gz OLD_FILES+=usr/share/man/man5/printcap.5.gz OLD_FILES+=usr/share/man/man8/chkprintcap.8.gz OLD_FILES+=usr/share/man/man8/lpc.8.gz OLD_FILES+=usr/share/man/man8/lpd.8.gz OLD_FILES+=usr/share/man/man8/pac.8.gz .endif .if ${MK_MAIL} == no OLD_FILES+=etc/aliases OLD_FILES+=etc/mail.rc OLD_FILES+=etc/mail/aliases OLD_FILES+=etc/mail/mailer.conf OLD_FILES+=etc/periodic/daily/130.clean-msgs OLD_FILES+=etc/rc.d/othermta OLD_FILES+=usr/bin/Mail OLD_FILES+=usr/bin/biff OLD_FILES+=usr/bin/from OLD_FILES+=usr/bin/mail OLD_FILES+=usr/bin/mailx OLD_FILES+=usr/bin/msgs OLD_FILES+=usr/libexec/comsat OLD_FILES+=usr/share/examples/etc/mail.rc OLD_FILES+=usr/share/man/man1/Mail.1.gz OLD_FILES+=usr/share/man/man1/biff.1.gz OLD_FILES+=usr/share/man/man1/from.1.gz OLD_FILES+=usr/share/man/man1/mail.1.gz OLD_FILES+=usr/share/man/man1/mailx.1.gz OLD_FILES+=usr/share/man/man1/msgs.1.gz OLD_FILES+=usr/share/man/man8/comsat.8.gz OLD_FILES+=usr/share/misc/mail.help OLD_FILES+=usr/share/misc/mail.tildehelp .endif .if ${MK_MAILWRAPPER} == no OLD_FILES+=etc/mail/mailer.conf # Don't remove, for no mailwrapper case: # /usr/sbin/sendmail -> /usr/sbin/mailwrapper # /usr/sbin/mailwrapper -> /usr/libexec/sendmail/sendmail #OLD_FILES+=usr/sbin/mailwrapper OLD_FILES+=usr/share/man/man8/mailwrapper.8.gz .endif .if ${MK_MAKE} == no OLD_FILES+=usr/bin/make OLD_FILES+=usr/share/man/man1/make.1.gz OLD_FILES+=usr/share/mk/atf.test.mk OLD_FILES+=usr/share/mk/bsd.README OLD_FILES+=usr/share/mk/bsd.arch.inc.mk OLD_FILES+=usr/share/mk/bsd.compiler.mk OLD_FILES+=usr/share/mk/bsd.cpu.mk OLD_FILES+=usr/share/mk/bsd.crunchgen.mk OLD_FILES+=usr/share/mk/bsd.dep.mk OLD_FILES+=usr/share/mk/bsd.doc.mk OLD_FILES+=usr/share/mk/bsd.dtb.mk OLD_FILES+=usr/share/mk/bsd.endian.mk OLD_FILES+=usr/share/mk/bsd.files.mk OLD_FILES+=usr/share/mk/bsd.incs.mk OLD_FILES+=usr/share/mk/bsd.info.mk OLD_FILES+=usr/share/mk/bsd.init.mk OLD_FILES+=usr/share/mk/bsd.kmod.mk OLD_FILES+=usr/share/mk/bsd.lib.mk OLD_FILES+=usr/share/mk/bsd.libnames.mk OLD_FILES+=usr/share/mk/bsd.links.mk OLD_FILES+=usr/share/mk/bsd.man.mk OLD_FILES+=usr/share/mk/bsd.mkopt.mk OLD_FILES+=usr/share/mk/bsd.nls.mk OLD_FILES+=usr/share/mk/bsd.obj.mk OLD_FILES+=usr/share/mk/bsd.opts.mk OLD_FILES+=usr/share/mk/bsd.own.mk OLD_FILES+=usr/share/mk/bsd.port.mk OLD_FILES+=usr/share/mk/bsd.port.options.mk OLD_FILES+=usr/share/mk/bsd.port.post.mk OLD_FILES+=usr/share/mk/bsd.port.pre.mk OLD_FILES+=usr/share/mk/bsd.port.subdir.mk OLD_FILES+=usr/share/mk/bsd.prog.mk OLD_FILES+=usr/share/mk/bsd.progs.mk OLD_FILES+=usr/share/mk/bsd.snmpmod.mk OLD_FILES+=usr/share/mk/bsd.subdir.mk OLD_FILES+=usr/share/mk/bsd.symver.mk OLD_FILES+=usr/share/mk/bsd.sys.mk OLD_FILES+=usr/share/mk/bsd.test.mk OLD_FILES+=usr/share/mk/plain.test.mk OLD_FILES+=usr/share/mk/suite.test.mk OLD_FILES+=usr/share/mk/sys.mk OLD_FILES+=usr/share/mk/tap.test.mk OLD_FILES+=usr/share/mk/version_gen.awk OLD_FILES+=usr/tests/usr.bin/bmake/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.status.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd/libtest.a OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.status.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_44bsd_mod/libtest.a OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.status.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stderr.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.6 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/expected.stdout.7 OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/archives/fmt_oldbsd/libtest.a OLD_FILES+=usr/tests/usr.bin/bmake/basic/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t0/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t2/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/basic/t3/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/common.sh OLD_FILES+=usr/tests/usr.bin/bmake/execution/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/ellipsis/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/empty/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/joberr/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/execution/plus/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/builtin/sh OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/meta/sh OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/path/sh OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/path_select/shell OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/shell/replace/shell OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/shell/select/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/TEST1.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/basic/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/TEST1.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/TEST2.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/TEST1.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/TEST2.a OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/suffixes/src_wild2/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/directive-t0/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.4 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.status.5 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.4 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stderr.5 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.4 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/expected.stdout.5 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/enl/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/funny-targets/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/syntax/semi/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t0/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/cleanup OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t1/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/cleanup OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/1/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/mk/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/sysmk/t2/mk/sys.mk OLD_FILES+=usr/tests/usr.bin/bmake/test-new.mk OLD_FILES+=usr/tests/usr.bin/bmake/variables/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_M/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.status.3 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stderr.3 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/expected.stdout.3 OLD_FILES+=usr/tests/usr.bin/bmake/variables/modifier_t/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.status.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stderr.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/expected.stdout.2 OLD_FILES+=usr/tests/usr.bin/bmake/variables/opt_V/legacy_test OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/Kyuafile OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/Makefile.test OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.status.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.stderr.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/expected.stdout.1 OLD_FILES+=usr/tests/usr.bin/bmake/variables/t0/legacy_test .endif .if ${MK_MAN} == no MAN_FILES!=find ${DESTDIR}/usr/share/man ${DESTDIR}/usr/share/openssl/man -type f | sed -e 's,^${DESTDIR}/,,'; echo OLD_FILES+=${MAN_FILES} MAN_DIRS!=find ${DESTDIR}/usr/share/man ${DESTDIR}/usr/share/openssl/man -type d | sed -e 's,^${DESTDIR}/,,'; echo OLD_DIRS+=${MAN_DIRS} .endif .if ${MK_MAN_UTILS} == no OLD_FILES+=etc/periodic/weekly/320.whatis OLD_FILES+=usr/bin/apropos OLD_FILES+=usr/bin/makewhatis OLD_FILES+=usr/bin/man OLD_FILES+=usr/bin/manpath OLD_FILES+=usr/bin/whatis OLD_FILES+=usr/libexec/makewhatis.local OLD_FILES+=usr/sbin/manctl OLD_FILES+=usr/share/man/man1/apropos.1.gz OLD_FILES+=usr/share/man/man1/makewhatis.1.gz OLD_FILES+=usr/share/man/man1/man.1.gz OLD_FILES+=usr/share/man/man1/manpath.1.gz OLD_FILES+=usr/share/man/man1/whatis.1.gz OLD_FILES+=usr/share/man/man5/man.conf.5.gz OLD_FILES+=usr/share/man/man8/makewhatis.local.8.gz OLD_FILES+=usr/share/man/man8/manctl.8.gz OLD_FILES+=usr/share/man/whatis OLD_FILES+=usr/share/openssl/man/whatis .endif .if ${MK_NDIS} == no OLD_FILES+=usr/sbin/ndiscvt OLD_FILES+=usr/sbin/ndisgen OLD_FILES+=usr/share/man/man8/ndiscvt.8.gz OLD_FILES+=usr/share/man/man8/ndisgen.8.gz OLD_FILES+=usr/share/misc/windrv_stub.c .endif .if ${MK_NETCAT} == no OLD_FILES+=rescue/nc OLD_FILES+=usr/bin/nc OLD_FILES+=usr/share/man/man1/nc.1.gz .endif .if ${MK_NETGRAPH} == no OLD_FILES+=usr/include/netgraph.h OLD_FILES+=usr/lib/libnetgraph.a OLD_FILES+=usr/lib/libnetgraph.so OLD_LIBS+=usr/lib/libnetgraph.so.4 OLD_FILES+=usr/lib/libnetgraph_p.a OLD_FILES+=usr/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_IPFW} == no || ${MK_NETGRAPH} == no OLD_FILES+=etc/rc.d/ipfw_netflow .endif .if ${MK_NETGRAPH_SUPPORT} == no OLD_FILES+=usr/include/bsnmp/snmp_netgraph.h OLD_FILES+=usr/lib/snmp_netgraph.so OLD_LIBS+=usr/lib/snmp_netgraph.so.6 OLD_FILES+=usr/share/man/man3/snmp_netgraph.3.gz OLD_FILES+=usr/share/snmp/defs/netgraph_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-NETGRAPH.txt .endif .if ${MK_NIS} == no OLD_FILES+=etc/rc.d/ypbind OLD_FILES+=etc/rc.d/ypldap OLD_FILES+=etc/rc.d/yppasswdd OLD_FILES+=etc/rc.d/ypserv OLD_FILES+=etc/rc.d/ypset OLD_FILES+=etc/rc.d/ypupdated OLD_FILES+=etc/rc.d/ypxfrd OLD_FILES+=usr/bin/ypcat OLD_FILES+=usr/bin/ypchfn OLD_FILES+=usr/bin/ypchpass OLD_FILES+=usr/bin/ypchsh OLD_FILES+=usr/bin/ypmatch OLD_FILES+=usr/bin/yppasswd OLD_FILES+=usr/bin/ypwhich OLD_FILES+=usr/include/ypclnt.h OLD_FILES+=usr/lib/libypclnt.a OLD_FILES+=usr/lib/libypclnt.so OLD_LIBS+=usr/lib/libypclnt.so.4 OLD_FILES+=usr/lib/libypclnt_p.a .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_DIRS+=usr/share/nls/ OLD_DIRS+=usr/share/nls/C OLD_FILES+=usr/share/nls/C/ee.cat OLD_DIRS+=usr/share/nls/af_ZA.ISO8859-1 OLD_DIRS+=usr/share/nls/af_ZA.ISO8859-15 OLD_DIRS+=usr/share/nls/af_ZA.UTF-8 OLD_DIRS+=usr/share/nls/am_ET.UTF-8 OLD_DIRS+=usr/share/nls/be_BY.CP1131 OLD_DIRS+=usr/share/nls/be_BY.CP1251 OLD_DIRS+=usr/share/nls/be_BY.ISO8859-5 OLD_DIRS+=usr/share/nls/be_BY.UTF-8 OLD_FILES+=usr/share/nls/be_BY.UTF-8/libc.cat OLD_DIRS+=usr/share/nls/bg_BG.CP1251 OLD_DIRS+=usr/share/nls/bg_BG.UTF-8 OLD_DIRS+=usr/share/nls/ca_ES.ISO8859-1 OLD_FILES+=usr/share/nls/ca_ES.ISO8859-1/libc.cat OLD_DIRS+=usr/share/nls/ca_ES.ISO8859-15 OLD_DIRS+=usr/share/nls/ca_ES.UTF-8 OLD_DIRS+=usr/share/nls/cs_CZ.ISO8859-2 OLD_DIRS+=usr/share/nls/cs_CZ.UTF-8 OLD_DIRS+=usr/share/nls/da_DK.ISO8859-1 OLD_DIRS+=usr/share/nls/da_DK.ISO8859-15 OLD_DIRS+=usr/share/nls/da_DK.UTF-8 OLD_DIRS+=usr/share/nls/de_AT.ISO8859-1 OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/de_AT.ISO8859-15 OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/de_AT.UTF-8 OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/de_CH.ISO8859-1 OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/de_CH.ISO8859-15 OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/de_CH.UTF-8 OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/de_DE.ISO8859-1 OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/de_DE.ISO8859-15 OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/de_DE.UTF-8 OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/el_GR.ISO8859-7 OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/libc.cat OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/tcsh.cat OLD_DIRS+=usr/share/nls/el_GR.UTF-8 OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/en_AU.ISO8859-1 OLD_DIRS+=usr/share/nls/en_AU.ISO8859-15 OLD_DIRS+=usr/share/nls/en_AU.US-ASCII OLD_DIRS+=usr/share/nls/en_AU.UTF-8 OLD_DIRS+=usr/share/nls/en_CA.ISO8859-1 OLD_FILES+=usr/share/nls/en_US.ISO8859-1/ee.cat OLD_DIRS+=usr/share/nls/en_CA.ISO8859-15 OLD_DIRS+=usr/share/nls/en_CA.US-ASCII OLD_DIRS+=usr/share/nls/en_CA.UTF-8 OLD_DIRS+=usr/share/nls/en_GB.ISO8859-1 OLD_DIRS+=usr/share/nls/en_GB.ISO8859-15 OLD_DIRS+=usr/share/nls/en_GB.US-ASCII OLD_DIRS+=usr/share/nls/en_GB.UTF-8 OLD_DIRS+=usr/share/nls/en_IE.UTF-8 OLD_DIRS+=usr/share/nls/en_NZ.ISO8859-1 OLD_DIRS+=usr/share/nls/en_NZ.ISO8859-15 OLD_DIRS+=usr/share/nls/en_NZ.US-ASCII OLD_DIRS+=usr/share/nls/en_NZ.UTF-8 OLD_DIRS+=usr/share/nls/en_US.ISO8859-1 OLD_DIRS+=usr/share/nls/en_US.ISO8859-15 OLD_FILES+=usr/share/nls/en_US.ISO8859-15/ee.cat OLD_DIRS+=usr/share/nls/en_US.UTF-8 OLD_DIRS+=usr/share/nls/es_ES.UTF-8 OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/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_DIRS+=usr/share/nls/es_ES.ISO8859-1 OLD_DIRS+=usr/share/nls/es_ES.ISO8859-15 OLD_FILES+=usr/share/nls/es_ES.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/et_EE.ISO8859-15 OLD_FILES+=usr/share/nls/et_EE.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/et_EE.UTF-8 OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/fi_FI.ISO8859-1 OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/fi_FI.ISO8859-15 OLD_FILES+=usr/share/nls/fi_FI.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/fi_FI.UTF-8 OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/fr_BE.ISO8859-1 OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/fr_BE.ISO8859-15 OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/fr_BE.UTF-8 OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/fr_CA.ISO8859-1 OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/fr_CA.ISO8859-15 OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/fr_CA.UTF-8 OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/fr_CH.ISO8859-1 OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/fr_CH.ISO8859-15 OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/fr_CH.UTF-8 OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/fr_FR.ISO8859-1 OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/libc.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/fr_FR.ISO8859-15 OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/ee.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/fr_FR.UTF-8 OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/gl_ES.ISO8859-1 OLD_FILES+=usr/share/nls/gl_ES.ISO8859-1/grep.cat OLD_FILES+=usr/share/nls/gl_ES.ISO8859-1/libc.cat OLD_DIRS+=usr/share/nls/he_IL.UTF-8 OLD_DIRS+=usr/share/nls/hi_IN.ISCII-DEV OLD_DIRS+=usr/share/nls/hr_HR.ISO8859-2 OLD_DIRS+=usr/share/nls/hu_HU.ISO8859-2 OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/ee.cat OLD_FILES+=usr/share/nls/hu_HU.ISO8859-2/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_DIRS+=usr/share/nls/hr_HR.UTF-8 OLD_DIRS+=usr/share/nls/hu_HU.UTF-8 OLD_DIRS+=usr/share/nls/hy_AM.ARMSCII-8 OLD_DIRS+=usr/share/nls/hy_AM.UTF-8 OLD_DIRS+=usr/share/nls/is_IS.ISO8859-1 OLD_DIRS+=usr/share/nls/is_IS.ISO8859-15 OLD_DIRS+=usr/share/nls/is_IS.UTF-8 OLD_DIRS+=usr/share/nls/it_CH.ISO8859-1 OLD_FILES+=usr/share/nls/it_CH.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/it_CH.ISO8859-15 OLD_FILES+=usr/share/nls/it_CH.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/it_CH.UTF-8 OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/it_IT.ISO8859-1 OLD_FILES+=usr/share/nls/it_IT.ISO8859-1/tcsh.cat OLD_DIRS+=usr/share/nls/it_IT.ISO8859-15 OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/libc.cat OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/tcsh.cat OLD_DIRS+=usr/share/nls/it_IT.UTF-8 OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/ja_JP.SJIS OLD_FILES+=usr/share/nls/ja_JP.SJIS/grep.cat OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat OLD_DIRS+=usr/share/nls/ja_JP.UTF-8 OLD_FILES+=usr/share/nls/ja_JP.UTF-8/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_DIRS+=usr/share/nls/ja_JP.eucJP 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_DIRS+=usr/share/nls/kk_KZ.PT154 OLD_DIRS+=usr/share/nls/kk_KZ.UTF-8 OLD_DIRS+=usr/share/nls/ko_KR.CP949 OLD_DIRS+=usr/share/nls/ko_KR.UTF-8 OLD_FILES+=usr/share/nls/ko_KR.UTF-8/libc.cat OLD_DIRS+=usr/share/nls/ko_KR.eucKR OLD_FILES+=usr/share/nls/ko_KR.eucKR/libc.cat OLD_DIRS+=usr/share/nls/lv_LV.UTF-8 OLD_DIRS+=usr/share/nls/lt_LT.ISO8859-13 OLD_DIRS+=usr/share/nls/lt_LT.UTF-8 OLD_DIRS+=usr/share/nls/lv_LV.ISO8859-13 OLD_DIRS+=usr/share/nls/mn_MN.UTF-8 OLD_FILES+=usr/share/nls/mn_MN.UTF-8/libc.cat OLD_DIRS+=usr/share/nls/nl_BE.ISO8859-1 OLD_DIRS+=usr/share/nls/nl_BE.ISO8859-15 OLD_DIRS+=usr/share/nls/nl_BE.UTF-8 OLD_DIRS+=usr/share/nls/no_NO.ISO8859-1 OLD_FILES+=usr/share/nls/nl_NL.ISO8859-1/libc.cat OLD_DIRS+=usr/share/nls/nl_NL.ISO8859-15 OLD_DIRS+=usr/share/nls/nl_NL.ISO8859-1 OLD_FILES+=usr/share/nls/no_NO.ISO8859-1/libc.cat OLD_DIRS+=usr/share/nls/no_NO.ISO8859-15 OLD_DIRS+=usr/share/nls/nl_NL.UTF-8 OLD_DIRS+=usr/share/nls/no_NO.UTF-8 OLD_DIRS+=usr/share/nls/pl_PL.ISO8859-2 OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/ee.cat OLD_FILES+=usr/share/nls/pl_PL.ISO8859-2/libc.cat OLD_DIRS+=usr/share/nls/pl_PL.UTF-8 OLD_DIRS+=usr/share/nls/pt_BR.ISO8859-1 OLD_DIRS+=usr/share/nls/pt_BR.UTF-8 OLD_DIRS+=usr/share/nls/pt_PT.ISO8859-1 OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/ee.cat OLD_FILES+=usr/share/nls/pt_BR.ISO8859-1/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_DIRS+=usr/share/nls/pt_PT.ISO8859-15 OLD_DIRS+=usr/share/nls/pt_PT.UTF-8 OLD_DIRS+=usr/share/nls/ro_RO.ISO8859-2 OLD_DIRS+=usr/share/nls/ro_RO.UTF-8 OLD_DIRS+=usr/share/nls/ru_RU.CP1251 OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat OLD_DIRS+=usr/share/nls/ru_RU.CP866 OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat OLD_DIRS+=usr/share/nls/ru_RU.ISO8859-5 OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat OLD_DIRS+=usr/share/nls/ru_RU.KOI8-R OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/ee.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/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_DIRS+=usr/share/nls/ru_RU.UTF-8 OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat OLD_DIRS+=usr/share/nls/sk_SK.ISO8859-2 OLD_FILES+=usr/share/nls/sk_SK.ISO8859-2/libc.cat OLD_DIRS+=usr/share/nls/sk_SK.UTF-8 OLD_DIRS+=usr/share/nls/sl_SI.ISO8859-2 OLD_DIRS+=usr/share/nls/sl_SI.UTF-8 OLD_DIRS+=usr/share/nls/sr_YU.ISO8859-2 OLD_DIRS+=usr/share/nls/sr_YU.ISO8859-5 OLD_DIRS+=usr/share/nls/sr_YU.UTF-8 OLD_DIRS+=usr/share/nls/sv_SE.ISO8859-1 OLD_FILES+=usr/share/nls/sv_SE.ISO8859-1/libc.cat OLD_DIRS+=usr/share/nls/sv_SE.ISO8859-15 OLD_DIRS+=usr/share/nls/sv_SE.UTF-8 OLD_DIRS+=usr/share/nls/tr_TR.ISO8859-9 OLD_DIRS+=usr/share/nls/tr_TR.UTF-8 OLD_DIRS+=usr/share/nls/uk_UA.ISO8859-5 OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat OLD_DIRS+=usr/share/nls/uk_UA.KOI8-U OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/ee.cat OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat OLD_DIRS+=usr/share/nls/uk_UA.UTF-8 OLD_FILES+=usr/share/nls/uk_UA.UTF-8/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_DIRS+=usr/share/nls/zh_CN.GB18030 OLD_FILES+=usr/share/nls/zh_CN.GB18030/libc.cat OLD_DIRS+=usr/share/nls/zh_CN.GBK OLD_DIRS+=usr/share/nls/zh_CN.GB2312 OLD_FILES+=usr/share/nls/zh_CN.GB2312/libc.cat OLD_DIRS+=usr/share/nls/zh_CN.UTF-8 OLD_FILES+=usr/share/nls/zh_CN.UTF-8/grep.cat OLD_FILES+=usr/share/nls/zh_CN.UTF-8/libc.cat OLD_DIRS+=usr/share/nls/zh_CN.eucCN OLD_DIRS+=usr/share/nls/zh_HK.UTF-8 OLD_DIRS+=usr/share/nls/zh_TW.UTF-8 OLD_FILES+=usr/tests/bin/sh/builtins/locale1.0 .endif .if ${MK_NLS_CATALOGS} == no OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat .endif .if ${MK_NS_CACHING} == no OLD_FILES+=etc/nscd.conf OLD_FILES+=etc/rc.d/nscd OLD_FILES+=usr/sbin/nscd OLD_FILES+=usr/share/examples/etc/nscd.conf OLD_FILES+=usr/share/man/man5/nscd.conf.5.gz OLD_FILES+=usr/share/man/man8/nscd.8.gz .endif .if ${MK_NTP} == no OLD_FILES+=etc/ntp/leap-seconds OLD_DIRS+=etc/ntp OLD_FILES+=etc/ntp.conf OLD_FILES+=etc/periodic/daily/480.status-ntpd OLD_FILES+=etc/periodic/daily/480.leapfile-ntpd OLD_FILES+=etc/rc.d/ntpd OLD_FILES+=usr/bin/ntpq OLD_FILES+=usr/sbin/ntp-keygen OLD_FILES+=usr/sbin/ntpd OLD_FILES+=usr/sbin/ntpdate OLD_FILES+=usr/sbin/ntpdc OLD_FILES+=usr/sbin/ntptime OLD_FILES+=usr/sbin/sntp OLD_FILES+=usr/share/doc/ntp/access.html OLD_FILES+=usr/share/doc/ntp/accopt.html OLD_FILES+=usr/share/doc/ntp/assoc.html OLD_FILES+=usr/share/doc/ntp/audio.html OLD_FILES+=usr/share/doc/ntp/authentic.html OLD_FILES+=usr/share/doc/ntp/authopt.html OLD_FILES+=usr/share/doc/ntp/autokey.html OLD_FILES+=usr/share/doc/ntp/bugs.html OLD_FILES+=usr/share/doc/ntp/build.html OLD_FILES+=usr/share/doc/ntp/clock.html OLD_FILES+=usr/share/doc/ntp/clockopt.html OLD_FILES+=usr/share/doc/ntp/cluster.html OLD_FILES+=usr/share/doc/ntp/comdex.html OLD_FILES+=usr/share/doc/ntp/config.html OLD_FILES+=usr/share/doc/ntp/confopt.html OLD_FILES+=usr/share/doc/ntp/copyright.html OLD_FILES+=usr/share/doc/ntp/debug.html OLD_FILES+=usr/share/doc/ntp/decode.html OLD_FILES+=usr/share/doc/ntp/discipline.html OLD_FILES+=usr/share/doc/ntp/discover.html OLD_FILES+=usr/share/doc/ntp/driver1.html OLD_FILES+=usr/share/doc/ntp/driver10.html OLD_FILES+=usr/share/doc/ntp/driver11.html OLD_FILES+=usr/share/doc/ntp/driver12.html OLD_FILES+=usr/share/doc/ntp/driver16.html OLD_FILES+=usr/share/doc/ntp/driver18.html OLD_FILES+=usr/share/doc/ntp/driver19.html OLD_FILES+=usr/share/doc/ntp/driver2.html OLD_FILES+=usr/share/doc/ntp/driver20.html OLD_FILES+=usr/share/doc/ntp/driver22.html OLD_FILES+=usr/share/doc/ntp/driver26.html OLD_FILES+=usr/share/doc/ntp/driver27.html OLD_FILES+=usr/share/doc/ntp/driver28.html OLD_FILES+=usr/share/doc/ntp/driver29.html OLD_FILES+=usr/share/doc/ntp/driver3.html OLD_FILES+=usr/share/doc/ntp/driver30.html OLD_FILES+=usr/share/doc/ntp/driver32.html OLD_FILES+=usr/share/doc/ntp/driver33.html OLD_FILES+=usr/share/doc/ntp/driver34.html OLD_FILES+=usr/share/doc/ntp/driver35.html OLD_FILES+=usr/share/doc/ntp/driver36.html OLD_FILES+=usr/share/doc/ntp/driver37.html OLD_FILES+=usr/share/doc/ntp/driver4.html OLD_FILES+=usr/share/doc/ntp/driver5.html OLD_FILES+=usr/share/doc/ntp/driver6.html OLD_FILES+=usr/share/doc/ntp/driver7.html OLD_FILES+=usr/share/doc/ntp/driver8.html OLD_FILES+=usr/share/doc/ntp/driver9.html OLD_FILES+=usr/share/doc/ntp/drivers/driver1.html OLD_FILES+=usr/share/doc/ntp/drivers/driver10.html OLD_FILES+=usr/share/doc/ntp/drivers/driver11.html OLD_FILES+=usr/share/doc/ntp/drivers/driver12.html OLD_FILES+=usr/share/doc/ntp/drivers/driver16.html OLD_FILES+=usr/share/doc/ntp/drivers/driver18.html OLD_FILES+=usr/share/doc/ntp/drivers/driver19.html OLD_FILES+=usr/share/doc/ntp/drivers/driver20.html OLD_FILES+=usr/share/doc/ntp/drivers/driver22.html OLD_FILES+=usr/share/doc/ntp/drivers/driver26.html OLD_FILES+=usr/share/doc/ntp/drivers/driver27.html OLD_FILES+=usr/share/doc/ntp/drivers/driver28.html OLD_FILES+=usr/share/doc/ntp/drivers/driver29.html OLD_FILES+=usr/share/doc/ntp/drivers/driver3.html OLD_FILES+=usr/share/doc/ntp/drivers/driver30.html OLD_FILES+=usr/share/doc/ntp/drivers/driver31.html OLD_FILES+=usr/share/doc/ntp/drivers/driver32.html OLD_FILES+=usr/share/doc/ntp/drivers/driver33.html OLD_FILES+=usr/share/doc/ntp/drivers/driver34.html OLD_FILES+=usr/share/doc/ntp/drivers/driver35.html OLD_FILES+=usr/share/doc/ntp/drivers/driver36.html OLD_FILES+=usr/share/doc/ntp/drivers/driver37.html OLD_FILES+=usr/share/doc/ntp/drivers/driver38.html OLD_FILES+=usr/share/doc/ntp/drivers/driver39.html OLD_FILES+=usr/share/doc/ntp/drivers/driver4.html OLD_FILES+=usr/share/doc/ntp/drivers/driver40.html OLD_FILES+=usr/share/doc/ntp/drivers/driver42.html OLD_FILES+=usr/share/doc/ntp/drivers/driver43.html OLD_FILES+=usr/share/doc/ntp/drivers/driver44.html OLD_FILES+=usr/share/doc/ntp/drivers/driver45.html OLD_FILES+=usr/share/doc/ntp/drivers/driver46.html OLD_FILES+=usr/share/doc/ntp/drivers/driver5.html OLD_FILES+=usr/share/doc/ntp/drivers/driver6.html OLD_FILES+=usr/share/doc/ntp/drivers/driver7.html OLD_FILES+=usr/share/doc/ntp/drivers/driver8.html OLD_FILES+=usr/share/doc/ntp/drivers/driver9.html OLD_FILES+=usr/share/doc/ntp/drivers/icons/home.gif OLD_FILES+=usr/share/doc/ntp/drivers/icons/mail2.gif OLD_FILES+=usr/share/doc/ntp/drivers/mx4200data.html OLD_FILES+=usr/share/doc/ntp/drivers/oncore-shmem.html OLD_FILES+=usr/share/doc/ntp/drivers/scripts/footer.txt OLD_FILES+=usr/share/doc/ntp/drivers/scripts/style.css OLD_FILES+=usr/share/doc/ntp/drivers/tf582_4.html OLD_FILES+=usr/share/doc/ntp/extern.html OLD_FILES+=usr/share/doc/ntp/filter.html OLD_FILES+=usr/share/doc/ntp/hints.html OLD_FILES+=usr/share/doc/ntp/hints/a-ux OLD_FILES+=usr/share/doc/ntp/hints/aix OLD_FILES+=usr/share/doc/ntp/hints/bsdi OLD_FILES+=usr/share/doc/ntp/hints/changes OLD_FILES+=usr/share/doc/ntp/hints/decosf1 OLD_FILES+=usr/share/doc/ntp/hints/decosf2 OLD_FILES+=usr/share/doc/ntp/hints/freebsd OLD_FILES+=usr/share/doc/ntp/hints/hpux OLD_FILES+=usr/share/doc/ntp/hints/linux OLD_FILES+=usr/share/doc/ntp/hints/mpeix OLD_FILES+=usr/share/doc/ntp/hints/notes-xntp-v3 OLD_FILES+=usr/share/doc/ntp/hints/parse OLD_FILES+=usr/share/doc/ntp/hints/refclocks OLD_FILES+=usr/share/doc/ntp/hints/rs6000 OLD_FILES+=usr/share/doc/ntp/hints/sco.html OLD_FILES+=usr/share/doc/ntp/hints/sgi OLD_FILES+=usr/share/doc/ntp/hints/solaris-dosynctodr.html OLD_FILES+=usr/share/doc/ntp/hints/solaris.html OLD_FILES+=usr/share/doc/ntp/hints/solaris.xtra.4023118 OLD_FILES+=usr/share/doc/ntp/hints/solaris.xtra.4095849 OLD_FILES+=usr/share/doc/ntp/hints/solaris.xtra.S99ntpd OLD_FILES+=usr/share/doc/ntp/hints/solaris.xtra.patchfreq OLD_FILES+=usr/share/doc/ntp/hints/sun4 OLD_FILES+=usr/share/doc/ntp/hints/svr4-dell OLD_FILES+=usr/share/doc/ntp/hints/svr4_package OLD_FILES+=usr/share/doc/ntp/hints/todo OLD_FILES+=usr/share/doc/ntp/hints/vxworks.html OLD_FILES+=usr/share/doc/ntp/hints/winnt.html OLD_FILES+=usr/share/doc/ntp/history.html OLD_FILES+=usr/share/doc/ntp/howto.html OLD_FILES+=usr/share/doc/ntp/huffpuff.html OLD_FILES+=usr/share/doc/ntp/icons/home.gif OLD_FILES+=usr/share/doc/ntp/icons/mail2.gif OLD_FILES+=usr/share/doc/ntp/icons/sitemap.png OLD_FILES+=usr/share/doc/ntp/index.html OLD_FILES+=usr/share/doc/ntp/kern.html OLD_FILES+=usr/share/doc/ntp/kernpps.html OLD_FILES+=usr/share/doc/ntp/keygen.html OLD_FILES+=usr/share/doc/ntp/ldisc.html OLD_FILES+=usr/share/doc/ntp/leap.html OLD_FILES+=usr/share/doc/ntp/measure.html OLD_FILES+=usr/share/doc/ntp/miscopt.html OLD_FILES+=usr/share/doc/ntp/monopt.html OLD_FILES+=usr/share/doc/ntp/msyslog.html OLD_FILES+=usr/share/doc/ntp/mx4200data.html OLD_FILES+=usr/share/doc/ntp/notes.html OLD_FILES+=usr/share/doc/ntp/ntp-keygen.html OLD_FILES+=usr/share/doc/ntp/ntp-wait.html OLD_FILES+=usr/share/doc/ntp/ntp.conf.html OLD_FILES+=usr/share/doc/ntp/ntp.keys.html OLD_FILES+=usr/share/doc/ntp/ntp_conf.html OLD_FILES+=usr/share/doc/ntp/ntpd.html OLD_FILES+=usr/share/doc/ntp/ntpdate.html OLD_FILES+=usr/share/doc/ntp/ntpdc.html OLD_FILES+=usr/share/doc/ntp/ntpdsim.html OLD_FILES+=usr/share/doc/ntp/ntpdsim_new.html OLD_FILES+=usr/share/doc/ntp/ntpq.html OLD_FILES+=usr/share/doc/ntp/ntpsnmpd.html OLD_FILES+=usr/share/doc/ntp/ntptime.html OLD_FILES+=usr/share/doc/ntp/ntptrace.html OLD_FILES+=usr/share/doc/ntp/orphan.html OLD_FILES+=usr/share/doc/ntp/parsedata.html OLD_FILES+=usr/share/doc/ntp/parsenew.html OLD_FILES+=usr/share/doc/ntp/patches.html OLD_FILES+=usr/share/doc/ntp/pic/9400n.jpg OLD_FILES+=usr/share/doc/ntp/pic/alice11.gif OLD_FILES+=usr/share/doc/ntp/pic/alice13.gif OLD_FILES+=usr/share/doc/ntp/pic/alice15.gif OLD_FILES+=usr/share/doc/ntp/pic/alice23.gif OLD_FILES+=usr/share/doc/ntp/pic/alice31.gif OLD_FILES+=usr/share/doc/ntp/pic/alice32.gif OLD_FILES+=usr/share/doc/ntp/pic/alice35.gif OLD_FILES+=usr/share/doc/ntp/pic/alice38.gif OLD_FILES+=usr/share/doc/ntp/pic/alice44.gif OLD_FILES+=usr/share/doc/ntp/pic/alice47.gif OLD_FILES+=usr/share/doc/ntp/pic/alice51.gif OLD_FILES+=usr/share/doc/ntp/pic/alice61.gif OLD_FILES+=usr/share/doc/ntp/pic/barnstable.gif OLD_FILES+=usr/share/doc/ntp/pic/beaver.gif OLD_FILES+=usr/share/doc/ntp/pic/boom3.gif OLD_FILES+=usr/share/doc/ntp/pic/boom3a.gif OLD_FILES+=usr/share/doc/ntp/pic/boom4.gif OLD_FILES+=usr/share/doc/ntp/pic/broad.gif OLD_FILES+=usr/share/doc/ntp/pic/bustardfly.gif OLD_FILES+=usr/share/doc/ntp/pic/c51.jpg OLD_FILES+=usr/share/doc/ntp/pic/description.jpg OLD_FILES+=usr/share/doc/ntp/pic/discipline.gif OLD_FILES+=usr/share/doc/ntp/pic/dogsnake.gif OLD_FILES+=usr/share/doc/ntp/pic/driver29.gif OLD_FILES+=usr/share/doc/ntp/pic/driver43_1.gif OLD_FILES+=usr/share/doc/ntp/pic/driver43_2.jpg OLD_FILES+=usr/share/doc/ntp/pic/fg6021.gif OLD_FILES+=usr/share/doc/ntp/pic/fg6039.jpg OLD_FILES+=usr/share/doc/ntp/pic/fig_3_1.gif OLD_FILES+=usr/share/doc/ntp/pic/flatheads.gif OLD_FILES+=usr/share/doc/ntp/pic/flt1.gif OLD_FILES+=usr/share/doc/ntp/pic/flt2.gif OLD_FILES+=usr/share/doc/ntp/pic/flt3.gif OLD_FILES+=usr/share/doc/ntp/pic/flt4.gif OLD_FILES+=usr/share/doc/ntp/pic/flt5.gif OLD_FILES+=usr/share/doc/ntp/pic/flt6.gif OLD_FILES+=usr/share/doc/ntp/pic/flt7.gif OLD_FILES+=usr/share/doc/ntp/pic/flt8.gif OLD_FILES+=usr/share/doc/ntp/pic/flt9.gif OLD_FILES+=usr/share/doc/ntp/pic/freq1211.gif OLD_FILES+=usr/share/doc/ntp/pic/gadget.jpg OLD_FILES+=usr/share/doc/ntp/pic/gps167.jpg OLD_FILES+=usr/share/doc/ntp/pic/group.gif OLD_FILES+=usr/share/doc/ntp/pic/hornraba.gif OLD_FILES+=usr/share/doc/ntp/pic/igclock.gif OLD_FILES+=usr/share/doc/ntp/pic/neoclock4x.gif OLD_FILES+=usr/share/doc/ntp/pic/offset1211.gif OLD_FILES+=usr/share/doc/ntp/pic/oncore_evalbig.gif OLD_FILES+=usr/share/doc/ntp/pic/oncore_remoteant.jpg OLD_FILES+=usr/share/doc/ntp/pic/oncore_utplusbig.gif OLD_FILES+=usr/share/doc/ntp/pic/oz2.gif OLD_FILES+=usr/share/doc/ntp/pic/panda.gif OLD_FILES+=usr/share/doc/ntp/pic/pd_om006.gif OLD_FILES+=usr/share/doc/ntp/pic/pd_om011.gif OLD_FILES+=usr/share/doc/ntp/pic/peer.gif OLD_FILES+=usr/share/doc/ntp/pic/pogo.gif OLD_FILES+=usr/share/doc/ntp/pic/pogo1a.gif OLD_FILES+=usr/share/doc/ntp/pic/pogo3a.gif OLD_FILES+=usr/share/doc/ntp/pic/pogo4.gif OLD_FILES+=usr/share/doc/ntp/pic/pogo5.gif OLD_FILES+=usr/share/doc/ntp/pic/pogo6.gif OLD_FILES+=usr/share/doc/ntp/pic/pogo7.gif OLD_FILES+=usr/share/doc/ntp/pic/pogo8.gif OLD_FILES+=usr/share/doc/ntp/pic/pzf509.jpg OLD_FILES+=usr/share/doc/ntp/pic/pzf511.jpg OLD_FILES+=usr/share/doc/ntp/pic/rabbit.gif OLD_FILES+=usr/share/doc/ntp/pic/radio2.jpg OLD_FILES+=usr/share/doc/ntp/pic/sheepb.jpg OLD_FILES+=usr/share/doc/ntp/pic/stack1a.jpg OLD_FILES+=usr/share/doc/ntp/pic/stats.gif OLD_FILES+=usr/share/doc/ntp/pic/sx5.gif OLD_FILES+=usr/share/doc/ntp/pic/thunderbolt.jpg OLD_FILES+=usr/share/doc/ntp/pic/time1.gif OLD_FILES+=usr/share/doc/ntp/pic/tonea.gif OLD_FILES+=usr/share/doc/ntp/pic/tribeb.gif OLD_FILES+=usr/share/doc/ntp/pic/wingdorothy.gif OLD_FILES+=usr/share/doc/ntp/poll.html OLD_FILES+=usr/share/doc/ntp/porting.html OLD_FILES+=usr/share/doc/ntp/pps.html OLD_FILES+=usr/share/doc/ntp/prefer.html OLD_FILES+=usr/share/doc/ntp/quick.html OLD_FILES+=usr/share/doc/ntp/rate.html OLD_FILES+=usr/share/doc/ntp/rdebug.html OLD_FILES+=usr/share/doc/ntp/refclock.html OLD_FILES+=usr/share/doc/ntp/release.html OLD_FILES+=usr/share/doc/ntp/scripts/accopt.txt OLD_FILES+=usr/share/doc/ntp/scripts/audio.txt OLD_FILES+=usr/share/doc/ntp/scripts/authopt.txt OLD_FILES+=usr/share/doc/ntp/scripts/clockopt.txt OLD_FILES+=usr/share/doc/ntp/scripts/command.txt OLD_FILES+=usr/share/doc/ntp/scripts/config.txt OLD_FILES+=usr/share/doc/ntp/scripts/confopt.txt OLD_FILES+=usr/share/doc/ntp/scripts/external.txt OLD_FILES+=usr/share/doc/ntp/scripts/footer.txt OLD_FILES+=usr/share/doc/ntp/scripts/hand.txt OLD_FILES+=usr/share/doc/ntp/scripts/install.txt OLD_FILES+=usr/share/doc/ntp/scripts/manual.txt OLD_FILES+=usr/share/doc/ntp/scripts/misc.txt OLD_FILES+=usr/share/doc/ntp/scripts/miscopt.txt OLD_FILES+=usr/share/doc/ntp/scripts/monopt.txt OLD_FILES+=usr/share/doc/ntp/scripts/refclock.txt OLD_FILES+=usr/share/doc/ntp/scripts/special.txt OLD_FILES+=usr/share/doc/ntp/scripts/style.css OLD_FILES+=usr/share/doc/ntp/select.html OLD_FILES+=usr/share/doc/ntp/sitemap.html OLD_FILES+=usr/share/doc/ntp/sntp.html OLD_FILES+=usr/share/doc/ntp/stats.html OLD_FILES+=usr/share/doc/ntp/tickadj.html OLD_FILES+=usr/share/doc/ntp/warp.html OLD_FILES+=usr/share/doc/ntp/xleave.html OLD_DIRS+=usr/share/doc/ntp/drivers OLD_DIRS+=usr/share/doc/ntp/drivers/scripts OLD_DIRS+=usr/share/doc/ntp/drivers/icons OLD_DIRS+=usr/share/doc/ntp/hints OLD_DIRS+=usr/share/doc/ntp/icons OLD_DIRS+=usr/share/doc/ntp/pic OLD_DIRS+=usr/share/doc/ntp/scripts OLD_DIRS+=usr/share/doc/ntp OLD_FILES+=usr/share/examples/etc/ntp.conf OLD_FILES+=usr/share/man/man1/sntp.1.gz OLD_FILES+=usr/share/man/man5/ntp.conf.5.gz OLD_FILES+=usr/share/man/man5/ntp.keys.5.gz OLD_FILES+=usr/share/man/man8/ntp-keygen.8.gz OLD_FILES+=usr/share/man/man8/ntpd.8.gz OLD_FILES+=usr/share/man/man8/ntpdate.8.gz OLD_FILES+=usr/share/man/man8/ntpdc.8.gz OLD_FILES+=usr/share/man/man8/ntpq.8.gz OLD_FILES+=usr/share/man/man8/ntptime.8.gz .endif .if ${MK_OFED} == no OLD_FILES+=etc/newsyslog.conf.d/opensm.conf OLD_FILES+=etc/rc.d/opensm OLD_FILES+=usr/bin/ibstat OLD_FILES+=usr/bin/ibv_asyncwatch OLD_FILES+=usr/bin/ibv_devices OLD_FILES+=usr/bin/ibv_devinfo OLD_FILES+=usr/bin/ibv_rc_pingpong OLD_FILES+=usr/bin/ibv_srq_pingpong OLD_FILES+=usr/bin/ibv_uc_pingpong OLD_FILES+=usr/bin/ibv_ud_pingpong OLD_FILES+=usr/bin/mckey OLD_FILES+=usr/bin/rping OLD_FILES+=usr/bin/ucmatose OLD_FILES+=usr/bin/udaddy OLD_FILES+=usr/include/infiniband/marshall.h OLD_FILES+=usr/include/infiniband/kern-abi.h OLD_FILES+=usr/include/infiniband/umad_sm.h OLD_FILES+=usr/include/infiniband/umad.h OLD_FILES+=usr/include/infiniband/arch.h OLD_FILES+=usr/include/infiniband/verbs.h OLD_FILES+=usr/include/infiniband/ib.h OLD_FILES+=usr/include/infiniband/cm.h OLD_FILES+=usr/include/infiniband/opcode.h OLD_FILES+=usr/include/infiniband/ibnetdisc.h OLD_FILES+=usr/include/infiniband/driver.h OLD_FILES+=usr/include/infiniband/mad_osd.h OLD_FILES+=usr/include/infiniband/umad_types.h OLD_FILES+=usr/include/infiniband/umad_cm.h OLD_FILES+=usr/include/infiniband/cm_abi.h OLD_FILES+=usr/include/infiniband/sa-kern-abi.h OLD_FILES+=usr/include/infiniband/ibnetdisc_osd.h OLD_FILES+=usr/include/infiniband/opensm/osm_event_plugin.h OLD_FILES+=usr/include/infiniband/opensm/osm_console_io.h OLD_FILES+=usr/include/infiniband/opensm/osm_ucast_cache.h OLD_FILES+=usr/include/infiniband/opensm/osm_port.h OLD_FILES+=usr/include/infiniband/opensm/osm_path.h OLD_FILES+=usr/include/infiniband/opensm/osm_mtree.h OLD_FILES+=usr/include/infiniband/opensm/osm_log.h OLD_FILES+=usr/include/infiniband/opensm/osm_mcm_port.h OLD_FILES+=usr/include/infiniband/opensm/osm_subnet.h OLD_FILES+=usr/include/infiniband/opensm/osm_pkey.h OLD_FILES+=usr/include/infiniband/opensm/osm_remote_sm.h OLD_FILES+=usr/include/infiniband/opensm/osm_qos_policy.h OLD_FILES+=usr/include/infiniband/opensm/osm_sm.h OLD_FILES+=usr/include/infiniband/opensm/osm_node.h OLD_FILES+=usr/include/infiniband/opensm/osm_mcast_mgr.h OLD_FILES+=usr/include/infiniband/opensm/osm_madw.h OLD_FILES+=usr/include/infiniband/opensm/osm_lid_mgr.h OLD_FILES+=usr/include/infiniband/opensm/osm_congestion_control.h OLD_FILES+=usr/include/infiniband/opensm/osm_port_profile.h OLD_FILES+=usr/include/infiniband/opensm/osm_perfmgr.h OLD_FILES+=usr/include/infiniband/opensm/osm_service.h OLD_FILES+=usr/include/infiniband/opensm/osm_base.h OLD_FILES+=usr/include/infiniband/opensm/osm_vl15intf.h OLD_FILES+=usr/include/infiniband/opensm/st.h OLD_FILES+=usr/include/infiniband/opensm/osm_attrib_req.h OLD_FILES+=usr/include/infiniband/opensm/osm_ucast_mgr.h OLD_FILES+=usr/include/infiniband/opensm/osm_db.h OLD_FILES+=usr/include/infiniband/opensm/osm_sa_mad_ctrl.h OLD_FILES+=usr/include/infiniband/opensm/osm_db_pack.h OLD_FILES+=usr/include/infiniband/opensm/osm_opensm.h OLD_FILES+=usr/include/infiniband/opensm/osm_mesh.h OLD_FILES+=usr/include/infiniband/opensm/osm_mcast_tbl.h OLD_FILES+=usr/include/infiniband/opensm/osm_sm_mad_ctrl.h OLD_FILES+=usr/include/infiniband/opensm/osm_stats.h OLD_FILES+=usr/include/infiniband/opensm/osm_mad_pool.h OLD_FILES+=usr/include/infiniband/opensm/osm_switch.h OLD_FILES+=usr/include/infiniband/opensm/osm_ucast_lash.h OLD_FILES+=usr/include/infiniband/opensm/osm_errors.h OLD_FILES+=usr/include/infiniband/opensm/osm_partition.h OLD_FILES+=usr/include/infiniband/opensm/osm_prefix_route.h OLD_FILES+=usr/include/infiniband/opensm/osm_helper.h OLD_FILES+=usr/include/infiniband/opensm/osm_version.h OLD_FILES+=usr/include/infiniband/opensm/osm_sa.h OLD_FILES+=usr/include/infiniband/opensm/osm_config.h OLD_FILES+=usr/include/infiniband/opensm/osm_multicast.h OLD_FILES+=usr/include/infiniband/opensm/osm_file_ids.h OLD_FILES+=usr/include/infiniband/opensm/osm_perfmgr_db.h OLD_FILES+=usr/include/infiniband/opensm/osm_console.h OLD_FILES+=usr/include/infiniband/opensm/osm_msgdef.h OLD_FILES+=usr/include/infiniband/opensm/osm_router.h OLD_FILES+=usr/include/infiniband/opensm/osm_guid.h OLD_FILES+=usr/include/infiniband/opensm/osm_inform.h OLD_DIRS+=usr/include/infiniband/opensm OLD_FILES+=usr/include/infiniband/iba/ib_types.h OLD_FILES+=usr/include/infiniband/iba/ib_cm_types.h OLD_DIRS+=usr/include/infiniband/iba OLD_FILES+=usr/include/infiniband/umad_str.h OLD_FILES+=usr/include/infiniband/udma_barrier.h OLD_FILES+=usr/include/infiniband/umad_sa.h OLD_FILES+=usr/include/infiniband/mad.h OLD_FILES+=usr/include/infiniband/sa.h OLD_FILES+=usr/include/infiniband/byteorder.h OLD_FILES+=usr/include/infiniband/types.h OLD_FILES+=usr/include/infiniband/byteswap.h OLD_FILES+=usr/include/infiniband/vendor/osm_pkt_randomizer.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_rmpp_ctx.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mtl_hca_guid.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_txn.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_svc.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_test.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_inout.h OLD_FILES+=usr/include/infiniband/vendor/osm_mtl_bind.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_hca.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_sa_api.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_sender.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor.h OLD_FILES+=usr/include/infiniband/vendor/osm_umadt.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mtl_transaction_mgr.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_defs.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_dispatcher.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_api.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mtl.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_transport.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_al.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_sar.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_umadt.h OLD_FILES+=usr/include/infiniband/vendor/osm_ts_useraccess.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_ts.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_mlx_transport_anafa.h OLD_FILES+=usr/include/infiniband/vendor/osm_vendor_ibumad.h OLD_DIRS+=usr/include/infiniband/vendor OLD_FILES+=usr/include/infiniband/endian.h OLD_FILES+=usr/include/infiniband/complib/cl_byteswap.h OLD_FILES+=usr/include/infiniband/complib/cl_types.h OLD_FILES+=usr/include/infiniband/complib/cl_map.h OLD_FILES+=usr/include/infiniband/complib/cl_packon.h OLD_FILES+=usr/include/infiniband/complib/cl_timer.h OLD_FILES+=usr/include/infiniband/complib/cl_thread_osd.h OLD_FILES+=usr/include/infiniband/complib/cl_thread.h OLD_FILES+=usr/include/infiniband/complib/cl_event.h OLD_FILES+=usr/include/infiniband/complib/cl_byteswap_osd.h OLD_FILES+=usr/include/infiniband/complib/cl_passivelock.h OLD_FILES+=usr/include/infiniband/complib/cl_vector.h OLD_FILES+=usr/include/infiniband/complib/cl_nodenamemap.h OLD_FILES+=usr/include/infiniband/complib/cl_event_wheel.h OLD_FILES+=usr/include/infiniband/complib/cl_log.h OLD_FILES+=usr/include/infiniband/complib/cl_fleximap.h OLD_FILES+=usr/include/infiniband/complib/cl_qlist.h OLD_FILES+=usr/include/infiniband/complib/cl_timer_osd.h OLD_FILES+=usr/include/infiniband/complib/cl_pool.h OLD_FILES+=usr/include/infiniband/complib/cl_debug.h OLD_FILES+=usr/include/infiniband/complib/cl_types_osd.h OLD_FILES+=usr/include/infiniband/complib/cl_dispatcher.h OLD_FILES+=usr/include/infiniband/complib/cl_ptr_vector.h OLD_FILES+=usr/include/infiniband/complib/cl_atomic_osd.h OLD_FILES+=usr/include/infiniband/complib/cl_qmap.h OLD_FILES+=usr/include/infiniband/complib/cl_spinlock_osd.h OLD_FILES+=usr/include/infiniband/complib/cl_qcomppool.h OLD_FILES+=usr/include/infiniband/complib/cl_threadpool.h OLD_FILES+=usr/include/infiniband/complib/cl_list.h OLD_FILES+=usr/include/infiniband/complib/cl_debug_osd.h OLD_FILES+=usr/include/infiniband/complib/cl_packoff.h OLD_FILES+=usr/include/infiniband/complib/cl_qpool.h OLD_FILES+=usr/include/infiniband/complib/cl_spinlock.h OLD_FILES+=usr/include/infiniband/complib/cl_event_osd.h OLD_FILES+=usr/include/infiniband/complib/cl_atomic.h OLD_FILES+=usr/include/infiniband/complib/cl_math.h OLD_FILES+=usr/include/infiniband/complib/cl_comppool.h OLD_DIRS+=usr/include/infiniband/complib OLD_DIRS+=usr/include/infiniband OLD_FILES+=usr/lib/libcxgb4.a OLD_FILES+=usr/lib/libcxgb4.so OLD_LIBS+=usr/lib/libcxgb4.so.1 OLD_FILES+=usr/lib/libibcm.a OLD_FILES+=usr/lib/libibcm.so OLD_LIBS+=usr/lib/libibcm.so.1 OLD_FILES+=usr/lib/libibmad.a OLD_FILES+=usr/lib/libibmad.so OLD_LIBS+=usr/lib/libibmad.so.5 OLD_FILES+=usr/lib/libibnetdisc.a OLD_FILES+=usr/lib/libibnetdisc.so OLD_LIBS+=usr/lib/libibnetdisc.so.5 OLD_FILES+=usr/lib/libibumad.a OLD_FILES+=usr/lib/libibumad.so OLD_LIBS+=usr/lib/libibumad.so.1 OLD_FILES+=usr/lib/libibverbs.a OLD_FILES+=usr/lib/libibverbs.so OLD_LIBS+=lib/libibverbs.so.1 OLD_FILES+=usr/lib/libmlx4.a OLD_FILES+=usr/lib/libmlx4.so OLD_LIBS+=usr/lib/libmlx4.so.1 OLD_FILES+=usr/lib/libmlx5.a OLD_FILES+=usr/lib/libmlx5.so OLD_LIBS+=lib/libmlx5.so.1 OLD_FILES+=usr/lib/libopensm.a OLD_FILES+=usr/lib/libopensm.so OLD_LIBS+=usr/lib/libopensm.so.5 OLD_FILES+=usr/lib/libosmcomp.a OLD_FILES+=usr/lib/libosmcomp.so OLD_LIBS+=usr/lib/libosmcomp.so.3 OLD_FILES+=usr/lib/libosmvendor.a OLD_FILES+=usr/lib/libosmvendor.so OLD_LIBS+=usr/lib/libosmvendor.so.4 OLD_FILES+=usr/lib/librdmacm.a OLD_FILES+=usr/lib/librdmacm.so OLD_LIBS+=usr/lib/librdmacm.so.1 .if ${TARGET_ARCH} == "amd64" || ${TARGET_ARCH} == "powerpc64" OLD_FILES+=usr/lib32/libcxgb4.a OLD_FILES+=usr/lib32/libcxgb4.so OLD_LIBS+=usr/lib32/libcxgb4.so.1 OLD_FILES+=usr/lib32/libibcm.a OLD_FILES+=usr/lib32/libibcm.so OLD_LIBS+=usr/lib32/libibcm.so.1 OLD_FILES+=usr/lib32/libibmad.a OLD_FILES+=usr/lib32/libibmad.so OLD_LIBS+=usr/lib32/libibmad.so.5 OLD_FILES+=usr/lib32/libibnetdisc.a OLD_FILES+=usr/lib32/libibnetdisc.so OLD_LIBS+=usr/lib32/libibnetdisc.so.5 OLD_FILES+=usr/lib32/libibumad.a OLD_FILES+=usr/lib32/libibumad.so OLD_LIBS+=usr/lib32/libibumad.so.1 OLD_FILES+=usr/lib32/libibverbs.a OLD_FILES+=usr/lib32/libibverbs.so OLD_LIBS+=usr/lib32/libibverbs.so.1 OLD_FILES+=usr/lib32/libmlx4.a OLD_FILES+=usr/lib32/libmlx4.so OLD_LIBS+=usr/lib32/libmlx4.so.1 OLD_FILES+=usr/lib32/libmlx5.a OLD_FILES+=usr/lib32/libmlx5.so OLD_LIBS+=usr/lib32/libmlx5.so.1 OLD_FILES+=usr/lib32/libopensm.a OLD_FILES+=usr/lib32/libopensm.so OLD_LIBS+=usr/lib32/libopensm.so.5 OLD_FILES+=usr/lib32/libosmcomp.a OLD_FILES+=usr/lib32/libosmcomp.so OLD_LIBS+=usr/lib32/libosmcomp.so.3 OLD_FILES+=usr/lib32/libosmvendor.a OLD_FILES+=usr/lib32/libosmvendor.so OLD_LIBS+=usr/lib32/libosmvendor.so.4 OLD_FILES+=usr/lib32/librdmacm.a OLD_FILES+=usr/lib32/librdmacm.so OLD_LIBS+=usr/lib32/librdmacm.so.1 .endif OLD_FILES+=usr/share/man/man1/ibv_asyncwatch.1.gz OLD_FILES+=usr/share/man/man1/ibv_devices.1.gz OLD_FILES+=usr/share/man/man1/ibv_devinfo.1.gz OLD_FILES+=usr/share/man/man1/ibv_rc_pingpong.1.gz OLD_FILES+=usr/share/man/man1/ibv_srq_pingpong.1.gz OLD_FILES+=usr/share/man/man1/ibv_uc_pingpong.1.gz OLD_FILES+=usr/share/man/man1/ibv_ud_pingpong.1.gz OLD_FILES+=usr/share/man/man1/mckey.1.gz OLD_FILES+=usr/share/man/man1/rping.1.gz OLD_FILES+=usr/share/man/man1/ucmatose.1.gz OLD_FILES+=usr/share/man/man1/udaddy.1.gz OLD_FILES+=usr/share/man/man3/ibnd_debug.3.gz OLD_FILES+=usr/share/man/man3/ibnd_destroy_fabric.3.gz OLD_FILES+=usr/share/man/man3/ibnd_discover_fabric.3.gz OLD_FILES+=usr/share/man/man3/ibnd_find_node_dr.3.gz OLD_FILES+=usr/share/man/man3/ibnd_find_node_guid.3.gz OLD_FILES+=usr/share/man/man3/ibnd_iter_nodes.3.gz OLD_FILES+=usr/share/man/man3/ibnd_iter_nodes_type.3.gz OLD_FILES+=usr/share/man/man3/ibnd_show_progress.3.gz OLD_FILES+=usr/share/man/man3/ibv_alloc_mw.3.gz OLD_FILES+=usr/share/man/man3/ibv_alloc_pd.3.gz OLD_FILES+=usr/share/man/man3/ibv_attach_mcast.3.gz OLD_FILES+=usr/share/man/man3/ibv_bind_mw.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_ah.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_ah_from_wc.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_comp_channel.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_cq.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_cq_ex.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_flow.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_qp.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_qp_ex.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_rwq_ind_table.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_srq.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_srq_ex.3.gz OLD_FILES+=usr/share/man/man3/ibv_create_wq.3.gz OLD_FILES+=usr/share/man/man3/ibv_event_type_str.3.gz OLD_FILES+=usr/share/man/man3/ibv_fork_init.3.gz OLD_FILES+=usr/share/man/man3/ibv_get_async_event.3.gz OLD_FILES+=usr/share/man/man3/ibv_get_cq_event.3.gz OLD_FILES+=usr/share/man/man3/ibv_get_device_guid.3.gz OLD_FILES+=usr/share/man/man3/ibv_get_device_list.3.gz OLD_FILES+=usr/share/man/man3/ibv_get_device_name.3.gz OLD_FILES+=usr/share/man/man3/ibv_get_srq_num.3.gz OLD_FILES+=usr/share/man/man3/ibv_inc_rkey.3.gz OLD_FILES+=usr/share/man/man3/ibv_modify_qp.3.gz OLD_FILES+=usr/share/man/man3/ibv_modify_srq.3.gz OLD_FILES+=usr/share/man/man3/ibv_modify_wq.3.gz OLD_FILES+=usr/share/man/man3/ibv_open_device.3.gz OLD_FILES+=usr/share/man/man3/ibv_open_qp.3.gz OLD_FILES+=usr/share/man/man3/ibv_open_xrcd.3.gz OLD_FILES+=usr/share/man/man3/ibv_poll_cq.3.gz OLD_FILES+=usr/share/man/man3/ibv_post_recv.3.gz OLD_FILES+=usr/share/man/man3/ibv_post_send.3.gz OLD_FILES+=usr/share/man/man3/ibv_post_srq_recv.3.gz OLD_FILES+=usr/share/man/man3/ibv_query_device.3.gz OLD_FILES+=usr/share/man/man3/ibv_query_device_ex.3.gz OLD_FILES+=usr/share/man/man3/ibv_query_gid.3.gz OLD_FILES+=usr/share/man/man3/ibv_query_pkey.3.gz OLD_FILES+=usr/share/man/man3/ibv_query_port.3.gz OLD_FILES+=usr/share/man/man3/ibv_query_qp.3.gz OLD_FILES+=usr/share/man/man3/ibv_query_rt_values_ex.3.gz OLD_FILES+=usr/share/man/man3/ibv_query_srq.3.gz OLD_FILES+=usr/share/man/man3/ibv_rate_to_mbps.3.gz OLD_FILES+=usr/share/man/man3/ibv_rate_to_mult.3.gz OLD_FILES+=usr/share/man/man3/ibv_reg_mr.3.gz OLD_FILES+=usr/share/man/man3/ibv_req_notify_cq.3.gz OLD_FILES+=usr/share/man/man3/ibv_rereg_mr.3.gz OLD_FILES+=usr/share/man/man3/ibv_resize_cq.3.gz OLD_FILES+=usr/share/man/man3/rdma_accept.3.gz OLD_FILES+=usr/share/man/man3/rdma_ack_cm_event.3.gz OLD_FILES+=usr/share/man/man3/rdma_bind_addr.3.gz OLD_FILES+=usr/share/man/man3/rdma_connect.3.gz OLD_FILES+=usr/share/man/man3/rdma_create_ep.3.gz OLD_FILES+=usr/share/man/man3/rdma_create_event_channel.3.gz OLD_FILES+=usr/share/man/man3/rdma_create_id.3.gz OLD_FILES+=usr/share/man/man3/rdma_create_qp.3.gz OLD_FILES+=usr/share/man/man3/rdma_create_srq.3.gz OLD_FILES+=usr/share/man/man3/rdma_dereg_mr.3.gz OLD_FILES+=usr/share/man/man3/rdma_destroy_ep.3.gz OLD_FILES+=usr/share/man/man3/rdma_destroy_event_channel.3.gz OLD_FILES+=usr/share/man/man3/rdma_destroy_id.3.gz OLD_FILES+=usr/share/man/man3/rdma_destroy_qp.3.gz OLD_FILES+=usr/share/man/man3/rdma_destroy_srq.3.gz OLD_FILES+=usr/share/man/man3/rdma_disconnect.3.gz OLD_FILES+=usr/share/man/man3/rdma_event_str.3.gz OLD_FILES+=usr/share/man/man3/rdma_free_devices.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_cm_event.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_devices.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_dst_port.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_local_addr.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_peer_addr.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_recv_comp.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_request.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_send_comp.3.gz OLD_FILES+=usr/share/man/man3/rdma_get_src_port.3.gz OLD_FILES+=usr/share/man/man3/rdma_getaddrinfo.3.gz OLD_FILES+=usr/share/man/man3/rdma_join_multicast.3.gz OLD_FILES+=usr/share/man/man3/rdma_leave_multicast.3.gz OLD_FILES+=usr/share/man/man3/rdma_listen.3.gz OLD_FILES+=usr/share/man/man3/rdma_migrate_id.3.gz OLD_FILES+=usr/share/man/man3/rdma_notify.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_read.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_readv.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_recv.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_recvv.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_send.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_sendv.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_ud_send.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_write.3.gz OLD_FILES+=usr/share/man/man3/rdma_post_writev.3.gz OLD_FILES+=usr/share/man/man3/rdma_reg_msgs.3.gz OLD_FILES+=usr/share/man/man3/rdma_reg_read.3.gz OLD_FILES+=usr/share/man/man3/rdma_reg_write.3.gz OLD_FILES+=usr/share/man/man3/rdma_reject.3.gz OLD_FILES+=usr/share/man/man3/rdma_resolve_addr.3.gz OLD_FILES+=usr/share/man/man3/rdma_resolve_route.3.gz OLD_FILES+=usr/share/man/man3/rdma_set_option.3.gz OLD_FILES+=usr/share/man/man4/mlx4ib.4.gz OLD_FILES+=usr/share/man/man4/mlx5ib.4.gz OLD_FILES+=usr/share/man/man8/ibstat.8.gz .endif .if ${MK_OFED_EXTRA} == no OLD_FILES+=usr/bin/dump_fts OLD_FILES+=usr/bin/ibaddr OLD_FILES+=usr/bin/ibcacheedit OLD_FILES+=usr/bin/ibccconfig OLD_FILES+=usr/bin/ibccquery OLD_FILES+=usr/bin/iblinkinfo OLD_FILES+=usr/bin/ibmirror OLD_FILES+=usr/bin/ibnetdiscover OLD_FILES+=usr/bin/ibping OLD_FILES+=usr/bin/ibportstate OLD_FILES+=usr/bin/ibqueryerrors OLD_FILES+=usr/bin/ibroute OLD_FILES+=usr/bin/ibsysstat OLD_FILES+=usr/bin/ibtracert OLD_FILES+=usr/bin/opensm OLD_FILES+=usr/bin/perfquery OLD_FILES+=usr/bin/saquery OLD_FILES+=usr/bin/sminfo OLD_FILES+=usr/bin/smpdump OLD_FILES+=usr/bin/smpquery OLD_FILES+=usr/bin/vendstat OLD_FILES+=usr/share/man/man8/dump_fts.8.gz OLD_FILES+=usr/share/man/man8/ibaddr.8.gz OLD_FILES+=usr/share/man/man8/ibcacheedit.8.gz OLD_FILES+=usr/share/man/man8/ibccconfig.8.gz OLD_FILES+=usr/share/man/man8/ibccquery.8.gz OLD_FILES+=usr/share/man/man8/iblinkinfo.8.gz OLD_FILES+=usr/share/man/man8/ibnetdiscover.8.gz OLD_FILES+=usr/share/man/man8/ibping.8.gz OLD_FILES+=usr/share/man/man8/ibportstate.8.gz OLD_FILES+=usr/share/man/man8/ibqueryerrors.8.gz OLD_FILES+=usr/share/man/man8/ibroute.8.gz OLD_FILES+=usr/share/man/man8/ibsysstat.8.gz OLD_FILES+=usr/share/man/man8/ibtracert.8.gz OLD_FILES+=usr/share/man/man8/opensm.8.gz OLD_FILES+=usr/share/man/man8/perfquery.8.gz OLD_FILES+=usr/share/man/man8/saquery.8.gz OLD_FILES+=usr/share/man/man8/sminfo.8.gz OLD_FILES+=usr/share/man/man8/smpdump.8.gz OLD_FILES+=usr/share/man/man8/smpquery.8.gz OLD_FILES+=usr/share/man/man8/vendstat.8.gz .endif .if ${MK_OPENMP} == no OLD_FILES+=usr/include/omp.h OLD_LIBS+=usr/lib/libgomp.so OLD_LIBS+=usr/lib32/libgomp.so 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_DIRS+=etc/ssh OLD_FILES+=usr/bin/scp OLD_FILES+=usr/bin/sftp OLD_FILES+=usr/bin/slogin OLD_FILES+=usr/bin/ssh OLD_FILES+=usr/bin/ssh-add OLD_FILES+=usr/bin/ssh-agent OLD_FILES+=usr/bin/ssh-copy-id OLD_FILES+=usr/bin/ssh-keygen OLD_FILES+=usr/bin/ssh-keyscan OLD_FILES+=usr/lib/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_PF} == no OLD_FILES+=etc/newsyslog.conf.d/pf.conf OLD_FILES+=etc/periodic/security/520.pfdenied OLD_FILES+=etc/pf.os OLD_FILES+=etc/rc.d/ftp-proxy OLD_FILES+=sbin/pfctl OLD_FILES+=sbin/pflogd OLD_FILES+=usr/include/netpfil/pf/pf.h OLD_FILES+=usr/include/netpfil/pf/pf_altq.h OLD_FILES+=usr/include/netpfil/pf/pf_mtag.h OLD_FILES+=usr/lib/snmp_pf.so OLD_LIBS+=usr/lib/snmp_pf.so.6 OLD_FILES+=usr/libexec/tftp-proxy OLD_FILES+=usr/sbin/ftp-proxy OLD_FILES+=usr/share/examples/etc/pf.os OLD_FILES+=usr/share/examples/pf/ackpri OLD_FILES+=usr/share/examples/pf/faq-example1 OLD_FILES+=usr/share/examples/pf/faq-example2 OLD_FILES+=usr/share/examples/pf/faq-example3 OLD_FILES+=usr/share/examples/pf/pf.conf OLD_FILES+=usr/share/examples/pf/queue1 OLD_FILES+=usr/share/examples/pf/queue2 OLD_FILES+=usr/share/examples/pf/queue3 OLD_FILES+=usr/share/examples/pf/queue4 OLD_FILES+=usr/share/examples/pf/spamd OLD_DIRS+=usr/share/examples/pf OLD_FILES+=usr/share/man/man4/pf.4.gz OLD_FILES+=usr/share/man/man4/pflog.4.gz OLD_FILES+=usr/share/man/man4/pfsync.4.gz OLD_FILES+=usr/share/man/man5/pf.conf.5.gz OLD_FILES+=usr/share/man/man5/pf.os.5.gz OLD_FILES+=usr/share/man/man8/ftp-proxy.8.gz OLD_FILES+=usr/share/man/man8/pfctl.8.gz OLD_FILES+=usr/share/man/man8/pflogd.8.gz OLD_FILES+=usr/share/man/man8/tftp-proxy.8.gz OLD_FILES+=usr/share/snmp/defs/pf_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-PF-MIB.txt .endif .if ${MK_PKGBOOTSTRAP} == no OLD_FILES+=usr/sbin/pkg OLD_FILES+=usr/share/man/man7/pkg.7.gz .endif .if ${MK_PMC} == no OLD_FILES+=usr/bin/pmcstudy .if ${TARGET_ARCH} == "amd64" OLD_FILES+=usr/include/libipt/pt_last_ip.h OLD_FILES+=usr/include/libipt/intel-pt.h OLD_FILES+=usr/include/libipt/pt_time.h OLD_FILES+=usr/include/libipt/pt_cpu.h OLD_FILES+=usr/include/libipt/pt_compiler.h OLD_DIRS+=usr/include/libipt .endif .if ${TARGET_ARCH} == "aarch64" OLD_FILES+=usr/include/opencsd/c_api/opencsd_c_api.h OLD_FILES+=usr/include/opencsd/c_api/ocsd_c_api_cust_impl.h OLD_FILES+=usr/include/opencsd/c_api/ocsd_c_api_types.h OLD_FILES+=usr/include/opencsd/c_api/ocsd_c_api_cust_fact.h OLD_FILES+=usr/include/opencsd/c_api/ocsd_c_api_custom.h OLD_DIRS+=usr/include/opencsd/c_api OLD_FILES+=usr/include/opencsd/ocsd_if_types.h OLD_FILES+=usr/include/opencsd/ptm/trc_dcd_mngr_ptm.h OLD_FILES+=usr/include/opencsd/ptm/trc_pkt_proc_ptm.h OLD_FILES+=usr/include/opencsd/ptm/trc_cmp_cfg_ptm.h OLD_FILES+=usr/include/opencsd/ptm/ptm_decoder.h OLD_FILES+=usr/include/opencsd/ptm/trc_pkt_elem_ptm.h OLD_FILES+=usr/include/opencsd/ptm/trc_pkt_decode_ptm.h OLD_FILES+=usr/include/opencsd/ptm/trc_pkt_types_ptm.h OLD_DIRS+=usr/include/opencsd/ptm OLD_FILES+=usr/include/opencsd/trc_gen_elem_types.h OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_proc_etmv4.h OLD_FILES+=usr/include/opencsd/etmv4/trc_etmv4_stack_elem.h OLD_FILES+=usr/include/opencsd/etmv4/etmv4_decoder.h OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_elem_etmv4i.h OLD_FILES+=usr/include/opencsd/etmv4/trc_dcd_mngr_etmv4i.h OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_types_etmv4.h OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_elem_etmv4d.h OLD_FILES+=usr/include/opencsd/etmv4/trc_pkt_decode_etmv4i.h OLD_FILES+=usr/include/opencsd/etmv4/trc_cmp_cfg_etmv4.h OLD_DIRS+=usr/include/opencsd/etmv4 OLD_FILES+=usr/include/opencsd/etmv3/trc_pkt_decode_etmv3.h OLD_FILES+=usr/include/opencsd/etmv3/trc_cmp_cfg_etmv3.h OLD_FILES+=usr/include/opencsd/etmv3/etmv3_decoder.h OLD_FILES+=usr/include/opencsd/etmv3/trc_pkt_proc_etmv3.h OLD_FILES+=usr/include/opencsd/etmv3/trc_pkt_elem_etmv3.h OLD_FILES+=usr/include/opencsd/etmv3/trc_pkt_types_etmv3.h OLD_FILES+=usr/include/opencsd/etmv3/trc_dcd_mngr_etmv3.h OLD_DIRS+=usr/include/opencsd/etmv3 OLD_FILES+=usr/include/opencsd/trc_pkt_types.h OLD_FILES+=usr/include/opencsd/stm/trc_pkt_proc_stm.h OLD_FILES+=usr/include/opencsd/stm/trc_pkt_types_stm.h OLD_FILES+=usr/include/opencsd/stm/stm_decoder.h OLD_FILES+=usr/include/opencsd/stm/trc_dcd_mngr_stm.h OLD_FILES+=usr/include/opencsd/stm/trc_cmp_cfg_stm.h OLD_FILES+=usr/include/opencsd/stm/trc_pkt_elem_stm.h OLD_FILES+=usr/include/opencsd/stm/trc_pkt_decode_stm.h OLD_DIRS+=usr/include/opencsd/stm OLD_DIRS+=usr/include/opencsd .endif OLD_FILES+=usr/include/pmc.h OLD_FILES+=usr/include/pmclog.h OLD_FILES+=usr/include/pmcformat.h OLD_FILES+=usr/include/libpmcstat.h .if ${TARGET_ARCH} == "amd64" OLD_FILES+=usr/lib/libipt.a OLD_FILES+=usr/lib/libipt.so OLD_LIBS+=lib/libipt.so.0 OLD_FILES+=usr/lib/libipt_p.a .endif .if ${TARGET_ARCH} == "aarch64" OLD_FILES+=usr/lib/libopencsd.a OLD_FILES+=usr/lib/libopencsd.so OLD_LIBS+=lib/libopencsd.so.0 OLD_FILES+=usr/lib/libopencsd_p.a .endif OLD_FILES+=usr/lib/libpmc.a OLD_FILES+=usr/lib/libpmc.so OLD_LIBS+=usr/lib/libpmc.so.5 OLD_FILES+=usr/lib/libpmc_p.a OLD_FILES+=usr/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/pmc OLD_FILES+=usr/sbin/pmcannotate OLD_FILES+=usr/sbin/pmccontrol OLD_FILES+=usr/sbin/pmcstat OLD_FILES+=usr/share/man/man3/pmc.3.gz OLD_FILES+=usr/share/man/man3/pmc.atom.3.gz OLD_FILES+=usr/share/man/man3/pmc.atomsilvermont.3.gz OLD_FILES+=usr/share/man/man3/pmc.core.3.gz OLD_FILES+=usr/share/man/man3/pmc.core2.3.gz OLD_FILES+=usr/share/man/man3/pmc.corei7.3.gz OLD_FILES+=usr/share/man/man3/pmc.corei7uc.3.gz OLD_FILES+=usr/share/man/man3/pmc.haswell.3.gz OLD_FILES+=usr/share/man/man3/pmc.haswelluc.3.gz OLD_FILES+=usr/share/man/man3/pmc.haswellxeon.3.gz OLD_FILES+=usr/share/man/man3/pmc.iaf.3.gz OLD_FILES+=usr/share/man/man3/pmc.ivybridge.3.gz OLD_FILES+=usr/share/man/man3/pmc.ivybridgexeon.3.gz OLD_FILES+=usr/share/man/man3/pmc.k7.3.gz OLD_FILES+=usr/share/man/man3/pmc.k8.3.gz OLD_FILES+=usr/share/man/man3/pmc.mips24k.3.gz OLD_FILES+=usr/share/man/man3/pmc.octeon.3.gz OLD_FILES+=usr/share/man/man3/pmc.p4.3.gz OLD_FILES+=usr/share/man/man3/pmc.p5.3.gz OLD_FILES+=usr/share/man/man3/pmc.p6.3.gz OLD_FILES+=usr/share/man/man3/pmc.sandybridge.3.gz OLD_FILES+=usr/share/man/man3/pmc.sandybridgeuc.3.gz OLD_FILES+=usr/share/man/man3/pmc.sandybridgexeon.3.gz OLD_FILES+=usr/share/man/man3/pmc.soft.3.gz OLD_FILES+=usr/share/man/man3/pmc.tsc.3.gz OLD_FILES+=usr/share/man/man3/pmc.ucf.3.gz OLD_FILES+=usr/share/man/man3/pmc.westmere.3.gz OLD_FILES+=usr/share/man/man3/pmc.westmereuc.3.gz OLD_FILES+=usr/share/man/man3/pmc.xscale.3.gz OLD_FILES+=usr/share/man/man3/pmc_allocate.3.gz OLD_FILES+=usr/share/man/man3/pmc_attach.3.gz OLD_FILES+=usr/share/man/man3/pmc_capabilities.3.gz OLD_FILES+=usr/share/man/man3/pmc_configure_logfile.3.gz OLD_FILES+=usr/share/man/man3/pmc_cpuinfo.3.gz OLD_FILES+=usr/share/man/man3/pmc_detach.3.gz OLD_FILES+=usr/share/man/man3/pmc_disable.3.gz OLD_FILES+=usr/share/man/man3/pmc_enable.3.gz OLD_FILES+=usr/share/man/man3/pmc_event_names_of_class.3.gz OLD_FILES+=usr/share/man/man3/pmc_flush_logfile.3.gz OLD_FILES+=usr/share/man/man3/pmc_get_driver_stats.3.gz OLD_FILES+=usr/share/man/man3/pmc_get_msr.3.gz OLD_FILES+=usr/share/man/man3/pmc_init.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_capability.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_class.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_cputype.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_disposition.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_event.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_mode.3.gz OLD_FILES+=usr/share/man/man3/pmc_name_of_state.3.gz OLD_FILES+=usr/share/man/man3/pmc_ncpu.3.gz OLD_FILES+=usr/share/man/man3/pmc_npmc.3.gz OLD_FILES+=usr/share/man/man3/pmc_pmcinfo.3.gz OLD_FILES+=usr/share/man/man3/pmc_read.3.gz OLD_FILES+=usr/share/man/man3/pmc_release.3.gz OLD_FILES+=usr/share/man/man3/pmc_rw.3.gz OLD_FILES+=usr/share/man/man3/pmc_set.3.gz OLD_FILES+=usr/share/man/man3/pmc_start.3.gz OLD_FILES+=usr/share/man/man3/pmc_stop.3.gz OLD_FILES+=usr/share/man/man3/pmc_width.3.gz OLD_FILES+=usr/share/man/man3/pmc_write.3.gz OLD_FILES+=usr/share/man/man3/pmc_writelog.3.gz OLD_FILES+=usr/share/man/man3/pmclog.3.gz OLD_FILES+=usr/share/man/man3/pmclog_close.3.gz OLD_FILES+=usr/share/man/man3/pmclog_feed.3.gz OLD_FILES+=usr/share/man/man3/pmclog_open.3.gz OLD_FILES+=usr/share/man/man3/pmclog_read.3.gz OLD_FILES+=usr/share/man/man8/pmcannotate.8.gz OLD_FILES+=usr/share/man/man8/pmccontrol.8.gz OLD_FILES+=usr/share/man/man8/pmcstat.8.gz OLD_FILES+=usr/share/man/man8/pmcstudy.8.gz .endif .if ${MK_PORTSNAP} == no OLD_FILES+=etc/portsnap.conf OLD_FILES+=usr/libexec/make_index OLD_FILES+=usr/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/newsyslog.conf.d/ppp.conf OLD_FILES+=etc/ppp/ppp.conf OLD_FILES+=etc/syslog.d/ppp.conf OLD_DIRS+=etc/ppp OLD_FILES+=usr/sbin/ppp OLD_FILES+=usr/sbin/pppctl OLD_FILES+=usr/share/man/man8/ppp.8.gz OLD_FILES+=usr/share/man/man8/pppctl.8.gz .endif .if ${MK_PROFILE} == no OLD_FILES+=usr/lib/lib80211_p.a OLD_FILES+=usr/lib/libBlocksRuntime_p.a OLD_FILES+=usr/lib/libalias_dummy_p.a OLD_FILES+=usr/lib/libalias_ftp_p.a OLD_FILES+=usr/lib/libalias_irc_p.a OLD_FILES+=usr/lib/libalias_nbt_p.a OLD_FILES+=usr/lib/libalias_p.a OLD_FILES+=usr/lib/libalias_pptp_p.a OLD_FILES+=usr/lib/libalias_skinny_p.a OLD_FILES+=usr/lib/libalias_smedia_p.a OLD_FILES+=usr/lib/libarchive_p.a OLD_FILES+=usr/lib/libasn1_p.a OLD_FILES+=usr/lib/libauditd_p.a OLD_FILES+=usr/lib/libavl_p.a OLD_FILES+=usr/lib/libbe_p.a OLD_FILES+=usr/lib/libbegemot_p.a OLD_FILES+=usr/lib/libblacklist_p.a OLD_FILES+=usr/lib/libbluetooth_p.a OLD_FILES+=usr/lib/libbsdxml_p.a OLD_FILES+=usr/lib/libbsm_p.a OLD_FILES+=usr/lib/libbsnmp_p.a OLD_FILES+=usr/lib/libbz2_p.a OLD_FILES+=usr/lib/libc++_p.a OLD_FILES+=usr/lib/libc_p.a OLD_FILES+=usr/lib/libcalendar_p.a OLD_FILES+=usr/lib/libcam_p.a OLD_FILES+=usr/lib/libcom_err_p.a OLD_FILES+=usr/lib/libcompat_p.a OLD_FILES+=usr/lib/libcompiler_rt_p.a OLD_FILES+=usr/lib/libcrypt_p.a OLD_FILES+=usr/lib/libcrypto_p.a OLD_FILES+=usr/lib/libctf_p.a OLD_FILES+=usr/lib/libcurses_p.a OLD_FILES+=usr/lib/libcursesw_p.a OLD_FILES+=usr/lib/libcuse_p.a OLD_FILES+=usr/lib/libcxxrt_p.a OLD_FILES+=usr/lib/libdevctl_p.a OLD_FILES+=usr/lib/libdevinfo_p.a OLD_FILES+=usr/lib/libdevstat_p.a OLD_FILES+=usr/lib/libdialog_p.a OLD_FILES+=usr/lib/libdl_p.a OLD_FILES+=usr/lib/libdpv_p.a OLD_FILES+=usr/lib/libdtrace_p.a OLD_FILES+=usr/lib/libdwarf_p.a OLD_FILES+=usr/lib/libedit_p.a OLD_FILES+=usr/lib/libefivar_p.a OLD_FILES+=usr/lib/libelf_p.a OLD_FILES+=usr/lib/libexecinfo_p.a OLD_FILES+=usr/lib/libfetch_p.a OLD_FILES+=usr/lib/libfigpar_p.a OLD_FILES+=usr/lib/libfl_p.a OLD_FILES+=usr/lib/libform_p.a OLD_FILES+=usr/lib/libformw_p.a OLD_FILES+=usr/lib/libgcc_eh_p.a OLD_FILES+=usr/lib/libgcc_p.a OLD_FILES+=usr/lib/libgeom_p.a OLD_FILES+=usr/lib/libgnuregex_p.a OLD_FILES+=usr/lib/libgpio_p.a OLD_FILES+=usr/lib/libgssapi_krb5_p.a OLD_FILES+=usr/lib/libgssapi_ntlm_p.a OLD_FILES+=usr/lib/libgssapi_p.a OLD_FILES+=usr/lib/libgssapi_spnego_p.a OLD_FILES+=usr/lib/libhdb_p.a OLD_FILES+=usr/lib/libheimbase_p.a OLD_FILES+=usr/lib/libheimntlm_p.a OLD_FILES+=usr/lib/libheimsqlite_p.a OLD_FILES+=usr/lib/libhistory_p.a OLD_FILES+=usr/lib/libhx509_p.a OLD_FILES+=usr/lib/libipsec_p.a OLD_FILES+=usr/lib/libipt_p.a OLD_FILES+=usr/lib/libjail_p.a OLD_FILES+=usr/lib/libkadm5clnt_p.a OLD_FILES+=usr/lib/libkadm5srv_p.a OLD_FILES+=usr/lib/libkafs5_p.a OLD_FILES+=usr/lib/libkdc_p.a OLD_FILES+=usr/lib/libkiconv_p.a OLD_FILES+=usr/lib/libkrb5_p.a OLD_FILES+=usr/lib/libkvm_p.a OLD_FILES+=usr/lib/libl_p.a OLD_FILES+=usr/lib/libln_p.a OLD_FILES+=usr/lib/liblzma_p.a OLD_FILES+=usr/lib/libm_p.a OLD_FILES+=usr/lib/libmagic_p.a OLD_FILES+=usr/lib/libmd_p.a OLD_FILES+=usr/lib/libmemstat_p.a OLD_FILES+=usr/lib/libmenu_p.a OLD_FILES+=usr/lib/libmenuw_p.a OLD_FILES+=usr/lib/libmilter_p.a OLD_FILES+=usr/lib/libmp_p.a OLD_FILES+=usr/lib/libmt_p.a OLD_FILES+=usr/lib/libncurses_p.a OLD_FILES+=usr/lib/libncursesw_p.a OLD_FILES+=usr/lib/libnetgraph_p.a OLD_FILES+=usr/lib/libngatm_p.a OLD_FILES+=usr/lib/libnv_p.a OLD_FILES+=usr/lib/libnvpair_p.a OLD_FILES+=usr/lib/libopencsd_p.a OLD_FILES+=usr/lib/libopie_p.a OLD_FILES+=usr/lib/libpanel_p.a OLD_FILES+=usr/lib/libpanelw_p.a OLD_FILES+=usr/lib/libpathconv_p.a OLD_FILES+=usr/lib/libpcap_p.a OLD_FILES+=usr/lib/libpjdlog_p.a OLD_FILES+=usr/lib/libpmc_p.a OLD_FILES+=usr/lib/libprivatebsdstat_p.a OLD_FILES+=usr/lib/libprivatedevdctl_p.a OLD_FILES+=usr/lib/libprivateevent_p.a OLD_FILES+=usr/lib/libprivateheimipcc_p.a OLD_FILES+=usr/lib/libprivateheimipcs_p.a OLD_FILES+=usr/lib/libprivateifconfig_p.a OLD_FILES+=usr/lib/libprivateldns_p.a OLD_FILES+=usr/lib/libprivatesqlite3_p.a OLD_FILES+=usr/lib/libprivatessh_p.a OLD_FILES+=usr/lib/libprivateucl_p.a OLD_FILES+=usr/lib/libprivateunbound_p.a OLD_FILES+=usr/lib/libprivatezstd_p.a OLD_FILES+=usr/lib/libproc_p.a OLD_FILES+=usr/lib/libprocstat_p.a OLD_FILES+=usr/lib/libpthread_p.a OLD_FILES+=usr/lib/libradius_p.a OLD_FILES+=usr/lib/libregex_p.a OLD_FILES+=usr/lib/libroken_p.a OLD_FILES+=usr/lib/librpcsvc_p.a OLD_FILES+=usr/lib/librss_p.a OLD_FILES+=usr/lib/librt_p.a OLD_FILES+=usr/lib/librtld_db_p.a OLD_FILES+=usr/lib/libsbuf_p.a OLD_FILES+=usr/lib/libsdp_p.a OLD_FILES+=usr/lib/libsmb_p.a OLD_FILES+=usr/lib/libssl_p.a OLD_FILES+=usr/lib/libstdbuf_p.a OLD_FILES+=usr/lib/libstdc++_p.a OLD_FILES+=usr/lib/libstdthreads_p.a OLD_FILES+=usr/lib/libsupc++_p.a OLD_FILES+=usr/lib/libsysdecode_p.a OLD_FILES+=usr/lib/libtacplus_p.a OLD_FILES+=usr/lib/libtermcap_p.a OLD_FILES+=usr/lib/libtermcapw_p.a OLD_FILES+=usr/lib/libtermlib_p.a OLD_FILES+=usr/lib/libtermlibw_p.a OLD_FILES+=usr/lib/libthr_p.a OLD_FILES+=usr/lib/libthread_db_p.a OLD_FILES+=usr/lib/libtinfo_p.a OLD_FILES+=usr/lib/libtinfow_p.a OLD_FILES+=usr/lib/libufs_p.a OLD_FILES+=usr/lib/libugidfw_p.a OLD_FILES+=usr/lib/libulog_p.a OLD_FILES+=usr/lib/libumem_p.a OLD_FILES+=usr/lib/libusb_p.a OLD_FILES+=usr/lib/libusbhid_p.a OLD_FILES+=usr/lib/libutempter_p.a OLD_FILES+=usr/lib/libutil_p.a OLD_FILES+=usr/lib/libuutil_p.a OLD_FILES+=usr/lib/libvgl_p.a OLD_FILES+=usr/lib/libvmmapi_p.a OLD_FILES+=usr/lib/libwind_p.a OLD_FILES+=usr/lib/libwrap_p.a OLD_FILES+=usr/lib/libxo_p.a OLD_FILES+=usr/lib/liby_p.a OLD_FILES+=usr/lib/libypclnt_p.a OLD_FILES+=usr/lib/libz_p.a OLD_FILES+=usr/lib/libzfs_core_p.a OLD_FILES+=usr/lib/libzfs_p.a OLD_FILES+=usr/lib/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_RESCUE} == no . if exists(${DESTDIR}${TESTSBASE}) RESCUE_DIRS!=find ${DESTDIR}/rescue -type d 2>/dev/null | sed -e 's,^${DESTDIR}/,,'; echo OLD_DIRS+=${RESCUE_DIRS} RESCUE_FILES!=find ${DESTDIR}/rescue \! -type d 2>/dev/null | sed -e 's,^${DESTDIR}/,,'; echo OLD_FILES+=${RESCUE_FILES} . endif .endif .if ${MK_ROUTED} == no OLD_FILES+=etc/rc.d/routed OLD_FILES+=rescue/routed OLD_FILES+=rescue/rtquery OLD_FILES+=sbin/routed OLD_FILES+=sbin/rtquery OLD_FILES+=usr/share/man/man8/routed.8.gz OLD_FILES+=usr/share/man/man8/rtquery.8.gz .endif .if ${MK_SENDMAIL} == no OLD_FILES+=etc/mtree/BSD.sendmail.dist OLD_FILES+=etc/newsyslog.conf.d/sendmail.conf OLD_FILES+=etc/periodic/daily/150.clean-hoststat OLD_FILES+=etc/periodic/daily/440.status-mailq OLD_FILES+=etc/periodic/daily/460.status-mail-rejects OLD_FILES+=etc/periodic/daily/500.queuerun OLD_FILES+=etc/rc.d/sendmail 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 OLD_DIRS+=var/spool/clientmqueue .endif .if ${MK_SERVICESDB} == no OLD_FILES+=var/db/services.db .endif .if ${MK_SHAREDOCS} == no OLD_FILES+=usr/share/doc/pjdfstest/README OLD_DIRS+=usr/share/doc/pjdfstest .endif .if ${MK_SYSCONS} == no OLD_FILES+=usr/share/syscons/fonts/INDEX.fonts OLD_FILES+=usr/share/syscons/fonts/armscii8-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/armscii8-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/armscii8-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp1251-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp1251-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp1251-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp437-thin-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp850-thin-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp865-thin-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp866-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp866-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp866-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/cp866b-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp866c-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp866u-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/cp866u-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/cp866u-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/haik8-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/haik8-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/haik8-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso02-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso02-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso02-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-vga9-wide-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso04-wide-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso05-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso05-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso05-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso07-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso07-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso07-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso08-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso08-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso08-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso09-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso15-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/iso15-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/iso15-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/iso15-thin-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-r-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-rb-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-rc-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/koi8-u-8x8.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-1131-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-1251-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-8x14.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-8x16.fnt OLD_FILES+=usr/share/syscons/fonts/swiss-8x8.fnt OLD_FILES+=usr/share/syscons/keymaps/INDEX.keymaps OLD_FILES+=usr/share/syscons/keymaps/be.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/be.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/bg.bds.ctrlcaps.kbd OLD_FILES+=usr/share/syscons/keymaps/bg.phonetic.ctrlcaps.kbd OLD_FILES+=usr/share/syscons/keymaps/br275.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/br275.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/br275.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/by.cp1131.kbd OLD_FILES+=usr/share/syscons/keymaps/by.cp1251.kbd OLD_FILES+=usr/share/syscons/keymaps/by.iso5.kbd OLD_FILES+=usr/share/syscons/keymaps/ce.iso2.kbd OLD_FILES+=usr/share/syscons/keymaps/colemak.iso15.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/cs.latin2.qwertz.kbd OLD_FILES+=usr/share/syscons/keymaps/cz.iso2.kbd OLD_FILES+=usr/share/syscons/keymaps/danish.cp865.kbd OLD_FILES+=usr/share/syscons/keymaps/danish.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/danish.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/danish.iso.macbook.kbd OLD_FILES+=usr/share/syscons/keymaps/dutch.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/eee_nordic.kbd OLD_FILES+=usr/share/syscons/keymaps/el.iso07.kbd OLD_FILES+=usr/share/syscons/keymaps/estonian.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/estonian.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/estonian.iso15.kbd OLD_FILES+=usr/share/syscons/keymaps/finnish.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/finnish.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.dvorak.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/fr.macbook.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/fr_CA.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/german.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/german.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/german.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/gr.elot.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/gr.us101.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/hr.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/hu.iso2.101keys.kbd OLD_FILES+=usr/share/syscons/keymaps/hu.iso2.102keys.kbd OLD_FILES+=usr/share/syscons/keymaps/hy.armscii-8.kbd OLD_FILES+=usr/share/syscons/keymaps/icelandic.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/icelandic.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/it.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/iw.iso8.kbd OLD_FILES+=usr/share/syscons/keymaps/jp.106.kbd OLD_FILES+=usr/share/syscons/keymaps/jp.106x.kbd OLD_FILES+=usr/share/syscons/keymaps/kk.pt154.io.kbd OLD_FILES+=usr/share/syscons/keymaps/kk.pt154.kst.kbd OLD_FILES+=usr/share/syscons/keymaps/latinamerican.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/latinamerican.kbd OLD_FILES+=usr/share/syscons/keymaps/lt.iso4.kbd OLD_FILES+=usr/share/syscons/keymaps/norwegian.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/norwegian.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/pl_PL.ISO8859-2.kbd OLD_FILES+=usr/share/syscons/keymaps/pl_PL.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/pt.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/pt.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.cp866.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.iso5.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.shift.kbd OLD_FILES+=usr/share/syscons/keymaps/ru.koi8-r.win.kbd OLD_FILES+=usr/share/syscons/keymaps/si.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/sk.iso2.kbd OLD_FILES+=usr/share/syscons/keymaps/spanish.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/spanish.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/spanish.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/spanish.iso15.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/swedish.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/swedish.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/swissfrench.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/swissfrench.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/swissfrench.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/swissgerman.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/swissgerman.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/swissgerman.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/swissgerman.macbook.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/tr.iso9.q.kbd OLD_FILES+=usr/share/syscons/keymaps/ua.iso5.kbd OLD_FILES+=usr/share/syscons/keymaps/ua.koi8-u.kbd OLD_FILES+=usr/share/syscons/keymaps/ua.koi8-u.shift.alt.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.cp850-ctrl.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.cp850.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.iso-ctrl.kbd OLD_FILES+=usr/share/syscons/keymaps/uk.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorak.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorakl.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorakp.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorakr.kbd OLD_FILES+=usr/share/syscons/keymaps/us.dvorakx.kbd OLD_FILES+=usr/share/syscons/keymaps/us.emacs.kbd OLD_FILES+=usr/share/syscons/keymaps/us.iso.acc.kbd OLD_FILES+=usr/share/syscons/keymaps/us.iso.kbd OLD_FILES+=usr/share/syscons/keymaps/us.pc-ctrl.kbd OLD_FILES+=usr/share/syscons/keymaps/us.unix.kbd OLD_FILES+=usr/share/syscons/scrnmaps/armscii8-2haik8.scm OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-1_to_cp437.scm OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-4_for_vga9.scm OLD_FILES+=usr/share/syscons/scrnmaps/iso-8859-7_to_cp437.scm OLD_FILES+=usr/share/syscons/scrnmaps/koi8-r2cp866.scm OLD_FILES+=usr/share/syscons/scrnmaps/koi8-u2cp866u.scm OLD_FILES+=usr/share/syscons/scrnmaps/us-ascii_to_cp437.scm OLD_DIRS+=usr/share/syscons/fonts OLD_DIRS+=usr/share/syscons/scrnmaps OLD_DIRS+=usr/share/syscons/keymaps OLD_DIRS+=usr/share/syscons .endif .if ${MK_TALK} == no OLD_FILES+=usr/bin/talk OLD_FILES+=usr/libexec/ntalkd OLD_FILES+=usr/share/man/man1/talk.1.gz OLD_FILES+=usr/share/man/man8/talkd.8.gz .endif .if ${MK_TCSH} == no OLD_FILES+=.cshrc OLD_FILES+=etc/csh.cshrc OLD_FILES+=etc/csh.login OLD_FILES+=etc/csh.logout OLD_FILES+=bin/csh OLD_FILES+=bin/tcsh OLD_FILES+=rescue/csh OLD_FILES+=rescue/tcsh OLD_FILES+=root/.cshrc OLD_FILES+=root/.login OLD_FILES+=usr/share/examples/etc/csh.cshrc OLD_FILES+=usr/share/examples/etc/csh.login OLD_FILES+=usr/share/examples/etc/csh.logout OLD_FILES+=usr/share/examples/tcsh/complete.tcsh OLD_FILES+=usr/share/examples/tcsh/csh-mode.el OLD_DIRS+=usr/share/examples/tcsh OLD_FILES+=usr/share/man/man1/csh.1.gz OLD_FILES+=usr/share/man/man1/tcsh.1.gz OLD_FILES+=usr/share/nls/de_AT.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_AT.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_AT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/de_DE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/el_GR.ISO8859-7/tcsh.cat OLD_FILES+=usr/share/nls/el_GR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/es_ES.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/et_EE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/et_EE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fi_FI.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_BE.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_CA.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/fr_FR.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/it_CH.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.ISO8859-1/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.ISO8859-15/tcsh.cat OLD_FILES+=usr/share/nls/it_IT.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.SJIS/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/ja_JP.eucJP/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP1251/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.CP866/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.KOI8-R/tcsh.cat OLD_FILES+=usr/share/nls/ru_RU.UTF-8/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.ISO8859-5/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.KOI8-U/tcsh.cat OLD_FILES+=usr/share/nls/uk_UA.UTF-8/tcsh.cat .endif .if ${MK_TELNET} == no OLD_FILES+=etc/pam.d/telnetd OLD_FILES+=usr/bin/telnet OLD_FILES+=usr/libexec/telnetd OLD_FILES+=usr/share/man/man1/telnet.1.gz OLD_FILES+=usr/share/man/man8/telnetd.8.gz .endif .if ${MK_TESTS} == yes OLD_FILES+=usr/bin/atf-sh OLD_FILES+=usr/include/atf-c++/config.hpp OLD_FILES+=usr/include/atf-c/config.h OLD_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/bin/kyua OLD_FILES+=usr/include/atf-c++.hpp OLD_FILES+=usr/include/atf-c++/build.hpp OLD_FILES+=usr/include/atf-c++/check.hpp OLD_FILES+=usr/include/atf-c++/macros.hpp OLD_FILES+=usr/include/atf-c++/tests.hpp OLD_FILES+=usr/include/atf-c++/utils.hpp OLD_FILES+=usr/include/atf-c.h OLD_FILES+=usr/include/atf-c/build.h OLD_FILES+=usr/include/atf-c/check.h OLD_FILES+=usr/include/atf-c/defs.h OLD_FILES+=usr/include/atf-c/error.h OLD_FILES+=usr/include/atf-c/error_fwd.h OLD_FILES+=usr/include/atf-c/macros.h OLD_FILES+=usr/include/atf-c/tc.h OLD_FILES+=usr/include/atf-c/tp.h OLD_FILES+=usr/include/atf-c/utils.h OLD_FILES+=usr/lib/debug/usr/bin/kyua.debug OLD_LIBS+=usr/lib/private/libatf-c++.so.2 OLD_LIBS+=usr/lib/private/libatf-c.so.1 OLD_FILES+=usr/share/examples/kyua/kyua.conf OLD_FILES+=usr/share/examples/kyua/Kyuafile.top OLD_FILES+=usr/share/kyua/misc/context.html OLD_FILES+=usr/share/kyua/misc/index.html OLD_FILES+=usr/share/kyua/misc/report.css OLD_FILES+=usr/share/kyua/misc/test_result.html OLD_FILES+=usr/share/kyua/store/migrate_v1_v2.sql OLD_FILES+=usr/share/kyua/store/migrate_v2_v3.sql OLD_FILES+=usr/share/kyua/store/schema_v3.sql OLD_FILES+=usr/share/man/man1/kyua-about.1.gz OLD_FILES+=usr/share/man/man1/kyua-config.1.gz OLD_FILES+=usr/share/man/man1/kyua-db-exec.1.gz OLD_FILES+=usr/share/man/man1/kyua-db-migrate.1.gz OLD_FILES+=usr/share/man/man1/kyua-debug.1.gz OLD_FILES+=usr/share/man/man1/kyua-help.1.gz OLD_FILES+=usr/share/man/man1/kyua-list.1.gz OLD_FILES+=usr/share/man/man1/kyua-report-html.1.gz OLD_FILES+=usr/share/man/man1/kyua-report-junit.1.gz OLD_FILES+=usr/share/man/man1/kyua-report.1.gz OLD_FILES+=usr/share/man/man1/kyua-test.1.gz OLD_FILES+=usr/share/man/man1/kyua.1.gz OLD_FILES+=usr/share/man/man3/atf-c++.3.gz OLD_FILES+=usr/share/man/man3/atf-c-api++.3.gz OLD_FILES+=usr/share/man/man3/atf-c-api.3.gz OLD_FILES+=usr/share/man/man3/atf-c.3.gz OLD_FILES+=usr/share/man/man5/kyua.conf.5.gz OLD_FILES+=usr/share/man/man5/kyuafile.5.gz OLD_FILES+=usr/tests/lib/atf/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c++/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c++/atf_c++_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/build_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/check_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/application_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/env_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/exceptions_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/fs_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/process_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/text_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/detail/version_helper OLD_FILES+=usr/tests/lib/atf/libatf-c++/macros_hpp_test.cpp OLD_FILES+=usr/tests/lib/atf/libatf-c++/macros_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/tests_test OLD_FILES+=usr/tests/lib/atf/libatf-c++/unused_test.cpp OLD_FILES+=usr/tests/lib/atf/libatf-c++/utils_test OLD_FILES+=usr/tests/lib/atf/libatf-c/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c/atf_c_test OLD_FILES+=usr/tests/lib/atf/libatf-c/build_test OLD_FILES+=usr/tests/lib/atf/libatf-c/check_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/Kyuafile OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/dynstr_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/env_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/fs_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/list_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/map_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/process_helpers OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/process_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/sanity_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/text_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/user_test OLD_FILES+=usr/tests/lib/atf/libatf-c/detail/version_helper OLD_FILES+=usr/tests/lib/atf/libatf-c/error_test OLD_FILES+=usr/tests/lib/atf/libatf-c/macros_h_test.c OLD_FILES+=usr/tests/lib/atf/libatf-c/macros_test OLD_FILES+=usr/tests/lib/atf/libatf-c/tc_test OLD_FILES+=usr/tests/lib/atf/libatf-c/tp_test OLD_FILES+=usr/tests/lib/atf/libatf-c/unused_test.c OLD_FILES+=usr/tests/lib/atf/libatf-c/utils_test OLD_FILES+=usr/tests/lib/atf/test-programs/Kyuafile OLD_FILES+=usr/tests/lib/atf/test-programs/c_helpers OLD_FILES+=usr/tests/lib/atf/test-programs/config_test OLD_FILES+=usr/tests/lib/atf/test-programs/cpp_helpers OLD_FILES+=usr/tests/lib/atf/test-programs/expect_test OLD_FILES+=usr/tests/lib/atf/test-programs/meta_data_test OLD_FILES+=usr/tests/lib/atf/test-programs/result_test OLD_FILES+=usr/tests/lib/atf/test-programs/sh_helpers OLD_FILES+=usr/tests/lib/atf/test-programs/srcdir_test .endif .if ${MK_TEXTPROC} == no OLD_FILES+=usr/bin/checknr OLD_FILES+=usr/bin/colcrt OLD_FILES+=usr/bin/ul OLD_FILES+=usr/share/man/man1/checknr.1.gz OLD_FILES+=usr/share/man/man1/colcrt.1.gz OLD_FILES+=usr/share/man/man1/ul.1.gz .endif .if ${MK_TFTP} == no OLD_FILES+=usr/bin/tftp OLD_FILES+=usr/libexec/tftpd OLD_FILES+=usr/share/man/man1/tftp.1.gz OLD_FILES+=usr/share/man/man8/tftpd.8.gz .endif .if ${MK_TOOLCHAIN} == no OLD_FILES+=usr/bin/addr2line OLD_FILES+=usr/bin/as OLD_FILES+=usr/bin/byacc OLD_FILES+=usr/bin/cc OLD_FILES+=usr/bin/c88 OLD_FILES+=usr/bin/c++ OLD_FILES+=usr/bin/c++filt OLD_FILES+=usr/bin/ld OLD_FILES+=usr/bin/ld.bfd OLD_FILES+=usr/bin/nm OLD_FILES+=usr/bin/objcopy OLD_FILES+=usr/bin/readelf OLD_FILES+=usr/bin/size OLD_FILES+=usr/bin/strip OLD_FILES+=usr/bin/yacc OLD_FILES+=usr/share/man/man1/addr2line.1.gz OLD_FILES+=usr/share/man/man1/c++filt.1.gz OLD_FILES+=usr/share/man/man1/nm.1.gz OLD_FILES+=usr/share/man/man1/readelf.1.gz OLD_FILES+=usr/share/man/man1/size.1.gz OLD_FILES+=usr/share/man/man1/strip.1.gz OLD_FILES+=usr/share/man/man1/objcopy.1.gz # lib/libelf OLD_FILES+=usr/share/man/man3/elf.3.gz OLD_FILES+=usr/share/man/man3/elf_begin.3.gz OLD_FILES+=usr/share/man/man3/elf_cntl.3.gz OLD_FILES+=usr/share/man/man3/elf_end.3.gz OLD_FILES+=usr/share/man/man3/elf_errmsg.3.gz OLD_FILES+=usr/share/man/man3/elf_fill.3.gz OLD_FILES+=usr/share/man/man3/elf_flagdata.3.gz OLD_FILES+=usr/share/man/man3/elf_getarhdr.3.gz OLD_FILES+=usr/share/man/man3/elf_getarsym.3.gz OLD_FILES+=usr/share/man/man3/elf_getbase.3.gz OLD_FILES+=usr/share/man/man3/elf_getdata.3.gz OLD_FILES+=usr/share/man/man3/elf_getident.3.gz OLD_FILES+=usr/share/man/man3/elf_getscn.3.gz OLD_FILES+=usr/share/man/man3/elf_getphdrnum.3.gz OLD_FILES+=usr/share/man/man3/elf_getphnum.3.gz OLD_FILES+=usr/share/man/man3/elf_getshdrnum.3.gz OLD_FILES+=usr/share/man/man3/elf_getshnum.3.gz OLD_FILES+=usr/share/man/man3/elf_getshdrstrndx.3.gz OLD_FILES+=usr/share/man/man3/elf_getshstrndx.3.gz OLD_FILES+=usr/share/man/man3/elf_hash.3.gz OLD_FILES+=usr/share/man/man3/elf_kind.3.gz OLD_FILES+=usr/share/man/man3/elf_memory.3.gz OLD_FILES+=usr/share/man/man3/elf_next.3.gz OLD_FILES+=usr/share/man/man3/elf_open.3.gz OLD_FILES+=usr/share/man/man3/elf_rawfile.3.gz OLD_FILES+=usr/share/man/man3/elf_rand.3.gz OLD_FILES+=usr/share/man/man3/elf_strptr.3.gz OLD_FILES+=usr/share/man/man3/elf_update.3.gz OLD_FILES+=usr/share/man/man3/elf_version.3.gz OLD_FILES+=usr/share/man/man3/gelf.3.gz OLD_FILES+=usr/share/man/man3/gelf_checksum.3.gz OLD_FILES+=usr/share/man/man3/gelf_fsize.3.gz OLD_FILES+=usr/share/man/man3/gelf_getcap.3.gz OLD_FILES+=usr/share/man/man3/gelf_getclass.3.gz OLD_FILES+=usr/share/man/man3/gelf_getdyn.3.gz OLD_FILES+=usr/share/man/man3/gelf_getehdr.3.gz OLD_FILES+=usr/share/man/man3/gelf_getmove.3.gz OLD_FILES+=usr/share/man/man3/gelf_getphdr.3.gz OLD_FILES+=usr/share/man/man3/gelf_getrel.3.gz OLD_FILES+=usr/share/man/man3/gelf_getrela.3.gz OLD_FILES+=usr/share/man/man3/gelf_getshdr.3.gz OLD_FILES+=usr/share/man/man3/gelf_getsym.3.gz OLD_FILES+=usr/share/man/man3/gelf_getsyminfo.3.gz OLD_FILES+=usr/share/man/man3/gelf_getsymshndx.3.gz OLD_FILES+=usr/share/man/man3/gelf_newehdr.3.gz OLD_FILES+=usr/share/man/man3/gelf_newphdr.3.gz OLD_FILES+=usr/share/man/man3/gelf_update_ehdr.3.gz OLD_FILES+=usr/share/man/man3/gelf_xlatetof.3.gz # lib/libelftc OLD_FILES+=usr/share/man/man3/elftc.3.gz OLD_FILES+=usr/share/man/man3/elftc_bfd_find_target.3.gz OLD_FILES+=usr/share/man/man3/elftc_copyfile.3.gz OLD_FILES+=usr/share/man/man3/elftc_demangle.3.gz OLD_FILES+=usr/share/man/man3/elftc_reloc_type_str.3.gz OLD_FILES+=usr/share/man/man3/elftc_set_timestamps.3.gz OLD_FILES+=usr/share/man/man3/elftc_timestamp.3.gz OLD_FILES+=usr/share/man/man3/elftc_string_table_create.3.gz OLD_FILES+=usr/share/man/man3/elftc_version.3.gz OLD_FILES+=usr/tests/usr.bin/yacc/Kyuafile OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_calc1.y OLD_FILES+=usr/tests/usr.bin/yacc/btyacc_demo.y OLD_FILES+=usr/tests/usr.bin/yacc/calc.y OLD_FILES+=usr/tests/usr.bin/yacc/calc1.y OLD_FILES+=usr/tests/usr.bin/yacc/calc2.y OLD_FILES+=usr/tests/usr.bin/yacc/calc3.y OLD_FILES+=usr/tests/usr.bin/yacc/code_calc.y OLD_FILES+=usr/tests/usr.bin/yacc/code_debug.y OLD_FILES+=usr/tests/usr.bin/yacc/code_error.y OLD_FILES+=usr/tests/usr.bin/yacc/empty.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit1.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit2.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit3.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit4.y OLD_FILES+=usr/tests/usr.bin/yacc/err_inherit5.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax1.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax10.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax11.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax12.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax13.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax14.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax15.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax16.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax17.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax18.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax19.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax2.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax20.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax21.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax22.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax23.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax24.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax25.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax26.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax27.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax3.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax4.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax5.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax6.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax7.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax7a.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax7b.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax8.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax8a.y OLD_FILES+=usr/tests/usr.bin/yacc/err_syntax9.y OLD_FILES+=usr/tests/usr.bin/yacc/error.y OLD_FILES+=usr/tests/usr.bin/yacc/grammar.y OLD_FILES+=usr/tests/usr.bin/yacc/inherit0.y OLD_FILES+=usr/tests/usr.bin/yacc/inherit1.y OLD_FILES+=usr/tests/usr.bin/yacc/inherit2.y OLD_FILES+=usr/tests/usr.bin/yacc/ok_syntax1.y OLD_FILES+=usr/tests/usr.bin/yacc/pure_calc.y OLD_FILES+=usr/tests/usr.bin/yacc/pure_error.y OLD_FILES+=usr/tests/usr.bin/yacc/quote_calc.y OLD_FILES+=usr/tests/usr.bin/yacc/quote_calc2.y OLD_FILES+=usr/tests/usr.bin/yacc/quote_calc3.y OLD_FILES+=usr/tests/usr.bin/yacc/quote_calc4.y OLD_FILES+=usr/tests/usr.bin/yacc/run_test OLD_FILES+=usr/tests/usr.bin/yacc/varsyntax_calc1.y OLD_FILES+=usr/tests/usr.bin/yacc/yacc/big_b.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/big_b.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/big_l.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/big_l.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc1.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc1.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc1.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc1.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc2.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc2.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc2.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc2.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc3.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc3.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc3.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/calc3.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.code.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_calc.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.code.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/code_error.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/empty.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/empty.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/empty.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/empty.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax1.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax1.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax1.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax1.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax10.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax10.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax10.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax10.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax11.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax11.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax11.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax11.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax12.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax12.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax12.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax12.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax13.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax13.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax13.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax13.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax14.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax14.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax14.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax14.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax15.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax15.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax15.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax15.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax16.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax16.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax16.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax16.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax17.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax17.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax17.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax17.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax18.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax18.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax18.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax18.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax19.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax19.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax19.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax19.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax2.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax2.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax2.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax2.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax20.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax20.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax20.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax20.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax21.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax21.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax21.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax21.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax22.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax22.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax22.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax22.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax23.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax23.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax23.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax23.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax24.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax24.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax24.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax24.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax25.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax25.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax25.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax25.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax26.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax26.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax26.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax26.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax27.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax27.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax27.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax27.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax3.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax3.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax3.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax3.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax4.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax4.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax4.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax4.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax5.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax5.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax5.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax5.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax6.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax6.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax6.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax6.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7a.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7a.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7a.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7a.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7b.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7b.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7b.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax7b.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8a.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8a.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8a.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax8a.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax9.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax9.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax9.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/err_syntax9.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/error.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/error.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/error.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/error.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.dot OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/grammar.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/help.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/help.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_b_opt.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_b_opt.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_b_opt1.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_b_opt1.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_code_c.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_code_c.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_defines.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_defines.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_graph.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_graph.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_include.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_include.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_opts.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_opts.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output1.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output1.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output2.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_output2.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_p_opt.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_p_opt.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_p_opt1.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_p_opt1.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_verbose.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/no_verbose.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/nostdin.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/nostdin.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/ok_syntax1.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/ok_syntax1.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/ok_syntax1.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/ok_syntax1.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_calc.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_calc.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_calc.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_calc.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_error.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_error.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_error.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/pure_error.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc-s.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc-s.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc-s.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc-s.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2-s.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2-s.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2-s.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2-s.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc2.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3-s.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3-s.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3-s.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3-s.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc3.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4-s.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4-s.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4-s.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4-s.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/quote_calc4.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.i OLD_FILES+=usr/tests/usr.bin/yacc/yacc/rename_debug.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/varsyntax_calc1.error OLD_FILES+=usr/tests/usr.bin/yacc/yacc/varsyntax_calc1.output OLD_FILES+=usr/tests/usr.bin/yacc/yacc/varsyntax_calc1.tab.c OLD_FILES+=usr/tests/usr.bin/yacc/yacc/varsyntax_calc1.tab.h OLD_FILES+=usr/tests/usr.bin/yacc/yacc_tests OLD_DIRS+=usr/tests/usr.bin/yacc .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 OLD_FILES+=usr/share/man/man5/local-unbound.conf.5.gz OLD_FILES+=usr/share/man/man8/local-unbound-anchor.8.gz OLD_FILES+=usr/share/man/man8/local-unbound-checkconf.8.gz OLD_FILES+=usr/share/man/man8/local-unbound-control.8.gz OLD_FILES+=usr/share/man/man8/local-unbound.8.gz .endif OLD_FILES+=usr/sbin/local-unbound-setup OLD_FILES+=usr/sbin/local-unbound OLD_FILES+=usr/sbin/local-unbound-anchor OLD_FILES+=usr/sbin/local-unbound-checkconf OLD_FILES+=usr/sbin/local-unbound-control .endif .if ${MK_USB} == no OLD_FILES+=etc/devd/uath.conf OLD_FILES+=etc/devd/uauth.conf OLD_FILES+=etc/devd/ulpt.conf OLD_FILES+=etc/devd/usb.conf OLD_FILES+=usr/bin/usbhidaction OLD_FILES+=usr/bin/usbhidctl OLD_FILES+=usr/include/libusb.h OLD_FILES+=usr/include/libusb20.h OLD_FILES+=usr/include/libusb20_desc.h OLD_FILES+=usr/include/usb.h OLD_FILES+=usr/include/usbhid.h OLD_FILES+=usr/lib/libusb.a OLD_FILES+=usr/lib/libusb.so OLD_LIBS+=usr/lib/libusb.so.3 OLD_FILES+=usr/lib/libusb_p.a OLD_FILES+=usr/lib/libusbhid.a OLD_FILES+=usr/lib/libusbhid.so OLD_LIBS+=usr/lib/libusbhid.so.4 OLD_FILES+=usr/lib/libusbhid_p.a OLD_FILES+=usr/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/if_rtwn_usb.4.gz OLD_FILES+=usr/share/man/man4/if_rum.4.gz OLD_FILES+=usr/share/man/man4/if_run.4.gz OLD_FILES+=usr/share/man/man4/if_zyd.4.gz OLD_FILES+=usr/share/man/man4/otus.4.gz OLD_FILES+=usr/share/man/man4/otusfw.4.gz OLD_FILES+=usr/share/man/man4/rsu.4.gz OLD_FILES+=usr/share/man/man4/rsufw.4.gz OLD_FILES+=usr/share/man/man4/rtwn_usb.4.gz OLD_FILES+=usr/share/man/man4/rum.4.gz OLD_FILES+=usr/share/man/man4/run.4.gz OLD_FILES+=usr/share/man/man4/runfw.4.gz OLD_FILES+=usr/share/man/man4/u3g.4.gz OLD_FILES+=usr/share/man/man4/u3gstub.4.gz OLD_FILES+=usr/share/man/man4/uark.4.gz OLD_FILES+=usr/share/man/man4/uart.4.gz OLD_FILES+=usr/share/man/man4/uath.4.gz OLD_FILES+=usr/share/man/man4/ubsa.4.gz OLD_FILES+=usr/share/man/man4/ubser.4.gz OLD_FILES+=usr/share/man/man4/ubtbcmfw.4.gz OLD_FILES+=usr/share/man/man4/uchcom.4.gz OLD_FILES+=usr/share/man/man4/ucom.4.gz OLD_FILES+=usr/share/man/man4/ucycom.4.gz OLD_FILES+=usr/share/man/man4/udav.4.gz OLD_FILES+=usr/share/man/man4/udbp.4.gz OLD_FILES+=usr/share/man/man4/uep.4.gz OLD_FILES+=usr/share/man/man4/ufm.4.gz OLD_FILES+=usr/share/man/man4/ufoma.4.gz OLD_FILES+=usr/share/man/man4/uftdi.4.gz OLD_FILES+=usr/share/man/man4/ugen.4.gz OLD_FILES+=usr/share/man/man4/uhci.4.gz OLD_FILES+=usr/share/man/man4/uhid.4.gz OLD_FILES+=usr/share/man/man4/uhso.4.gz OLD_FILES+=usr/share/man/man4/uipaq.4.gz OLD_FILES+=usr/share/man/man4/ukbd.4.gz OLD_FILES+=usr/share/man/man4/uled.4.gz OLD_FILES+=usr/share/man/man4/ulpt.4.gz OLD_FILES+=usr/share/man/man4/umass.4.gz OLD_FILES+=usr/share/man/man4/umcs.4.gz OLD_FILES+=usr/share/man/man4/umct.4.gz OLD_FILES+=usr/share/man/man4/umodem.4.gz OLD_FILES+=usr/share/man/man4/umoscom.4.gz OLD_FILES+=usr/share/man/man4/ums.4.gz OLD_FILES+=usr/share/man/man4/unix.4.gz OLD_FILES+=usr/share/man/man4/upgt.4.gz OLD_FILES+=usr/share/man/man4/uplcom.4.gz OLD_FILES+=usr/share/man/man4/ural.4.gz OLD_FILES+=usr/share/man/man4/urio.4.gz OLD_FILES+=usr/share/man/man4/urndis.4.gz OLD_FILES+=usr/share/man/man4/urtw.4.gz OLD_FILES+=usr/share/man/man4/usb.4.gz OLD_FILES+=usr/share/man/man4/usb_quirk.4.gz OLD_FILES+=usr/share/man/man4/usb_template.4.gz OLD_FILES+=usr/share/man/man4/usfs.4.gz OLD_FILES+=usr/share/man/man4/uslcom.4.gz OLD_FILES+=usr/share/man/man4/uvisor.4.gz OLD_FILES+=usr/share/man/man4/uvscom.4.gz OLD_FILES+=usr/share/man/man4/zyd.4.gz OLD_FILES+=usr/share/man/man8/uathload.8.gz OLD_FILES+=usr/share/man/man8/usbconfig.8.gz OLD_FILES+=usr/share/man/man8/usbdump.8.gz OLD_FILES+=usr/share/man/man9/usb_fifo_alloc_buffer.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_attach.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_detach.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_free_buffer.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_get_data.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_buffer.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_error.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_get_data_linear.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_bytes_max.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_data.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_buffer.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_error.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_put_data_linear.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_reset.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_softc.9.gz OLD_FILES+=usr/share/man/man9/usb_fifo_wakeup.9.gz OLD_FILES+=usr/share/man/man9/usbd_do_request.9.gz OLD_FILES+=usr/share/man/man9/usbd_do_request_flags.9.gz OLD_FILES+=usr/share/man/man9/usbd_errstr.9.gz OLD_FILES+=usr/share/man/man9/usbd_lookup_id_by_info.9.gz OLD_FILES+=usr/share/man/man9/usbd_lookup_id_by_uaa.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_clear_stall.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_drain.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_pending.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_poll.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_setup.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_start.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_stop.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_submit.9.gz OLD_FILES+=usr/share/man/man9/usbd_transfer_unsetup.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_clr_flag.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_frame_data.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_frame_len.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_get_frame.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_get_priv.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_is_stalled.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_max_framelen.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_max_frames.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_max_len.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_flag.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_data.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_len.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frame_offset.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_frames.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_interval.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_priv.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_stall.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_set_timeout.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_softc.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_state.9.gz OLD_FILES+=usr/share/man/man9/usbd_xfer_status.9.gz OLD_FILES+=usr/share/man/man9/usbdi.9.gz OLD_FILES+=usr/share/misc/usb_hid_usages OLD_FILES+=usr/share/misc/usbdevs .endif .if ${MK_UTMPX} == no OLD_FILES+=etc/periodic/monthly/200.accounting OLD_FILES+=etc/rc.d/utx OLD_FILES+=usr/bin/last OLD_FILES+=usr/bin/users OLD_FILES+=usr/bin/who OLD_FILES+=usr/sbin/ac OLD_FILES+=usr/sbin/lastlogin OLD_FILES+=usr/sbin/utx OLD_FILES+=usr/share/man/man1/last.1.gz OLD_FILES+=usr/share/man/man1/users.1.gz OLD_FILES+=usr/share/man/man1/who.1.gz OLD_FILES+=usr/share/man/man8/ac.8.gz OLD_FILES+=usr/share/man/man8/lastlogin.8.gz OLD_FILES+=usr/share/man/man8/utx.8.gz .endif .if ${MK_VI} == no OLD_FILES+=etc/rc.d/virecover OLD_FILES+=rescue/ex OLD_FILES+=rescue/vi OLD_FILES+=usr/bin/ex OLD_FILES+=usr/bin/nex OLD_FILES+=usr/bin/nvi OLD_FILES+=usr/bin/nview OLD_FILES+=usr/bin/vi OLD_FILES+=usr/bin/view OLD_FILES+=usr/share/man/man1/ex.1.gz OLD_FILES+=usr/share/man/man1/nex.1.gz OLD_FILES+=usr/share/man/man1/nvi.1.gz OLD_FILES+=usr/share/man/man1/nview.1.gz OLD_FILES+=usr/share/man/man1/vi.1.gz OLD_FILES+=usr/share/man/man1/view.1.gz . if exists(${DESTDIR}/usr/share/vi) VI_DIRS!=find ${DESTDIR}/usr/share/vi -type d \ | sed -e 's,^${DESTDIR}/,,'; echo VI_FILES!=find ${DESTDIR}/usr/share/vi \! -type d \ | sed -e 's,^${DESTDIR}/,,'; echo OLD_DIRS+=${VI_DIRS} OLD_FILES+=${VI_FILES} . endif .endif .if ${MK_WIRELESS} == no OLD_FILES+=etc/regdomain.xml OLD_FILES+=etc/rc.d/hostapd OLD_FILES+=etc/rc.d/wpa_supplicant OLD_FILES+=usr/sbin/ancontrol OLD_FILES+=usr/sbin/hostapd OLD_FILES+=usr/sbin/hostapd_cli OLD_FILES+=usr/sbin/ndis_events OLD_FILES+=usr/sbin/wlandebug OLD_FILES+=usr/sbin/wpa_cli OLD_FILES+=usr/sbin/wpa_passphrase OLD_FILES+=usr/sbin/wpa_supplicant OLD_FILES+=usr/share/examples/etc/regdomain.xml OLD_FILES+=usr/share/examples/etc/wpa_supplicant.conf OLD_FILES+=usr/share/examples/hostapd/hostapd.conf OLD_FILES+=usr/share/examples/hostapd/hostapd.eap_user OLD_FILES+=usr/share/examples/hostapd/hostapd.wpa_psk OLD_DIRS+=usr/share/examples/hostapd OLD_FILES+=usr/share/man/man5/hostapd.conf.5.gz OLD_FILES+=usr/share/man/man5/wpa_supplicant.conf.5.gz OLD_FILES+=usr/share/man/man8/ancontrol.8.gz OLD_FILES+=usr/share/man/man8/hostapd.8.gz OLD_FILES+=usr/share/man/man8/hostapd_cli.8.gz OLD_FILES+=usr/share/man/man8/ndis_events.8.gz OLD_FILES+=usr/share/man/man8/wlandebug.8.gz OLD_FILES+=usr/share/man/man8/wpa_cli.8.gz OLD_FILES+=usr/share/man/man8/wpa_passphrase.8.gz OLD_FILES+=usr/share/man/man8/wpa_supplicant.8.gz OLD_FILES+=usr/lib/snmp_wlan.so OLD_LIBS+=usr/lib/snmp_wlan.so.6 # bsnmp module OLD_FILES+=usr/share/man/man3/snmp_wlan.3.gz OLD_FILES+=usr/share/snmp/defs/wlan_tree.def OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt .endif .if ${MK_SVNLITE} == no || ${MK_SVN} == yes OLD_FILES+=usr/bin/svnlite OLD_FILES+=usr/bin/svnliteadmin OLD_FILES+=usr/bin/svnlitebench OLD_FILES+=usr/bin/svnlitedumpfilter OLD_FILES+=usr/bin/svnlitefsfs OLD_FILES+=usr/bin/svnlitelook OLD_FILES+=usr/bin/svnlitemucc OLD_FILES+=usr/bin/svnliterdump OLD_FILES+=usr/bin/svnliteserve OLD_FILES+=usr/bin/svnlitesync OLD_FILES+=usr/bin/svnliteversion OLD_FILES+=usr/share/man/man1/svnlite.1.gz .endif .if ${MK_SVN} == no OLD_FILES+=usr/bin/svn OLD_FILES+=usr/bin/svnadmin OLD_FILES+=usr/bin/svnbench OLD_FILES+=usr/bin/svndumpfilter OLD_FILES+=usr/bin/svnfsfs OLD_FILES+=usr/bin/svnlook OLD_FILES+=usr/bin/svnmucc OLD_FILES+=usr/bin/svnrdump OLD_FILES+=usr/bin/svnserve OLD_FILES+=usr/bin/svnsync OLD_FILES+=usr/bin/svnversion .endif .if ${MK_HYPERV} == no OLD_FILES+=etc/devd/hyperv.conf OLD_FILES+=usr/libexec/hyperv/hv_set_ifconfig OLD_FILES+=usr/libexec/hyperv/hv_get_dns_info OLD_FILES+=usr/libexec/hyperv/hv_get_dhcp_info OLD_FILES+=usr/sbin/hv_kvp_daemon OLD_FILES+=usr/sbin/hv_vss_daemon OLD_FILES+=usr/share/man/man8/hv_kvp_daemon.8.gz .endif .if ${MK_ZONEINFO} == no OLD_FILES+=usr/share/zoneinfo/Africa/Abidjan OLD_FILES+=usr/share/zoneinfo/Africa/Accra OLD_FILES+=usr/share/zoneinfo/Africa/Addis_Ababa OLD_FILES+=usr/share/zoneinfo/Africa/Algiers OLD_FILES+=usr/share/zoneinfo/Africa/Asmara OLD_FILES+=usr/share/zoneinfo/Africa/Bamako OLD_FILES+=usr/share/zoneinfo/Africa/Bangui OLD_FILES+=usr/share/zoneinfo/Africa/Banjul OLD_FILES+=usr/share/zoneinfo/Africa/Bissau OLD_FILES+=usr/share/zoneinfo/Africa/Blantyre OLD_FILES+=usr/share/zoneinfo/Africa/Brazzaville OLD_FILES+=usr/share/zoneinfo/Africa/Bujumbura OLD_FILES+=usr/share/zoneinfo/Africa/Cairo OLD_FILES+=usr/share/zoneinfo/Africa/Casablanca OLD_FILES+=usr/share/zoneinfo/Africa/Ceuta OLD_FILES+=usr/share/zoneinfo/Africa/Conakry OLD_FILES+=usr/share/zoneinfo/Africa/Dakar OLD_FILES+=usr/share/zoneinfo/Africa/Dar_es_Salaam OLD_FILES+=usr/share/zoneinfo/Africa/Djibouti OLD_FILES+=usr/share/zoneinfo/Africa/Douala OLD_FILES+=usr/share/zoneinfo/Africa/El_Aaiun OLD_FILES+=usr/share/zoneinfo/Africa/Freetown OLD_FILES+=usr/share/zoneinfo/Africa/Gaborone OLD_FILES+=usr/share/zoneinfo/Africa/Harare OLD_FILES+=usr/share/zoneinfo/Africa/Johannesburg OLD_FILES+=usr/share/zoneinfo/Africa/Juba OLD_FILES+=usr/share/zoneinfo/Africa/Kampala OLD_FILES+=usr/share/zoneinfo/Africa/Khartoum OLD_FILES+=usr/share/zoneinfo/Africa/Kigali OLD_FILES+=usr/share/zoneinfo/Africa/Kinshasa OLD_FILES+=usr/share/zoneinfo/Africa/Lagos OLD_FILES+=usr/share/zoneinfo/Africa/Libreville OLD_FILES+=usr/share/zoneinfo/Africa/Lome OLD_FILES+=usr/share/zoneinfo/Africa/Luanda OLD_FILES+=usr/share/zoneinfo/Africa/Lubumbashi OLD_FILES+=usr/share/zoneinfo/Africa/Lusaka OLD_FILES+=usr/share/zoneinfo/Africa/Malabo OLD_FILES+=usr/share/zoneinfo/Africa/Maputo OLD_FILES+=usr/share/zoneinfo/Africa/Maseru OLD_FILES+=usr/share/zoneinfo/Africa/Mbabane OLD_FILES+=usr/share/zoneinfo/Africa/Mogadishu OLD_FILES+=usr/share/zoneinfo/Africa/Monrovia OLD_FILES+=usr/share/zoneinfo/Africa/Nairobi OLD_FILES+=usr/share/zoneinfo/Africa/Ndjamena OLD_FILES+=usr/share/zoneinfo/Africa/Niamey OLD_FILES+=usr/share/zoneinfo/Africa/Nouakchott OLD_FILES+=usr/share/zoneinfo/Africa/Ouagadougou OLD_FILES+=usr/share/zoneinfo/Africa/Porto-Novo OLD_FILES+=usr/share/zoneinfo/Africa/Sao_Tome OLD_FILES+=usr/share/zoneinfo/Africa/Tripoli OLD_FILES+=usr/share/zoneinfo/Africa/Tunis OLD_FILES+=usr/share/zoneinfo/Africa/Windhoek OLD_FILES+=usr/share/zoneinfo/America/Adak OLD_FILES+=usr/share/zoneinfo/America/Anchorage OLD_FILES+=usr/share/zoneinfo/America/Anguilla OLD_FILES+=usr/share/zoneinfo/America/Antigua OLD_FILES+=usr/share/zoneinfo/America/Araguaina OLD_FILES+=usr/share/zoneinfo/America/Argentina/Buenos_Aires OLD_FILES+=usr/share/zoneinfo/America/Argentina/Catamarca OLD_FILES+=usr/share/zoneinfo/America/Argentina/Cordoba OLD_FILES+=usr/share/zoneinfo/America/Argentina/Jujuy OLD_FILES+=usr/share/zoneinfo/America/Argentina/La_Rioja OLD_FILES+=usr/share/zoneinfo/America/Argentina/Mendoza OLD_FILES+=usr/share/zoneinfo/America/Argentina/Rio_Gallegos OLD_FILES+=usr/share/zoneinfo/America/Argentina/Salta OLD_FILES+=usr/share/zoneinfo/America/Argentina/San_Juan OLD_FILES+=usr/share/zoneinfo/America/Argentina/San_Luis OLD_FILES+=usr/share/zoneinfo/America/Argentina/Tucuman OLD_FILES+=usr/share/zoneinfo/America/Argentina/Ushuaia OLD_FILES+=usr/share/zoneinfo/America/Aruba OLD_FILES+=usr/share/zoneinfo/America/Asuncion OLD_FILES+=usr/share/zoneinfo/America/Atikokan OLD_FILES+=usr/share/zoneinfo/America/Bahia OLD_FILES+=usr/share/zoneinfo/America/Bahia_Banderas OLD_FILES+=usr/share/zoneinfo/America/Barbados OLD_FILES+=usr/share/zoneinfo/America/Belem OLD_FILES+=usr/share/zoneinfo/America/Belize OLD_FILES+=usr/share/zoneinfo/America/Blanc-Sablon OLD_FILES+=usr/share/zoneinfo/America/Boa_Vista OLD_FILES+=usr/share/zoneinfo/America/Bogota OLD_FILES+=usr/share/zoneinfo/America/Boise OLD_FILES+=usr/share/zoneinfo/America/Cambridge_Bay OLD_FILES+=usr/share/zoneinfo/America/Campo_Grande OLD_FILES+=usr/share/zoneinfo/America/Cancun OLD_FILES+=usr/share/zoneinfo/America/Caracas OLD_FILES+=usr/share/zoneinfo/America/Cayenne OLD_FILES+=usr/share/zoneinfo/America/Cayman OLD_FILES+=usr/share/zoneinfo/America/Chicago OLD_FILES+=usr/share/zoneinfo/America/Chihuahua OLD_FILES+=usr/share/zoneinfo/America/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: head/usr.bin/clang/Makefile =================================================================== --- head/usr.bin/clang/Makefile (revision 362718) +++ head/usr.bin/clang/Makefile (revision 362719) @@ -1,62 +1,65 @@ # $FreeBSD$ .include SUBDIR+= clang SUBDIR+= clang-tblgen SUBDIR+= llvm-tblgen .if ${MK_LLDB} != "no" SUBDIR+= lldb-tblgen .endif .if !defined(TOOLS_PREFIX) SUBDIR+= llvm-ar SUBDIR+= llvm-nm SUBDIR+= llvm-objdump SUBDIR+= llvm-symbolizer .if ${MK_CLANG_EXTRAS} != "no" SUBDIR+= bugpoint SUBDIR+= llc SUBDIR+= lli SUBDIR+= llvm-as SUBDIR+= llvm-bcanalyzer SUBDIR+= llvm-cxxdump SUBDIR+= llvm-cxxfilt SUBDIR+= llvm-diff SUBDIR+= llvm-dis SUBDIR+= llvm-dwarfdump +SUBDIR+= llvm-dwp SUBDIR+= llvm-extract SUBDIR+= llvm-link SUBDIR+= llvm-lto SUBDIR+= llvm-lto2 SUBDIR+= llvm-mc SUBDIR+= llvm-mca SUBDIR+= llvm-modextract SUBDIR+= llvm-objcopy SUBDIR+= llvm-pdbutil SUBDIR+= llvm-rtdyld +SUBDIR+= llvm-size +SUBDIR+= llvm-strings SUBDIR+= llvm-xray SUBDIR+= opt .endif .if ${MK_CLANG_EXTRAS} != "no" || ${MK_CLANG_FORMAT} != "no" SUBDIR+= clang-format .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 Index: head/usr.bin/clang/llvm-dwp/Makefile =================================================================== --- head/usr.bin/clang/llvm-dwp/Makefile (nonexistent) +++ head/usr.bin/clang/llvm-dwp/Makefile (revision 362719) @@ -0,0 +1,12 @@ +# $FreeBSD$ + +PROG_CXX= llvm-dwp +MAN= + +SRCDIR= llvm/tools/llvm-dwp +SRCS+= DWPError.cpp +SRCS+= llvm-dwp.cpp + +LIBADD+= z + +.include "../llvm.prog.mk" Property changes on: head/usr.bin/clang/llvm-dwp/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.bin/clang/llvm-size/Makefile =================================================================== --- head/usr.bin/clang/llvm-size/Makefile (nonexistent) +++ head/usr.bin/clang/llvm-size/Makefile (revision 362719) @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PROG_CXX= llvm-size + +SRCDIR= llvm/tools/llvm-size +SRCS+= llvm-size.cpp + +.include "../llvm.prog.mk" Property changes on: head/usr.bin/clang/llvm-size/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.bin/clang/llvm-size/llvm-size.1 =================================================================== --- head/usr.bin/clang/llvm-size/llvm-size.1 (nonexistent) +++ head/usr.bin/clang/llvm-size/llvm-size.1 (revision 362719) @@ -0,0 +1,275 @@ +.\" $FreeBSD$ +.\" Man page generated from reStructuredText. +. +.TH "LLVM-SIZE" "1" "2020-06-26" "10" "LLVM" +.SH NAME +llvm-size \- print size information +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.SH SYNOPSIS +.sp +\fBllvm\-size\fP [\fIoptions\fP] [\fIinput...\fP] +.SH DESCRIPTION +.sp +\fBllvm\-size\fP is a tool that prints size information for binary files. +It is intended to be a drop\-in replacement for GNU\(aqs \fBsize\fP\&. +.sp +The tool prints size information for each \fBinput\fP specified. If no input is +specified, the program prints size information for \fBa.out\fP\&. If "\fB\-\fP" is +specified as an input file, \fBllvm\-size\fP reads a file from the standard +input stream. If an input is an archive, size information will be displayed for +all its members. +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-A +Equivalent to \fI\%\-\-format\fP with a value of \fBsysv\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-arch= +Architecture(s) from Mach\-O universal binaries to display information for. +.UNINDENT +.INDENT 0.0 +.TP +.B \-B +Equivalent to \fI\%\-\-format\fP with a value of \fBberkeley\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-common +Include ELF common symbol sizes in bss size for \fBberkeley\fP output format, or +as a separate section entry for \fBsysv\fP output. If not specified, these +symbols are ignored. +.UNINDENT +.INDENT 0.0 +.TP +.B \-d +Equivalent to \fI\%\-\-radix\fP with a value of \fB10\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-l +Display verbose address and offset information for segments and sections in +Mach\-O files in \fBdarwin\fP format. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-format= +Set the output format to the \fB\fP specified. Available \fB\fP +options are \fBberkeley\fP (the default), \fBsysv\fP and \fBdarwin\fP\&. +.sp +Berkeley output summarises text, data and bss sizes in each file, as shown +below for a typical pair of ELF files: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-format=berkeley test.o test2.o + text data bss dec hex filename + 182 16 5 203 cb test.elf + 82 8 1 91 5b test2.o +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +For Mach\-O files, the output format is slightly different: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-format=berkeley macho.obj macho2.obj +__TEXT __DATA __OBJC others dec hex +4 8 0 0 12 c macho.obj +16 32 0 0 48 30 macho2.obj +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Sysv output displays size and address information for most sections, with each +file being listed separately: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-format=sysv test.elf test2.o + test.elf : + section size addr + .eh_frame 92 2097496 + .text 90 2101248 + .data 16 2105344 + .bss 5 2105360 + .comment 209 0 + Total 412 + + test2.o : + section size addr + .text 26 0 + .data 8 0 + .bss 1 0 + .comment 106 0 + .note.GNU\-stack 0 0 + .eh_frame 56 0 + .llvm_addrsig 2 0 + Total 199 +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +\fBdarwin\fP format only affects Mach\-O input files. If an input of a different +file format is specified, \fBllvm\-size\fP falls back to \fBberkeley\fP +format. When producing \fBdarwin\fP format, the tool displays information about +segments and sections: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-format=darwin macho.obj macho2.obj + macho.obj: + Segment : 12 + Section (__TEXT, __text): 4 + Section (__DATA, __data): 8 + total 12 + total 12 + macho2.obj: + Segment : 48 + Section (__TEXT, __text): 16 + Section (__DATA, __data): 32 + total 48 + total 48 +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-help, \-h +Display a summary of command line options. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-help\-list +Display an uncategorized summary of command line options. +.UNINDENT +.INDENT 0.0 +.TP +.B \-m +Equivalent to \fI\%\-\-format\fP with a value of \fBdarwin\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-o +Equivalent to \fI\%\-\-radix\fP with a value of \fB8\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-radix= +Display size information in the specified radix. Permitted values are \fB8\fP, +\fB10\fP (the default) and \fB16\fP for octal, decimal and hexadecimal output +respectively. +.sp +Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-radix=8 test.o + text data bss oct hex filename + 0152 04 04 162 72 test.o + +$ llvm\-size \-\-radix=10 test.o + text data bss dec hex filename + 106 4 4 114 72 test.o + +$ llvm\-size \-\-radix=16 test.o + text data bss dec hex filename + 0x6a 0x4 0x4 114 72 test.o +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-totals, \-t +Applies only to \fBberkeley\fP output format. Display the totals for all listed +fields, in addition to the individual file listings. +.sp +Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-size \-\-totals test.elf test2.o + text data bss dec hex filename + 182 16 5 203 cb test.elf + 82 8 1 91 5b test2.o + 264 24 6 294 126 (TOTALS) +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-version +Display the version of the \fBllvm\-size\fP executable. +.UNINDENT +.INDENT 0.0 +.TP +.B \-x +Equivalent to \fI\%\-\-radix\fP with a value of \fB16\fP\&. +.UNINDENT +.INDENT 0.0 +.TP +.B @ +Read command\-line options from response file \fB\fP\&. +.UNINDENT +.SH EXIT STATUS +.sp +\fBllvm\-size\fP exits with a non\-zero exit code if there is an error. +Otherwise, it exits with code 0. +.SH BUGS +.sp +To report bugs, please visit <\fI\%http://llvm.org/bugs/\fP>. +.SH AUTHOR +Maintained by the LLVM Team (https://llvm.org/). +.SH COPYRIGHT +2003-2020, LLVM Project +.\" Generated by docutils manpage writer. +. Property changes on: head/usr.bin/clang/llvm-size/llvm-size.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.bin/clang/llvm-strings/Makefile =================================================================== --- head/usr.bin/clang/llvm-strings/Makefile (nonexistent) +++ head/usr.bin/clang/llvm-strings/Makefile (revision 362719) @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG_CXX= llvm-strings +MAN= + +SRCDIR= llvm/tools/llvm-strings +SRCS+= llvm-strings.cpp + +.include "../llvm.prog.mk" Property changes on: head/usr.bin/clang/llvm-strings/Makefile ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.bin/clang/llvm-strings/llvm-strings.1 =================================================================== --- head/usr.bin/clang/llvm-strings/llvm-strings.1 (nonexistent) +++ head/usr.bin/clang/llvm-strings/llvm-strings.1 (revision 362719) @@ -0,0 +1,179 @@ +.\" $FreeBSD$ +.\" Man page generated from reStructuredText. +. +.TH "LLVM-STRINGS" "1" "2020-06-26" "10" "LLVM" +.SH NAME +llvm-strings \- print strings +. +.nr rst2man-indent-level 0 +. +.de1 rstReportMargin +\\$1 \\n[an-margin] +level \\n[rst2man-indent-level] +level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] +- +\\n[rst2man-indent0] +\\n[rst2man-indent1] +\\n[rst2man-indent2] +.. +.de1 INDENT +.\" .rstReportMargin pre: +. RS \\$1 +. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] +. nr rst2man-indent-level +1 +.\" .rstReportMargin post: +.. +.de UNINDENT +. RE +.\" indent \\n[an-margin] +.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] +.nr rst2man-indent-level -1 +.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] +.in \\n[rst2man-indent\\n[rst2man-indent-level]]u +.. +.SH SYNOPSIS +.sp +\fBllvm\-strings\fP [\fIoptions\fP] [\fIinput...\fP] +.SH DESCRIPTION +.sp +\fBllvm\-strings\fP is a tool intended as a drop\-in replacement for GNU\(aqs +\fBstrings\fP, which looks for printable strings in files and writes them +to the standard output stream. A printable string is any sequence of four (by +default) or more printable ASCII characters. The end of the file, or any other +byte, terminates the current sequence. +.sp +\fBllvm\-strings\fP looks for strings in each \fBinput\fP file specified. +Unlike GNU \fBstrings\fP it looks in the entire input file, regardless of +file format, rather than restricting the search to certain sections of object +files. If "\fB\-\fP" is specified as an \fBinput\fP, or no \fBinput\fP is specified, +the program reads from the standard input stream. +.SH EXAMPLE +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ cat input.txt +bars +foo +wibble blob +$ llvm\-strings input.txt +bars +wibble blob +.ft P +.fi +.UNINDENT +.UNINDENT +.SH OPTIONS +.INDENT 0.0 +.TP +.B \-\-all, \-a +Silently ignored. Present for GNU \fBstrings\fP compatibility. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-bytes=, \-n +Set the minimum number of printable ASCII characters required for a sequence of +bytes to be considered a string. The default value is 4. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-help, \-h +Display a summary of command line options. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-help\-list +Display an uncategorized summary of command line options. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-print\-file\-name, \-f +Display the name of the containing file before each string. +.sp +Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-strings \-\-print\-file\-name test.o test.elf +test.o: _Z5hellov +test.o: some_bss +test.o: test.cpp +test.o: main +test.elf: test.cpp +test.elf: test2.cpp +test.elf: _Z5hellov +test.elf: main +test.elf: some_bss +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-radix=, \-t +Display the offset within the file of each string, before the string and using +the specified radix. Valid \fB\fP values are \fBo\fP, \fBd\fP and \fBx\fP for +octal, decimal and hexadecimal respectively. +.sp +Example: +.INDENT 7.0 +.INDENT 3.5 +.sp +.nf +.ft C +$ llvm\-strings \-\-radix=o test.o + 1054 _Z5hellov + 1066 .rela.text + 1101 .comment + 1112 some_bss + 1123 .bss + 1130 test.cpp + 1141 main +$ llvm\-strings \-\-radix=d test.o + 556 _Z5hellov + 566 .rela.text + 577 .comment + 586 some_bss + 595 .bss + 600 test.cpp + 609 main +$ llvm\-strings \-t x test.o + 22c _Z5hellov + 236 .rela.text + 241 .comment + 24a some_bss + 253 .bss + 258 test.cpp + 261 main +.ft P +.fi +.UNINDENT +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-version +Display the version of the \fBllvm\-strings\fP executable. +.UNINDENT +.INDENT 0.0 +.TP +.B @ +Read command\-line options from response file \fB\fP\&. +.UNINDENT +.SH EXIT STATUS +.sp +\fBllvm\-strings\fP exits with a non\-zero exit code if there is an error. +Otherwise, it exits with code 0. +.SH BUGS +.sp +To report bugs, please visit <\fI\%http://llvm.org/bugs/\fP>. +.SH AUTHOR +Maintained by the LLVM Team (https://llvm.org/). +.SH COPYRIGHT +2003-2020, LLVM Project +.\" Generated by docutils manpage writer. +. Property changes on: head/usr.bin/clang/llvm-strings/llvm-strings.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property