aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm16/include/llvm/Support
diff options
context:
space:
mode:
authorvitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
committervitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
commit6ffe9e53658409f212834330e13564e4952558f6 (patch)
tree85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/llvm16/include/llvm/Support
parent726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff)
downloadydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/llvm16/include/llvm/Support')
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/AArch64TargetParser.h26
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/AMDGPUMetadata.h540
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ARMAttributeParser.h94
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ARMBuildAttributes.h280
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ARMTargetParser.h26
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ARMTargetParserCommon.h26
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ARMWinEH.h532
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/AlignOf.h45
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Alignment.h338
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Allocator.h465
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/AllocatorBase.h137
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ArrayRecycler.h155
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Atomic.h53
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/AtomicOrdering.h173
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/AutoConvert.h51
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BCD.h64
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BLAKE3.h135
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Base64.h72
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BinaryByteStream.h281
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BinaryItemStream.h117
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BinaryStream.h112
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BinaryStreamArray.h385
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BinaryStreamError.h58
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BinaryStreamReader.h286
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BinaryStreamRef.h283
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BinaryStreamWriter.h201
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BlockFrequency.h91
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BranchProbability.h259
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/BuryPointer.h40
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CBindingWrapping.h57
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CFGDiff.h188
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CFGUpdate.h128
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/COM.h46
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CRC.h71
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CSKYAttributeParser.h54
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CSKYAttributes.h106
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CSKYTargetParser.h26
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CachePruning.h97
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Caching.h90
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Capacity.h42
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Casting.h819
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CheckedArithmetic.h123
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Chrono.h183
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CodeGen.h147
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CodeGenCoverage.h49
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CommandLine.h2282
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Compiler.h565
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Compression.h139
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ConvertUTF.h359
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/CrashRecoveryContext.h283
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/DJB.h43
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/DOTGraphTraits.h183
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/DXILOperationCommon.h74
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/DataExtractor.h720
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/DataTypes.h32
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Debug.h116
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/DebugCounter.h198
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Discriminator.h144
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/DivisionByConstantInfo.h51
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Duration.h39
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/DynamicLibrary.h165
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ELFAttributeParser.h89
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ELFAttributes.h49
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Endian.h438
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/EndianStream.h80
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Errc.h97
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Errno.h56
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Error.h1424
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ErrorHandling.h168
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ErrorOr.h283
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ExitCodes.h44
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ExtensibleRTTI.h143
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FileCollector.h157
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FileOutputBuffer.h97
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FileSystem.h1598
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FileSystem/UniqueID.h90
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FileUtilities.h148
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Format.h269
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FormatAdapters.h120
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FormatCommon.h87
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FormatProviders.h430
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FormatVariadic.h273
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FormatVariadicDetails.h174
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/FormattedStream.h196
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/GenericDomTree.h977
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/GenericDomTreeConstruction.h1641
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/GenericIteratedDominanceFrontier.h220
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/GlobPattern.h68
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/GraphWriter.h451
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/HashBuilder.h442
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Host.h25
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/InitLLVM.h63
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/InstructionCost.h298
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ItaniumManglingCanonicalizer.h104
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/JSON.h1091
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/KnownBits.h478
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/LEB128.h219
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/LICENSE.TXT6
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/LineIterator.h109
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Locale.h28
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/LockFileManager.h111
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/LowLevelTypeImpl.h442
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/MD5.h133
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/MSP430AttributeParser.h55
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/MSP430Attributes.h55
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/MachineValueType.h1587
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ManagedStatic.h136
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/MathExtras.h787
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/MemAlloc.h98
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Memory.h192
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/MemoryBuffer.h302
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/MemoryBufferRef.h67
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ModRef.h272
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Mutex.h86
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/NativeFormatting.h58
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/OnDiskHashTable.h626
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/OptimizedStructLayout.h154
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/PGOOptions.h76
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Parallel.h303
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Path.h564
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/PluginLoader.h51
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/PointerLikeTypeTraits.h163
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/PrettyStackTrace.h127
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Printable.h63
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Process.h236
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Program.h255
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/RISCVAttributeParser.h48
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/RISCVAttributes.h55
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/RISCVISAInfo.h126
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/RWMutex.h206
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/RandomNumberGenerator.h80
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Recycler.h126
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/RecyclingAllocator.h87
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Regex.h124
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Registry.h170
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ReverseIteration.h30
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SHA1.h93
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SHA256.h100
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SMLoc.h75
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SMTAPI.h458
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SaveAndRestore.h55
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ScaledNumber.h903
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ScopedPrinter.h860
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Signals.h140
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Signposts.h55
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SmallVectorMemoryBuffer.h74
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SourceMgr.h336
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SpecialCaseList.h170
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/StringSaver.h70
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SuffixTree.h361
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SwapByteOrder.h130
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SymbolRemappingReader.h144
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/SystemUtils.h41
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/TarWriter.h44
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/TargetOpcodes.def808
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/TargetParser.h25
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ThreadPool.h260
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Threading.h270
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/TimeProfiler.h173
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Timer.h267
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/ToolOutputFile.h85
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/TrailingObjects.h396
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/TrigramIndex.h78
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/TypeName.h75
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/TypeSize.h451
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Unicode.h103
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/UnicodeCharRanges.h114
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/VCSRevision.h13
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Valgrind.h42
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/VersionTuple.h230
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/VirtualFileSystem.h1135
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Watchdog.h48
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Win64EH.h230
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/Windows/WindowsSupport.h263
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/WindowsError.h29
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/WithColor.h162
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/X86DisassemblerDecoderCommon.h487
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/X86TargetParser.h26
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/YAMLParser.h639
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/YAMLTraits.h2149
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/circular_raw_ostream.h169
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/raw_os_ostream.h52
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/raw_ostream.h782
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/thread.h255
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/type_traits.h147
-rw-r--r--contrib/libs/llvm16/include/llvm/Support/xxhash.h60
186 files changed, 47857 insertions, 0 deletions
diff --git a/contrib/libs/llvm16/include/llvm/Support/AArch64TargetParser.h b/contrib/libs/llvm16/include/llvm/Support/AArch64TargetParser.h
new file mode 100644
index 00000000000..f2001849483
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/AArch64TargetParser.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/AArch64TargetParser.h ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This header is deprecated in favour of
+/// `llvm/TargetParser/AArch64TargetParser.h`.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/AArch64TargetParser.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/AMDGPUMetadata.h b/contrib/libs/llvm16/include/llvm/Support/AMDGPUMetadata.h
new file mode 100644
index 00000000000..5c76a988d03
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/AMDGPUMetadata.h
@@ -0,0 +1,540 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- AMDGPUMetadata.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// AMDGPU metadata definitions and in-memory representations.
+///
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_AMDGPUMETADATA_H
+#define LLVM_SUPPORT_AMDGPUMETADATA_H
+
+#include "llvm/ADT/StringRef.h"
+#include <cstdint>
+#include <string>
+#include <system_error>
+#include <vector>
+
+namespace llvm {
+namespace AMDGPU {
+
+//===----------------------------------------------------------------------===//
+// HSA metadata.
+//===----------------------------------------------------------------------===//
+namespace HSAMD {
+
+/// HSA metadata major version for code object V2.
+constexpr uint32_t VersionMajorV2 = 1;
+/// HSA metadata minor version for code object V2.
+constexpr uint32_t VersionMinorV2 = 0;
+
+/// HSA metadata major version for code object V3.
+constexpr uint32_t VersionMajorV3 = 1;
+/// HSA metadata minor version for code object V3.
+constexpr uint32_t VersionMinorV3 = 0;
+
+/// HSA metadata major version for code object V4.
+constexpr uint32_t VersionMajorV4 = 1;
+/// HSA metadata minor version for code object V4.
+constexpr uint32_t VersionMinorV4 = 1;
+
+/// HSA metadata major version for code object V5.
+constexpr uint32_t VersionMajorV5 = 1;
+/// HSA metadata minor version for code object V5.
+constexpr uint32_t VersionMinorV5 = 2;
+
+/// HSA metadata beginning assembler directive.
+constexpr char AssemblerDirectiveBegin[] = ".amd_amdgpu_hsa_metadata";
+/// HSA metadata ending assembler directive.
+constexpr char AssemblerDirectiveEnd[] = ".end_amd_amdgpu_hsa_metadata";
+
+/// Access qualifiers.
+enum class AccessQualifier : uint8_t {
+ Default = 0,
+ ReadOnly = 1,
+ WriteOnly = 2,
+ ReadWrite = 3,
+ Unknown = 0xff
+};
+
+/// Address space qualifiers.
+enum class AddressSpaceQualifier : uint8_t {
+ Private = 0,
+ Global = 1,
+ Constant = 2,
+ Local = 3,
+ Generic = 4,
+ Region = 5,
+ Unknown = 0xff
+};
+
+/// Value kinds.
+enum class ValueKind : uint8_t {
+ ByValue = 0,
+ GlobalBuffer = 1,
+ DynamicSharedPointer = 2,
+ Sampler = 3,
+ Image = 4,
+ Pipe = 5,
+ Queue = 6,
+ HiddenGlobalOffsetX = 7,
+ HiddenGlobalOffsetY = 8,
+ HiddenGlobalOffsetZ = 9,
+ HiddenNone = 10,
+ HiddenPrintfBuffer = 11,
+ HiddenDefaultQueue = 12,
+ HiddenCompletionAction = 13,
+ HiddenMultiGridSyncArg = 14,
+ HiddenHostcallBuffer = 15,
+ Unknown = 0xff
+};
+
+/// Value types. This is deprecated and only remains for compatibility parsing
+/// of old metadata.
+enum class ValueType : uint8_t {
+ Struct = 0,
+ I8 = 1,
+ U8 = 2,
+ I16 = 3,
+ U16 = 4,
+ F16 = 5,
+ I32 = 6,
+ U32 = 7,
+ F32 = 8,
+ I64 = 9,
+ U64 = 10,
+ F64 = 11,
+ Unknown = 0xff
+};
+
+//===----------------------------------------------------------------------===//
+// Kernel Metadata.
+//===----------------------------------------------------------------------===//
+namespace Kernel {
+
+//===----------------------------------------------------------------------===//
+// Kernel Attributes Metadata.
+//===----------------------------------------------------------------------===//
+namespace Attrs {
+
+namespace Key {
+/// Key for Kernel::Attr::Metadata::mReqdWorkGroupSize.
+constexpr char ReqdWorkGroupSize[] = "ReqdWorkGroupSize";
+/// Key for Kernel::Attr::Metadata::mWorkGroupSizeHint.
+constexpr char WorkGroupSizeHint[] = "WorkGroupSizeHint";
+/// Key for Kernel::Attr::Metadata::mVecTypeHint.
+constexpr char VecTypeHint[] = "VecTypeHint";
+/// Key for Kernel::Attr::Metadata::mRuntimeHandle.
+constexpr char RuntimeHandle[] = "RuntimeHandle";
+} // end namespace Key
+
+/// In-memory representation of kernel attributes metadata.
+struct Metadata final {
+ /// 'reqd_work_group_size' attribute. Optional.
+ std::vector<uint32_t> mReqdWorkGroupSize = std::vector<uint32_t>();
+ /// 'work_group_size_hint' attribute. Optional.
+ std::vector<uint32_t> mWorkGroupSizeHint = std::vector<uint32_t>();
+ /// 'vec_type_hint' attribute. Optional.
+ std::string mVecTypeHint = std::string();
+ /// External symbol created by runtime to store the kernel address
+ /// for enqueued blocks.
+ std::string mRuntimeHandle = std::string();
+
+ /// Default constructor.
+ Metadata() = default;
+
+ /// \returns True if kernel attributes metadata is empty, false otherwise.
+ bool empty() const {
+ return !notEmpty();
+ }
+
+ /// \returns True if kernel attributes metadata is not empty, false otherwise.
+ bool notEmpty() const {
+ return !mReqdWorkGroupSize.empty() || !mWorkGroupSizeHint.empty() ||
+ !mVecTypeHint.empty() || !mRuntimeHandle.empty();
+ }
+};
+
+} // end namespace Attrs
+
+//===----------------------------------------------------------------------===//
+// Kernel Argument Metadata.
+//===----------------------------------------------------------------------===//
+namespace Arg {
+
+namespace Key {
+/// Key for Kernel::Arg::Metadata::mName.
+constexpr char Name[] = "Name";
+/// Key for Kernel::Arg::Metadata::mTypeName.
+constexpr char TypeName[] = "TypeName";
+/// Key for Kernel::Arg::Metadata::mSize.
+constexpr char Size[] = "Size";
+/// Key for Kernel::Arg::Metadata::mOffset.
+constexpr char Offset[] = "Offset";
+/// Key for Kernel::Arg::Metadata::mAlign.
+constexpr char Align[] = "Align";
+/// Key for Kernel::Arg::Metadata::mValueKind.
+constexpr char ValueKind[] = "ValueKind";
+/// Key for Kernel::Arg::Metadata::mValueType. (deprecated)
+constexpr char ValueType[] = "ValueType";
+/// Key for Kernel::Arg::Metadata::mPointeeAlign.
+constexpr char PointeeAlign[] = "PointeeAlign";
+/// Key for Kernel::Arg::Metadata::mAddrSpaceQual.
+constexpr char AddrSpaceQual[] = "AddrSpaceQual";
+/// Key for Kernel::Arg::Metadata::mAccQual.
+constexpr char AccQual[] = "AccQual";
+/// Key for Kernel::Arg::Metadata::mActualAccQual.
+constexpr char ActualAccQual[] = "ActualAccQual";
+/// Key for Kernel::Arg::Metadata::mIsConst.
+constexpr char IsConst[] = "IsConst";
+/// Key for Kernel::Arg::Metadata::mIsRestrict.
+constexpr char IsRestrict[] = "IsRestrict";
+/// Key for Kernel::Arg::Metadata::mIsVolatile.
+constexpr char IsVolatile[] = "IsVolatile";
+/// Key for Kernel::Arg::Metadata::mIsPipe.
+constexpr char IsPipe[] = "IsPipe";
+} // end namespace Key
+
+/// In-memory representation of kernel argument metadata.
+struct Metadata final {
+ /// Name. Optional.
+ std::string mName = std::string();
+ /// Type name. Optional.
+ std::string mTypeName = std::string();
+ /// Size in bytes. Required.
+ uint32_t mSize = 0;
+ /// Offset in bytes. Required for code object v3, unused for code object v2.
+ uint32_t mOffset = 0;
+ /// Alignment in bytes. Required.
+ uint32_t mAlign = 0;
+ /// Value kind. Required.
+ ValueKind mValueKind = ValueKind::Unknown;
+ /// Pointee alignment in bytes. Optional.
+ uint32_t mPointeeAlign = 0;
+ /// Address space qualifier. Optional.
+ AddressSpaceQualifier mAddrSpaceQual = AddressSpaceQualifier::Unknown;
+ /// Access qualifier. Optional.
+ AccessQualifier mAccQual = AccessQualifier::Unknown;
+ /// Actual access qualifier. Optional.
+ AccessQualifier mActualAccQual = AccessQualifier::Unknown;
+ /// True if 'const' qualifier is specified. Optional.
+ bool mIsConst = false;
+ /// True if 'restrict' qualifier is specified. Optional.
+ bool mIsRestrict = false;
+ /// True if 'volatile' qualifier is specified. Optional.
+ bool mIsVolatile = false;
+ /// True if 'pipe' qualifier is specified. Optional.
+ bool mIsPipe = false;
+
+ /// Default constructor.
+ Metadata() = default;
+};
+
+} // end namespace Arg
+
+//===----------------------------------------------------------------------===//
+// Kernel Code Properties Metadata.
+//===----------------------------------------------------------------------===//
+namespace CodeProps {
+
+namespace Key {
+/// Key for Kernel::CodeProps::Metadata::mKernargSegmentSize.
+constexpr char KernargSegmentSize[] = "KernargSegmentSize";
+/// Key for Kernel::CodeProps::Metadata::mGroupSegmentFixedSize.
+constexpr char GroupSegmentFixedSize[] = "GroupSegmentFixedSize";
+/// Key for Kernel::CodeProps::Metadata::mPrivateSegmentFixedSize.
+constexpr char PrivateSegmentFixedSize[] = "PrivateSegmentFixedSize";
+/// Key for Kernel::CodeProps::Metadata::mKernargSegmentAlign.
+constexpr char KernargSegmentAlign[] = "KernargSegmentAlign";
+/// Key for Kernel::CodeProps::Metadata::mWavefrontSize.
+constexpr char WavefrontSize[] = "WavefrontSize";
+/// Key for Kernel::CodeProps::Metadata::mNumSGPRs.
+constexpr char NumSGPRs[] = "NumSGPRs";
+/// Key for Kernel::CodeProps::Metadata::mNumVGPRs.
+constexpr char NumVGPRs[] = "NumVGPRs";
+/// Key for Kernel::CodeProps::Metadata::mMaxFlatWorkGroupSize.
+constexpr char MaxFlatWorkGroupSize[] = "MaxFlatWorkGroupSize";
+/// Key for Kernel::CodeProps::Metadata::mIsDynamicCallStack.
+constexpr char IsDynamicCallStack[] = "IsDynamicCallStack";
+/// Key for Kernel::CodeProps::Metadata::mIsXNACKEnabled.
+constexpr char IsXNACKEnabled[] = "IsXNACKEnabled";
+/// Key for Kernel::CodeProps::Metadata::mNumSpilledSGPRs.
+constexpr char NumSpilledSGPRs[] = "NumSpilledSGPRs";
+/// Key for Kernel::CodeProps::Metadata::mNumSpilledVGPRs.
+constexpr char NumSpilledVGPRs[] = "NumSpilledVGPRs";
+} // end namespace Key
+
+/// In-memory representation of kernel code properties metadata.
+struct Metadata final {
+ /// Size in bytes of the kernarg segment memory. Kernarg segment memory
+ /// holds the values of the arguments to the kernel. Required.
+ uint64_t mKernargSegmentSize = 0;
+ /// Size in bytes of the group segment memory required by a workgroup.
+ /// This value does not include any dynamically allocated group segment memory
+ /// that may be added when the kernel is dispatched. Required.
+ uint32_t mGroupSegmentFixedSize = 0;
+ /// Size in bytes of the private segment memory required by a workitem.
+ /// Private segment memory includes arg, spill and private segments. Required.
+ uint32_t mPrivateSegmentFixedSize = 0;
+ /// Maximum byte alignment of variables used by the kernel in the
+ /// kernarg memory segment. Required.
+ uint32_t mKernargSegmentAlign = 0;
+ /// Wavefront size. Required.
+ uint32_t mWavefrontSize = 0;
+ /// Total number of SGPRs used by a wavefront. Optional.
+ uint16_t mNumSGPRs = 0;
+ /// Total number of VGPRs used by a workitem. Optional.
+ uint16_t mNumVGPRs = 0;
+ /// Maximum flat work-group size supported by the kernel. Optional.
+ uint32_t mMaxFlatWorkGroupSize = 0;
+ /// True if the generated machine code is using a dynamically sized
+ /// call stack. Optional.
+ bool mIsDynamicCallStack = false;
+ /// True if the generated machine code is capable of supporting XNACK.
+ /// Optional.
+ bool mIsXNACKEnabled = false;
+ /// Number of SGPRs spilled by a wavefront. Optional.
+ uint16_t mNumSpilledSGPRs = 0;
+ /// Number of VGPRs spilled by a workitem. Optional.
+ uint16_t mNumSpilledVGPRs = 0;
+
+ /// Default constructor.
+ Metadata() = default;
+
+ /// \returns True if kernel code properties metadata is empty, false
+ /// otherwise.
+ bool empty() const {
+ return !notEmpty();
+ }
+
+ /// \returns True if kernel code properties metadata is not empty, false
+ /// otherwise.
+ bool notEmpty() const {
+ return true;
+ }
+};
+
+} // end namespace CodeProps
+
+//===----------------------------------------------------------------------===//
+// Kernel Debug Properties Metadata.
+//===----------------------------------------------------------------------===//
+namespace DebugProps {
+
+namespace Key {
+/// Key for Kernel::DebugProps::Metadata::mDebuggerABIVersion.
+constexpr char DebuggerABIVersion[] = "DebuggerABIVersion";
+/// Key for Kernel::DebugProps::Metadata::mReservedNumVGPRs.
+constexpr char ReservedNumVGPRs[] = "ReservedNumVGPRs";
+/// Key for Kernel::DebugProps::Metadata::mReservedFirstVGPR.
+constexpr char ReservedFirstVGPR[] = "ReservedFirstVGPR";
+/// Key for Kernel::DebugProps::Metadata::mPrivateSegmentBufferSGPR.
+constexpr char PrivateSegmentBufferSGPR[] = "PrivateSegmentBufferSGPR";
+/// Key for
+/// Kernel::DebugProps::Metadata::mWavefrontPrivateSegmentOffsetSGPR.
+constexpr char WavefrontPrivateSegmentOffsetSGPR[] =
+ "WavefrontPrivateSegmentOffsetSGPR";
+} // end namespace Key
+
+/// In-memory representation of kernel debug properties metadata.
+struct Metadata final {
+ /// Debugger ABI version. Optional.
+ std::vector<uint32_t> mDebuggerABIVersion = std::vector<uint32_t>();
+ /// Consecutive number of VGPRs reserved for debugger use. Must be 0 if
+ /// mDebuggerABIVersion is not set. Optional.
+ uint16_t mReservedNumVGPRs = 0;
+ /// First fixed VGPR reserved. Must be uint16_t(-1) if
+ /// mDebuggerABIVersion is not set or mReservedFirstVGPR is 0. Optional.
+ uint16_t mReservedFirstVGPR = uint16_t(-1);
+ /// Fixed SGPR of the first of 4 SGPRs used to hold the scratch V# used
+ /// for the entire kernel execution. Must be uint16_t(-1) if
+ /// mDebuggerABIVersion is not set or SGPR not used or not known. Optional.
+ uint16_t mPrivateSegmentBufferSGPR = uint16_t(-1);
+ /// Fixed SGPR used to hold the wave scratch offset for the entire
+ /// kernel execution. Must be uint16_t(-1) if mDebuggerABIVersion is not set
+ /// or SGPR is not used or not known. Optional.
+ uint16_t mWavefrontPrivateSegmentOffsetSGPR = uint16_t(-1);
+
+ /// Default constructor.
+ Metadata() = default;
+
+ /// \returns True if kernel debug properties metadata is empty, false
+ /// otherwise.
+ bool empty() const {
+ return !notEmpty();
+ }
+
+ /// \returns True if kernel debug properties metadata is not empty, false
+ /// otherwise.
+ bool notEmpty() const {
+ return !mDebuggerABIVersion.empty();
+ }
+};
+
+} // end namespace DebugProps
+
+namespace Key {
+/// Key for Kernel::Metadata::mName.
+constexpr char Name[] = "Name";
+/// Key for Kernel::Metadata::mSymbolName.
+constexpr char SymbolName[] = "SymbolName";
+/// Key for Kernel::Metadata::mLanguage.
+constexpr char Language[] = "Language";
+/// Key for Kernel::Metadata::mLanguageVersion.
+constexpr char LanguageVersion[] = "LanguageVersion";
+/// Key for Kernel::Metadata::mAttrs.
+constexpr char Attrs[] = "Attrs";
+/// Key for Kernel::Metadata::mArgs.
+constexpr char Args[] = "Args";
+/// Key for Kernel::Metadata::mCodeProps.
+constexpr char CodeProps[] = "CodeProps";
+/// Key for Kernel::Metadata::mDebugProps.
+constexpr char DebugProps[] = "DebugProps";
+} // end namespace Key
+
+/// In-memory representation of kernel metadata.
+struct Metadata final {
+ /// Kernel source name. Required.
+ std::string mName = std::string();
+ /// Kernel descriptor name. Required.
+ std::string mSymbolName = std::string();
+ /// Language. Optional.
+ std::string mLanguage = std::string();
+ /// Language version. Optional.
+ std::vector<uint32_t> mLanguageVersion = std::vector<uint32_t>();
+ /// Attributes metadata. Optional.
+ Attrs::Metadata mAttrs = Attrs::Metadata();
+ /// Arguments metadata. Optional.
+ std::vector<Arg::Metadata> mArgs = std::vector<Arg::Metadata>();
+ /// Code properties metadata. Optional.
+ CodeProps::Metadata mCodeProps = CodeProps::Metadata();
+ /// Debug properties metadata. Optional.
+ DebugProps::Metadata mDebugProps = DebugProps::Metadata();
+
+ /// Default constructor.
+ Metadata() = default;
+};
+
+} // end namespace Kernel
+
+namespace Key {
+/// Key for HSA::Metadata::mVersion.
+constexpr char Version[] = "Version";
+/// Key for HSA::Metadata::mPrintf.
+constexpr char Printf[] = "Printf";
+/// Key for HSA::Metadata::mKernels.
+constexpr char Kernels[] = "Kernels";
+} // end namespace Key
+
+/// In-memory representation of HSA metadata.
+struct Metadata final {
+ /// HSA metadata version. Required.
+ std::vector<uint32_t> mVersion = std::vector<uint32_t>();
+ /// Printf metadata. Optional.
+ std::vector<std::string> mPrintf = std::vector<std::string>();
+ /// Kernels metadata. Required.
+ std::vector<Kernel::Metadata> mKernels = std::vector<Kernel::Metadata>();
+
+ /// Default constructor.
+ Metadata() = default;
+};
+
+/// Converts \p String to \p HSAMetadata.
+std::error_code fromString(StringRef String, Metadata &HSAMetadata);
+
+/// Converts \p HSAMetadata to \p String.
+std::error_code toString(Metadata HSAMetadata, std::string &String);
+
+//===----------------------------------------------------------------------===//
+// HSA metadata for v3 code object.
+//===----------------------------------------------------------------------===//
+namespace V3 {
+/// HSA metadata major version.
+constexpr uint32_t VersionMajor = 1;
+/// HSA metadata minor version.
+constexpr uint32_t VersionMinor = 0;
+
+/// HSA metadata beginning assembler directive.
+constexpr char AssemblerDirectiveBegin[] = ".amdgpu_metadata";
+/// HSA metadata ending assembler directive.
+constexpr char AssemblerDirectiveEnd[] = ".end_amdgpu_metadata";
+} // end namespace V3
+
+} // end namespace HSAMD
+
+//===----------------------------------------------------------------------===//
+// PAL metadata.
+//===----------------------------------------------------------------------===//
+namespace PALMD {
+
+/// PAL metadata (old linear format) assembler directive.
+constexpr char AssemblerDirective[] = ".amd_amdgpu_pal_metadata";
+
+/// PAL metadata (new MsgPack format) beginning assembler directive.
+constexpr char AssemblerDirectiveBegin[] = ".amdgpu_pal_metadata";
+
+/// PAL metadata (new MsgPack format) ending assembler directive.
+constexpr char AssemblerDirectiveEnd[] = ".end_amdgpu_pal_metadata";
+
+/// PAL metadata keys.
+enum Key : uint32_t {
+ R_2E12_COMPUTE_PGM_RSRC1 = 0x2e12,
+ R_2D4A_SPI_SHADER_PGM_RSRC1_LS = 0x2d4a,
+ R_2D0A_SPI_SHADER_PGM_RSRC1_HS = 0x2d0a,
+ R_2CCA_SPI_SHADER_PGM_RSRC1_ES = 0x2cca,
+ R_2C8A_SPI_SHADER_PGM_RSRC1_GS = 0x2c8a,
+ R_2C4A_SPI_SHADER_PGM_RSRC1_VS = 0x2c4a,
+ R_2C0A_SPI_SHADER_PGM_RSRC1_PS = 0x2c0a,
+ R_2E00_COMPUTE_DISPATCH_INITIATOR = 0x2e00,
+ R_A1B3_SPI_PS_INPUT_ENA = 0xa1b3,
+ R_A1B4_SPI_PS_INPUT_ADDR = 0xa1b4,
+ R_A1B6_SPI_PS_IN_CONTROL = 0xa1b6,
+ R_A2D5_VGT_SHADER_STAGES_EN = 0xa2d5,
+
+ LS_NUM_USED_VGPRS = 0x10000021,
+ HS_NUM_USED_VGPRS = 0x10000022,
+ ES_NUM_USED_VGPRS = 0x10000023,
+ GS_NUM_USED_VGPRS = 0x10000024,
+ VS_NUM_USED_VGPRS = 0x10000025,
+ PS_NUM_USED_VGPRS = 0x10000026,
+ CS_NUM_USED_VGPRS = 0x10000027,
+
+ LS_NUM_USED_SGPRS = 0x10000028,
+ HS_NUM_USED_SGPRS = 0x10000029,
+ ES_NUM_USED_SGPRS = 0x1000002a,
+ GS_NUM_USED_SGPRS = 0x1000002b,
+ VS_NUM_USED_SGPRS = 0x1000002c,
+ PS_NUM_USED_SGPRS = 0x1000002d,
+ CS_NUM_USED_SGPRS = 0x1000002e,
+
+ LS_SCRATCH_SIZE = 0x10000044,
+ HS_SCRATCH_SIZE = 0x10000045,
+ ES_SCRATCH_SIZE = 0x10000046,
+ GS_SCRATCH_SIZE = 0x10000047,
+ VS_SCRATCH_SIZE = 0x10000048,
+ PS_SCRATCH_SIZE = 0x10000049,
+ CS_SCRATCH_SIZE = 0x1000004a
+};
+
+} // end namespace PALMD
+} // end namespace AMDGPU
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_AMDGPUMETADATA_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ARMAttributeParser.h b/contrib/libs/llvm16/include/llvm/Support/ARMAttributeParser.h
new file mode 100644
index 00000000000..9c5c8884673
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ARMAttributeParser.h
@@ -0,0 +1,94 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- ARMAttributeParser.h - ARM Attribute Information Printer -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_ARMATTRIBUTEPARSER_H
+
+#include "ARMBuildAttributes.h"
+#include "ELFAttributeParser.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+class ScopedPrinter;
+
+class ARMAttributeParser : public ELFAttributeParser {
+ struct DisplayHandler {
+ ARMBuildAttrs::AttrType attribute;
+ Error (ARMAttributeParser::*routine)(ARMBuildAttrs::AttrType);
+ };
+ static const DisplayHandler displayRoutines[];
+
+ Error handler(uint64_t tag, bool &handled) override;
+
+ Error stringAttribute(ARMBuildAttrs::AttrType tag);
+
+ Error CPU_arch(ARMBuildAttrs::AttrType tag);
+ Error CPU_arch_profile(ARMBuildAttrs::AttrType tag);
+ Error ARM_ISA_use(ARMBuildAttrs::AttrType tag);
+ Error THUMB_ISA_use(ARMBuildAttrs::AttrType tag);
+ Error FP_arch(ARMBuildAttrs::AttrType tag);
+ Error WMMX_arch(ARMBuildAttrs::AttrType tag);
+ Error Advanced_SIMD_arch(ARMBuildAttrs::AttrType tag);
+ Error MVE_arch(ARMBuildAttrs::AttrType tag);
+ Error PCS_config(ARMBuildAttrs::AttrType tag);
+ Error ABI_PCS_R9_use(ARMBuildAttrs::AttrType tag);
+ Error ABI_PCS_RW_data(ARMBuildAttrs::AttrType tag);
+ Error ABI_PCS_RO_data(ARMBuildAttrs::AttrType tag);
+ Error ABI_PCS_GOT_use(ARMBuildAttrs::AttrType tag);
+ Error ABI_PCS_wchar_t(ARMBuildAttrs::AttrType tag);
+ Error ABI_FP_rounding(ARMBuildAttrs::AttrType tag);
+ Error ABI_FP_denormal(ARMBuildAttrs::AttrType tag);
+ Error ABI_FP_exceptions(ARMBuildAttrs::AttrType tag);
+ Error ABI_FP_user_exceptions(ARMBuildAttrs::AttrType tag);
+ Error ABI_FP_number_model(ARMBuildAttrs::AttrType tag);
+ Error ABI_align_needed(ARMBuildAttrs::AttrType tag);
+ Error ABI_align_preserved(ARMBuildAttrs::AttrType tag);
+ Error ABI_enum_size(ARMBuildAttrs::AttrType tag);
+ Error ABI_HardFP_use(ARMBuildAttrs::AttrType tag);
+ Error ABI_VFP_args(ARMBuildAttrs::AttrType tag);
+ Error ABI_WMMX_args(ARMBuildAttrs::AttrType tag);
+ Error ABI_optimization_goals(ARMBuildAttrs::AttrType tag);
+ Error ABI_FP_optimization_goals(ARMBuildAttrs::AttrType tag);
+ Error compatibility(ARMBuildAttrs::AttrType tag);
+ Error CPU_unaligned_access(ARMBuildAttrs::AttrType tag);
+ Error FP_HP_extension(ARMBuildAttrs::AttrType tag);
+ Error ABI_FP_16bit_format(ARMBuildAttrs::AttrType tag);
+ Error MPextension_use(ARMBuildAttrs::AttrType tag);
+ Error DIV_use(ARMBuildAttrs::AttrType tag);
+ Error DSP_extension(ARMBuildAttrs::AttrType tag);
+ Error T2EE_use(ARMBuildAttrs::AttrType tag);
+ Error Virtualization_use(ARMBuildAttrs::AttrType tag);
+ Error PAC_extension(ARMBuildAttrs::AttrType tag);
+ Error BTI_extension(ARMBuildAttrs::AttrType tag);
+ Error PACRET_use(ARMBuildAttrs::AttrType tag);
+ Error BTI_use(ARMBuildAttrs::AttrType tag);
+ Error nodefaults(ARMBuildAttrs::AttrType tag);
+ Error also_compatible_with(ARMBuildAttrs::AttrType tag);
+
+public:
+ ARMAttributeParser(ScopedPrinter *sw)
+ : ELFAttributeParser(sw, ARMBuildAttrs::getARMAttributeTags(), "aeabi") {}
+ ARMAttributeParser()
+ : ELFAttributeParser(ARMBuildAttrs::getARMAttributeTags(), "aeabi") {}
+};
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ARMBuildAttributes.h b/contrib/libs/llvm16/include/llvm/Support/ARMBuildAttributes.h
new file mode 100644
index 00000000000..b0b793bf2c7
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ARMBuildAttributes.h
@@ -0,0 +1,280 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- ARMBuildAttributes.h - ARM Build Attributes -------------*- 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 enumerations and support routines for ARM build attributes
+// as defined in ARM ABI addenda document (ABI release 2.08).
+//
+// ELF for the ARM Architecture r2.09 - November 30, 2012
+//
+// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ARMBUILDATTRIBUTES_H
+#define LLVM_SUPPORT_ARMBUILDATTRIBUTES_H
+
+#include "llvm/Support/ELFAttributes.h"
+
+namespace llvm {
+namespace ARMBuildAttrs {
+
+const TagNameMap &getARMAttributeTags();
+
+enum SpecialAttr {
+ // This is for the .cpu asm attr. It translates into one or more
+ // AttrType (below) entries in the .ARM.attributes section in the ELF.
+ SEL_CPU
+};
+
+enum AttrType : unsigned {
+ // Rest correspond to ELF/.ARM.attributes
+ File = 1,
+ CPU_raw_name = 4,
+ CPU_name = 5,
+ CPU_arch = 6,
+ CPU_arch_profile = 7,
+ ARM_ISA_use = 8,
+ THUMB_ISA_use = 9,
+ FP_arch = 10,
+ WMMX_arch = 11,
+ Advanced_SIMD_arch = 12,
+ PCS_config = 13,
+ ABI_PCS_R9_use = 14,
+ ABI_PCS_RW_data = 15,
+ ABI_PCS_RO_data = 16,
+ ABI_PCS_GOT_use = 17,
+ ABI_PCS_wchar_t = 18,
+ ABI_FP_rounding = 19,
+ ABI_FP_denormal = 20,
+ ABI_FP_exceptions = 21,
+ ABI_FP_user_exceptions = 22,
+ ABI_FP_number_model = 23,
+ ABI_align_needed = 24,
+ ABI_align_preserved = 25,
+ ABI_enum_size = 26,
+ ABI_HardFP_use = 27,
+ ABI_VFP_args = 28,
+ ABI_WMMX_args = 29,
+ ABI_optimization_goals = 30,
+ ABI_FP_optimization_goals = 31,
+ compatibility = 32,
+ CPU_unaligned_access = 34,
+ FP_HP_extension = 36,
+ ABI_FP_16bit_format = 38,
+ MPextension_use = 42, // recoded from 70 (ABI r2.08)
+ DIV_use = 44,
+ DSP_extension = 46,
+ MVE_arch = 48,
+ PAC_extension = 50,
+ BTI_extension = 52,
+ also_compatible_with = 65,
+ conformance = 67,
+ Virtualization_use = 68,
+ BTI_use = 74,
+ PACRET_use = 76,
+
+ /// Legacy Tags
+ Section = 2, // deprecated (ABI r2.09)
+ Symbol = 3, // deprecated (ABI r2.09)
+ ABI_align8_needed = 24, // renamed to ABI_align_needed (ABI r2.09)
+ ABI_align8_preserved = 25, // renamed to ABI_align_preserved (ABI r2.09)
+ nodefaults = 64, // deprecated (ABI r2.09)
+ T2EE_use = 66, // deprecated (ABI r2.09)
+ MPextension_use_old = 70 // recoded to MPextension_use (ABI r2.08)
+};
+
+// Legal Values for CPU_arch, (=6), uleb128
+enum CPUArch {
+ Pre_v4 = 0,
+ v4 = 1, // e.g. SA110
+ v4T = 2, // e.g. ARM7TDMI
+ v5T = 3, // e.g. ARM9TDMI
+ v5TE = 4, // e.g. ARM946E_S
+ v5TEJ = 5, // e.g. ARM926EJ_S
+ v6 = 6, // e.g. ARM1136J_S
+ v6KZ = 7, // e.g. ARM1176JZ_S
+ v6T2 = 8, // e.g. ARM1156T2_S
+ v6K = 9, // e.g. ARM1176JZ_S
+ v7 = 10, // e.g. Cortex A8, Cortex M3
+ v6_M = 11, // e.g. Cortex M1
+ v6S_M = 12, // v6_M with the System extensions
+ v7E_M = 13, // v7_M with DSP extensions
+ v8_A = 14, // v8_A AArch32
+ v8_R = 15, // e.g. Cortex R52
+ v8_M_Base = 16, // v8_M_Base AArch32
+ v8_M_Main = 17, // v8_M_Main AArch32
+ v8_1_M_Main = 21, // v8_1_M_Main AArch32
+ v9_A = 22, // v9_A AArch32
+};
+
+enum CPUArchProfile { // (=7), uleb128
+ Not_Applicable = 0, // pre v7, or cross-profile code
+ ApplicationProfile = (0x41), // 'A' (e.g. for Cortex A8)
+ RealTimeProfile = (0x52), // 'R' (e.g. for Cortex R4)
+ MicroControllerProfile = (0x4D), // 'M' (e.g. for Cortex M3)
+ SystemProfile = (0x53) // 'S' Application or real-time profile
+};
+
+// The following have a lot of common use cases
+enum {
+ Not_Allowed = 0,
+ Allowed = 1,
+
+ // Tag_ARM_ISA_use (=8), uleb128
+
+ // Tag_THUMB_ISA_use, (=9), uleb128
+ AllowThumb32 = 2, // 32-bit Thumb (implies 16-bit instructions)
+ AllowThumbDerived = 3, // Thumb allowed, derived from arch/profile
+
+ // Tag_FP_arch (=10), uleb128 (formerly Tag_VFP_arch = 10)
+ AllowFPv2 = 2, // v2 FP ISA permitted (implies use of the v1 FP ISA)
+ AllowFPv3A = 3, // v3 FP ISA permitted (implies use of the v2 FP ISA)
+ AllowFPv3B = 4, // v3 FP ISA permitted, but only D0-D15, S0-S31
+ AllowFPv4A = 5, // v4 FP ISA permitted (implies use of v3 FP ISA)
+ AllowFPv4B = 6, // v4 FP ISA was permitted, but only D0-D15, S0-S31
+ AllowFPARMv8A = 7, // Use of the ARM v8-A FP ISA was permitted
+ AllowFPARMv8B = 8, // Use of the ARM v8-A FP ISA was permitted, but only
+ // D0-D15, S0-S31
+
+ // Tag_WMMX_arch, (=11), uleb128
+ AllowWMMXv1 = 1, // The user permitted this entity to use WMMX v1
+ AllowWMMXv2 = 2, // The user permitted this entity to use WMMX v2
+
+ // Tag_Advanced_SIMD_arch, (=12), uleb128
+ AllowNeon = 1, // SIMDv1 was permitted
+ AllowNeon2 = 2, // SIMDv2 was permitted (Half-precision FP, MAC operations)
+ AllowNeonARMv8 = 3, // ARM v8-A SIMD was permitted
+ AllowNeonARMv8_1a = 4,// ARM v8.1-A SIMD was permitted (RDMA)
+
+ // Tag_MVE_arch, (=48), uleb128
+ AllowMVEInteger = 1, // integer-only MVE was permitted
+ AllowMVEIntegerAndFloat = 2, // both integer and floating point MVE were permitted
+
+ // Tag_ABI_PCS_R9_use, (=14), uleb128
+ R9IsGPR = 0, // R9 used as v6 (just another callee-saved register)
+ R9IsSB = 1, // R9 used as a global static base rgister
+ R9IsTLSPointer = 2, // R9 used as a thread local storage pointer
+ R9Reserved = 3, // R9 not used by code associated with attributed entity
+
+ // Tag_ABI_PCS_RW_data, (=15), uleb128
+ AddressRWPCRel = 1, // Address RW static data PC-relative
+ AddressRWSBRel = 2, // Address RW static data SB-relative
+ AddressRWNone = 3, // No RW static data permitted
+
+ // Tag_ABI_PCS_RO_data, (=14), uleb128
+ AddressROPCRel = 1, // Address RO static data PC-relative
+ AddressRONone = 2, // No RO static data permitted
+
+ // Tag_ABI_PCS_GOT_use, (=17), uleb128
+ AddressDirect = 1, // Address imported data directly
+ AddressGOT = 2, // Address imported data indirectly (via GOT)
+
+ // Tag_ABI_PCS_wchar_t, (=18), uleb128
+ WCharProhibited = 0, // wchar_t is not used
+ WCharWidth2Bytes = 2, // sizeof(wchar_t) == 2
+ WCharWidth4Bytes = 4, // sizeof(wchar_t) == 4
+
+ // Tag_ABI_align_needed, (=24), uleb128
+ Align8Byte = 1,
+ Align4Byte = 2,
+ AlignReserved = 3,
+
+ // Tag_ABI_align_needed, (=25), uleb128
+ AlignNotPreserved = 0,
+ AlignPreserve8Byte = 1,
+ AlignPreserveAll = 2,
+
+ // Tag_ABI_FP_denormal, (=20), uleb128
+ PositiveZero = 0,
+ IEEEDenormals = 1,
+ PreserveFPSign = 2, // sign when flushed-to-zero is preserved
+
+ // Tag_ABI_FP_number_model, (=23), uleb128
+ AllowIEEENormal = 1,
+ AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI])
+ AllowIEEE754 = 3, // this code to use all the IEEE 754-defined FP encodings
+
+ // Tag_ABI_enum_size, (=26), uleb128
+ EnumProhibited = 0, // The user prohibited the use of enums when building
+ // this entity.
+ EnumSmallest = 1, // Enum is smallest container big enough to hold all
+ // values.
+ Enum32Bit = 2, // Enum is at least 32 bits.
+ Enum32BitABI = 3, // Every enumeration visible across an ABI-complying
+ // interface contains a value needing 32 bits to encode
+ // it; other enums can be containerized.
+
+ // Tag_ABI_HardFP_use, (=27), uleb128
+ HardFPImplied = 0, // FP use should be implied by Tag_FP_arch
+ HardFPSinglePrecision = 1, // Single-precision only
+
+ // Tag_ABI_VFP_args, (=28), uleb128
+ BaseAAPCS = 0,
+ HardFPAAPCS = 1,
+ ToolChainFPPCS = 2,
+ CompatibleFPAAPCS = 3,
+
+ // Tag_FP_HP_extension, (=36), uleb128
+ AllowHPFP = 1, // Allow use of Half Precision FP
+
+ // Tag_FP_16bit_format, (=38), uleb128
+ FP16FormatIEEE = 1,
+ FP16VFP3 = 2,
+
+ // Tag_MPextension_use, (=42), uleb128
+ AllowMP = 1, // Allow use of MP extensions
+
+ // Tag_DIV_use, (=44), uleb128
+ // Note: AllowDIVExt must be emitted if and only if the permission to use
+ // hardware divide cannot be conveyed using AllowDIVIfExists or DisallowDIV
+ AllowDIVIfExists = 0, // Allow hardware divide if available in arch, or no
+ // info exists.
+ DisallowDIV = 1, // Hardware divide explicitly disallowed.
+ AllowDIVExt = 2, // Allow hardware divide as optional architecture
+ // extension above the base arch specified by
+ // Tag_CPU_arch and Tag_CPU_arch_profile.
+
+ // Tag_Virtualization_use, (=68), uleb128
+ AllowTZ = 1,
+ AllowVirtualization = 2,
+ AllowTZVirtualization = 3,
+
+ // Tag_PAC_extension, (=50), uleb128
+ DisallowPAC = 0,
+ AllowPACInNOPSpace = 1,
+ AllowPAC = 2,
+
+ // Tag_BTI_extension, (=52), uleb128
+ DisallowBTI = 0,
+ AllowBTIInNOPSpace = 1,
+ AllowBTI = 2,
+
+ // Tag_BTI_use, (=74), uleb128
+ BTINotUsed = 0,
+ BTIUsed = 1,
+
+ // Tag_PACRET_use, (=76), uleb128
+ PACRETNotUsed = 0,
+ PACRETUsed = 1
+};
+
+} // namespace ARMBuildAttrs
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ARMTargetParser.h b/contrib/libs/llvm16/include/llvm/Support/ARMTargetParser.h
new file mode 100644
index 00000000000..22a4ca85cd6
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ARMTargetParser.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/ARMTargetParser.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This header is deprecated in favour of
+/// `llvm/TargetParser/ARMTargetParser.h`.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/ARMTargetParser.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ARMTargetParserCommon.h b/contrib/libs/llvm16/include/llvm/Support/ARMTargetParserCommon.h
new file mode 100644
index 00000000000..62502ee8b15
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ARMTargetParserCommon.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/ARMTargetParserCommon.def ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This header is deprecated in favour of
+/// `llvm/TargetParser/ARMTargetParserCommon.h`.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/ARMTargetParserCommon.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ARMWinEH.h b/contrib/libs/llvm16/include/llvm/Support/ARMWinEH.h
new file mode 100644
index 00000000000..c21d6870b00
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ARMWinEH.h
@@ -0,0 +1,532 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/ARMWinEH.h - Windows on ARM EH Constants ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ARMWINEH_H
+#define LLVM_SUPPORT_ARMWINEH_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Endian.h"
+
+namespace llvm {
+namespace ARM {
+namespace WinEH {
+enum class RuntimeFunctionFlag {
+ RFF_Unpacked, /// unpacked entry
+ RFF_Packed, /// packed entry
+ RFF_PackedFragment, /// packed entry representing a fragment
+ RFF_Reserved, /// reserved
+};
+
+enum class ReturnType {
+ RT_POP, /// return via pop {pc} (L flag must be set)
+ RT_B, /// 16-bit branch
+ RT_BW, /// 32-bit branch
+ RT_NoEpilogue, /// no epilogue (fragment)
+};
+
+/// RuntimeFunction - An entry in the table of procedure data (.pdata)
+///
+/// This is ARM specific, but the Function Start RVA, Flag and
+/// ExceptionInformationRVA fields work identically for ARM64.
+///
+/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +---------------------------------------------------------------+
+/// | Function Start RVA |
+/// +-------------------+-+-+-+-----+-+---+---------------------+---+
+/// | Stack Adjust |C|L|R| Reg |H|Ret| Function Length |Flg|
+/// +-------------------+-+-+-+-----+-+---+---------------------+---+
+///
+/// Flag : 2-bit field with the following meanings:
+/// - 00 = packed unwind data not used; reamining bits point to .xdata record
+/// - 01 = packed unwind data
+/// - 10 = packed unwind data, function assumed to have no prologue; useful
+/// for function fragments that are discontiguous with the start of the
+/// function
+/// - 11 = reserved
+/// Function Length : 11-bit field providing the length of the entire function
+/// in bytes, divided by 2; if the function is greater than
+/// 4KB, a full .xdata record must be used instead
+/// Ret : 2-bit field indicating how the function returns
+/// - 00 = return via pop {pc} (the L bit must be set)
+/// - 01 = return via 16-bit branch
+/// - 10 = return via 32-bit branch
+/// - 11 = no epilogue; useful for function fragments that may only contain a
+/// prologue but the epilogue is elsewhere
+/// H : 1-bit flag indicating whether the function "homes" the integer parameter
+/// registers (r0-r3), allocating 16-bytes on the stack
+/// Reg : 3-bit field indicating the index of the last saved non-volatile
+/// register. If the R bit is set to 0, then only integer registers are
+/// saved (r4-rN, where N is 4 + Reg). If the R bit is set to 1, then
+/// only floating-point registers are being saved (d8-dN, where N is
+/// 8 + Reg). The special case of the R bit being set to 1 and Reg equal
+/// to 7 indicates that no registers are saved.
+/// R : 1-bit flag indicating whether the non-volatile registers are integer or
+/// floating-point. 0 indicates integer, 1 indicates floating-point. The
+/// special case of the R-flag being set and Reg being set to 7 indicates
+/// that no non-volatile registers are saved.
+/// L : 1-bit flag indicating whether the function saves/restores the link
+/// register (LR)
+/// C : 1-bit flag indicating whether the function includes extra instructions
+/// to setup a frame chain for fast walking. If this flag is set, r11 is
+/// implicitly added to the list of saved non-volatile integer registers.
+/// Stack Adjust : 10-bit field indicating the number of bytes of stack that are
+/// allocated for this function. Only values between 0x000 and
+/// 0x3f3 can be directly encoded. If the value is 0x3f4 or
+/// greater, then the low 4 bits have special meaning as follows:
+/// - Bit 0-1
+/// indicate the number of words' of adjustment (1-4), minus 1
+/// - Bit 2
+/// indicates if the prologue combined adjustment into push
+/// - Bit 3
+/// indicates if the epilogue combined adjustment into pop
+///
+/// RESTRICTIONS:
+/// - IF C is SET:
+/// + L flag must be set since frame chaining requires r11 and lr
+/// + r11 must NOT be included in the set of registers described by Reg
+/// - IF Ret is 0:
+/// + L flag must be set
+
+// NOTE: RuntimeFunction is meant to be a simple class that provides raw access
+// to all fields in the structure. The accessor methods reflect the names of
+// the bitfields that they correspond to. Although some obvious simplifications
+// are possible via merging of methods, it would prevent the use of this class
+// to fully inspect the contents of the data structure which is particularly
+// useful for scenarios such as llvm-readobj to aid in testing.
+
+class RuntimeFunction {
+public:
+ const support::ulittle32_t BeginAddress;
+ const support::ulittle32_t UnwindData;
+
+ RuntimeFunction(const support::ulittle32_t *Data)
+ : BeginAddress(Data[0]), UnwindData(Data[1]) {}
+
+ RuntimeFunction(const support::ulittle32_t BeginAddress,
+ const support::ulittle32_t UnwindData)
+ : BeginAddress(BeginAddress), UnwindData(UnwindData) {}
+
+ RuntimeFunctionFlag Flag() const {
+ return RuntimeFunctionFlag(UnwindData & 0x3);
+ }
+
+ uint32_t ExceptionInformationRVA() const {
+ assert(Flag() == RuntimeFunctionFlag::RFF_Unpacked &&
+ "unpacked form required for this operation");
+ return (UnwindData & ~0x3);
+ }
+
+ uint32_t PackedUnwindData() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return (UnwindData & ~0x3);
+ }
+ uint32_t FunctionLength() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return (((UnwindData & 0x00001ffc) >> 2) << 1);
+ }
+ ReturnType Ret() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ assert(((UnwindData & 0x00006000) || L()) && "L must be set to 1");
+ return ReturnType((UnwindData & 0x00006000) >> 13);
+ }
+ bool H() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0x00008000) >> 15);
+ }
+ uint8_t Reg() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0x00070000) >> 16);
+ }
+ bool R() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0x00080000) >> 19);
+ }
+ bool L() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0x00100000) >> 20);
+ }
+ bool C() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ assert(((~UnwindData & 0x00200000) || L()) &&
+ "L flag must be set, chaining requires r11 and LR");
+ assert(((~UnwindData & 0x00200000) || (Reg() < 7) || R()) &&
+ "r11 must not be included in Reg; C implies r11");
+ return ((UnwindData & 0x00200000) >> 21);
+ }
+ uint16_t StackAdjust() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0xffc00000) >> 22);
+ }
+};
+
+/// PrologueFolding - pseudo-flag derived from Stack Adjust indicating that the
+/// prologue has stack adjustment combined into the push
+inline bool PrologueFolding(const RuntimeFunction &RF) {
+ return RF.StackAdjust() >= 0x3f4 && (RF.StackAdjust() & 0x4);
+}
+/// Epilogue - pseudo-flag derived from Stack Adjust indicating that the
+/// epilogue has stack adjustment combined into the pop
+inline bool EpilogueFolding(const RuntimeFunction &RF) {
+ return RF.StackAdjust() >= 0x3f4 && (RF.StackAdjust() & 0x8);
+}
+/// StackAdjustment - calculated stack adjustment in words. The stack
+/// adjustment should be determined via this function to account for the special
+/// handling the special encoding when the value is >= 0x3f4.
+inline uint16_t StackAdjustment(const RuntimeFunction &RF) {
+ uint16_t Adjustment = RF.StackAdjust();
+ if (Adjustment >= 0x3f4)
+ return (Adjustment & 0x3) + 1;
+ return Adjustment;
+}
+
+/// SavedRegisterMask - Utility function to calculate the set of saved general
+/// purpose (r0-r15) and VFP (d0-d31) registers.
+std::pair<uint16_t, uint32_t> SavedRegisterMask(const RuntimeFunction &RF,
+ bool Prologue = true);
+
+/// RuntimeFunctionARM64 - An entry in the table of procedure data (.pdata)
+///
+/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +---------------------------------------------------------------+
+/// | Function Start RVA |
+/// +-----------------+---+-+-------+-----+---------------------+---+
+/// | Frame Size |CR |H| RegI |RegF | Function Length |Flg|
+/// +-----------------+---+-+-------+-----+---------------------+---+
+///
+/// See https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
+/// for the full reference for this struct.
+
+class RuntimeFunctionARM64 {
+public:
+ const support::ulittle32_t BeginAddress;
+ const support::ulittle32_t UnwindData;
+
+ RuntimeFunctionARM64(const support::ulittle32_t *Data)
+ : BeginAddress(Data[0]), UnwindData(Data[1]) {}
+
+ RuntimeFunctionARM64(const support::ulittle32_t BeginAddress,
+ const support::ulittle32_t UnwindData)
+ : BeginAddress(BeginAddress), UnwindData(UnwindData) {}
+
+ RuntimeFunctionFlag Flag() const {
+ return RuntimeFunctionFlag(UnwindData & 0x3);
+ }
+
+ uint32_t ExceptionInformationRVA() const {
+ assert(Flag() == RuntimeFunctionFlag::RFF_Unpacked &&
+ "unpacked form required for this operation");
+ return (UnwindData & ~0x3);
+ }
+
+ uint32_t PackedUnwindData() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return (UnwindData & ~0x3);
+ }
+ uint32_t FunctionLength() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return (((UnwindData & 0x00001ffc) >> 2) << 2);
+ }
+ uint8_t RegF() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0x0000e000) >> 13);
+ }
+ uint8_t RegI() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0x000f0000) >> 16);
+ }
+ bool H() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0x00100000) >> 20);
+ }
+ uint8_t CR() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0x600000) >> 21);
+ }
+ uint16_t FrameSize() const {
+ assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+ Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+ "packed form required for this operation");
+ return ((UnwindData & 0xff800000) >> 23);
+ }
+};
+
+/// ExceptionDataRecord - An entry in the table of exception data (.xdata)
+///
+/// The format on ARM is:
+///
+/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +-------+---------+-+-+-+---+-----------------------------------+
+/// | C Wrd | Epi Cnt |F|E|X|Ver| Function Length |
+/// +-------+--------+'-'-'-'---'---+-------------------------------+
+/// | Reserved |Ex. Code Words| (Extended Epilogue Count) |
+/// +-------+--------+--------------+-------------------------------+
+///
+/// The format on ARM64 is:
+///
+/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +---------+---------+-+-+---+-----------------------------------+
+/// | C Wrd | Epi Cnt |E|X|Ver| Function Length |
+/// +---------+------+--'-'-'---'---+-------------------------------+
+/// | Reserved |Ex. Code Words| (Extended Epilogue Count) |
+/// +-------+--------+--------------+-------------------------------+
+///
+/// Function Length : 18-bit field indicating the total length of the function
+/// in bytes divided by 2. If a function is larger than
+/// 512KB, then multiple pdata and xdata records must be used.
+/// Vers : 2-bit field describing the version of the remaining structure. Only
+/// version 0 is currently defined (values 1-3 are not permitted).
+/// X : 1-bit field indicating the presence of exception data
+/// E : 1-bit field indicating that the single epilogue is packed into the
+/// header
+/// F : 1-bit field indicating that the record describes a function fragment
+/// (implies that no prologue is present, and prologue processing should be
+/// skipped) (ARM only)
+/// Epilogue Count : 5-bit field that differs in meaning based on the E field.
+///
+/// If E is set, then this field specifies the index of the
+/// first unwind code describing the (only) epilogue.
+///
+/// Otherwise, this field indicates the number of exception
+/// scopes. If more than 31 scopes exist, then this field and
+/// the Code Words field must both be set to 0 to indicate that
+/// an extension word is required.
+/// Code Words : 4-bit (5-bit on ARM64) field that specifies the number of
+/// 32-bit words needed to contain all the unwind codes. If more
+/// than 15 words (31 words on ARM64) are required, then this field
+/// and the Epilogue Count field must both be set to 0 to indicate
+/// that an extension word is required.
+/// Extended Epilogue Count, Extended Code Words :
+/// Valid only if Epilog Count and Code Words are both
+/// set to 0. Provides an 8-bit extended code word
+/// count and 16-bits for epilogue count
+///
+/// The epilogue scope format on ARM is:
+///
+/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +----------------+------+---+---+-------------------------------+
+/// | Ep Start Idx | Cond |Res| Epilogue Start Offset |
+/// +----------------+------+---+-----------------------------------+
+///
+/// The epilogue scope format on ARM64 is:
+///
+/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +-------------------+-------+---+-------------------------------+
+/// | Ep Start Idx | Res | Epilogue Start Offset |
+/// +-------------------+-------+-----------------------------------+
+///
+/// If the E bit is unset in the header, the header is followed by a series of
+/// epilogue scopes, which are sorted by their offset.
+///
+/// Epilogue Start Offset: 18-bit field encoding the offset of epilogue relative
+/// to the start of the function in bytes divided by two
+/// Res : 2-bit field reserved for future expansion (must be set to 0)
+/// Condition : (ARM only) 4-bit field providing the condition under which the
+/// epilogue is executed. Unconditional epilogues should set this
+/// field to 0xe. Epilogues must be entirely conditional or
+/// unconditional, and in Thumb-2 mode. The epilogue begins with
+/// the first instruction after the IT opcode.
+/// Epilogue Start Index : 8-bit field indicating the byte index of the first
+/// unwind code describing the epilogue
+///
+/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +---------------+---------------+---------------+---------------+
+/// | Unwind Code 3 | Unwind Code 2 | Unwind Code 1 | Unwind Code 0 |
+/// +---------------+---------------+---------------+---------------+
+///
+/// Following the epilogue scopes, the byte code describing the unwinding
+/// follows. This is padded to align up to word alignment. Bytes are stored in
+/// little endian.
+///
+/// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+/// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +---------------------------------------------------------------+
+/// | Exception Handler RVA (requires X = 1) |
+/// +---------------------------------------------------------------+
+/// | (possibly followed by data required for exception handler) |
+/// +---------------------------------------------------------------+
+///
+/// If the X bit is set in the header, the unwind byte code is followed by the
+/// exception handler information. This constants of one Exception Handler RVA
+/// which is the address to the exception handler, followed immediately by the
+/// variable length data associated with the exception handler.
+///
+
+struct EpilogueScope {
+ const support::ulittle32_t ES;
+
+ EpilogueScope(const support::ulittle32_t Data) : ES(Data) {}
+ // Same for both ARM and AArch64.
+ uint32_t EpilogueStartOffset() const {
+ return (ES & 0x0003ffff);
+ }
+
+ // Different implementations for ARM and AArch64.
+ uint8_t ResARM() const {
+ return ((ES & 0x000c0000) >> 18);
+ }
+
+ uint8_t ResAArch64() const {
+ return ((ES & 0x000f0000) >> 18);
+ }
+
+ // Condition is only applicable to ARM.
+ uint8_t Condition() const {
+ return ((ES & 0x00f00000) >> 20);
+ }
+
+ // Different implementations for ARM and AArch64.
+ uint8_t EpilogueStartIndexARM() const {
+ return ((ES & 0xff000000) >> 24);
+ }
+
+ uint16_t EpilogueStartIndexAArch64() const {
+ return ((ES & 0xffc00000) >> 22);
+ }
+};
+
+struct ExceptionDataRecord;
+inline size_t HeaderWords(const ExceptionDataRecord &XR);
+
+struct ExceptionDataRecord {
+ const support::ulittle32_t *Data;
+ bool isAArch64;
+
+ ExceptionDataRecord(const support::ulittle32_t *Data, bool isAArch64) :
+ Data(Data), isAArch64(isAArch64) {}
+
+ uint32_t FunctionLength() const {
+ return (Data[0] & 0x0003ffff);
+ }
+
+ uint32_t FunctionLengthInBytesARM() const {
+ return FunctionLength() << 1;
+ }
+
+ uint32_t FunctionLengthInBytesAArch64() const {
+ return FunctionLength() << 2;
+ }
+
+ uint8_t Vers() const {
+ return (Data[0] & 0x000C0000) >> 18;
+ }
+
+ bool X() const {
+ return ((Data[0] & 0x00100000) >> 20);
+ }
+
+ bool E() const {
+ return ((Data[0] & 0x00200000) >> 21);
+ }
+
+ bool F() const {
+ assert(!isAArch64 && "Fragments are only supported on ARMv7 WinEH");
+ return ((Data[0] & 0x00400000) >> 22);
+ }
+
+ uint16_t EpilogueCount() const {
+ if (HeaderWords(*this) == 1) {
+ if (isAArch64)
+ return (Data[0] & 0x07C00000) >> 22;
+ return (Data[0] & 0x0f800000) >> 23;
+ }
+ return Data[1] & 0x0000ffff;
+ }
+
+ uint8_t CodeWords() const {
+ if (HeaderWords(*this) == 1) {
+ if (isAArch64)
+ return (Data[0] & 0xf8000000) >> 27;
+ return (Data[0] & 0xf0000000) >> 28;
+ }
+ return (Data[1] & 0x00ff0000) >> 16;
+ }
+
+ ArrayRef<support::ulittle32_t> EpilogueScopes() const {
+ assert(E() == 0 && "epilogue scopes are only present when the E bit is 0");
+ size_t Offset = HeaderWords(*this);
+ return ArrayRef(&Data[Offset], EpilogueCount());
+ }
+
+ ArrayRef<uint8_t> UnwindByteCode() const {
+ const size_t Offset = HeaderWords(*this)
+ + (E() ? 0 : EpilogueCount());
+ const uint8_t *ByteCode =
+ reinterpret_cast<const uint8_t *>(&Data[Offset]);
+ return ArrayRef(ByteCode, CodeWords() * sizeof(uint32_t));
+ }
+
+ uint32_t ExceptionHandlerRVA() const {
+ assert(X() && "Exception Handler RVA is only valid if the X bit is set");
+ return Data[HeaderWords(*this) + (E() ? 0 : EpilogueCount()) + CodeWords()];
+ }
+
+ uint32_t ExceptionHandlerParameter() const {
+ assert(X() && "Exception Handler RVA is only valid if the X bit is set");
+ return Data[HeaderWords(*this) + (E() ? 0 : EpilogueCount()) + CodeWords() +
+ 1];
+ }
+};
+
+inline size_t HeaderWords(const ExceptionDataRecord &XR) {
+ if (XR.isAArch64)
+ return (XR.Data[0] & 0xffc00000) ? 1 : 2;
+ return (XR.Data[0] & 0xff800000) ? 1 : 2;
+}
+}
+}
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/AlignOf.h b/contrib/libs/llvm16/include/llvm/Support/AlignOf.h
new file mode 100644
index 00000000000..1521bcebb30
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/AlignOf.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- AlignOf.h - Portable calculation of type alignment -----*- 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 defines the AlignedCharArrayUnion class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ALIGNOF_H
+#define LLVM_SUPPORT_ALIGNOF_H
+
+#include <type_traits>
+
+namespace llvm {
+
+/// A suitably aligned and sized character array member which can hold elements
+/// of any type.
+///
+/// This template is equivalent to std::aligned_union_t<1, ...>, but we cannot
+/// use it due to a bug in the MSVC x86 compiler:
+/// https://github.com/microsoft/STL/issues/1533
+/// Using `alignas` here works around the bug.
+template <typename T, typename... Ts> struct AlignedCharArrayUnion {
+ using AlignedUnion = std::aligned_union_t<1, T, Ts...>;
+ alignas(alignof(AlignedUnion)) char buffer[sizeof(AlignedUnion)];
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ALIGNOF_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Alignment.h b/contrib/libs/llvm16/include/llvm/Support/Alignment.h
new file mode 100644
index 00000000000..e2db67159f8
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Alignment.h
@@ -0,0 +1,338 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/Alignment.h - Useful alignment functions ---*- 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 types to represent alignments.
+// They are instrumented to guarantee some invariants are preserved and prevent
+// invalid manipulations.
+//
+// - Align represents an alignment in bytes, it is always set and always a valid
+// power of two, its minimum value is 1 which means no alignment requirements.
+//
+// - MaybeAlign is an optional type, it may be undefined or set. When it's set
+// you can get the underlying Align type by using the getValue() method.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ALIGNMENT_H_
+#define LLVM_SUPPORT_ALIGNMENT_H_
+
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <optional>
+#ifndef NDEBUG
+#include <string>
+#endif // NDEBUG
+
+namespace llvm {
+
+#define ALIGN_CHECK_ISPOSITIVE(decl) \
+ assert(decl > 0 && (#decl " should be defined"))
+
+/// This struct is a compact representation of a valid (non-zero power of two)
+/// alignment.
+/// It is suitable for use as static global constants.
+struct Align {
+private:
+ uint8_t ShiftValue = 0; /// The log2 of the required alignment.
+ /// ShiftValue is less than 64 by construction.
+
+ friend struct MaybeAlign;
+ friend unsigned Log2(Align);
+ friend bool operator==(Align Lhs, Align Rhs);
+ friend bool operator!=(Align Lhs, Align Rhs);
+ friend bool operator<=(Align Lhs, Align Rhs);
+ friend bool operator>=(Align Lhs, Align Rhs);
+ friend bool operator<(Align Lhs, Align Rhs);
+ friend bool operator>(Align Lhs, Align Rhs);
+ friend unsigned encode(struct MaybeAlign A);
+ friend struct MaybeAlign decodeMaybeAlign(unsigned Value);
+
+ /// A trivial type to allow construction of constexpr Align.
+ /// This is currently needed to workaround a bug in GCC 5.3 which prevents
+ /// definition of constexpr assign operators.
+ /// https://stackoverflow.com/questions/46756288/explicitly-defaulted-function-cannot-be-declared-as-constexpr-because-the-implic
+ /// FIXME: Remove this, make all assign operators constexpr and introduce user
+ /// defined literals when we don't have to support GCC 5.3 anymore.
+ /// https://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain
+ struct LogValue {
+ uint8_t Log;
+ };
+
+public:
+ /// Default is byte-aligned.
+ constexpr Align() = default;
+ /// Do not perform checks in case of copy/move construct/assign, because the
+ /// checks have been performed when building `Other`.
+ constexpr Align(const Align &Other) = default;
+ constexpr Align(Align &&Other) = default;
+ Align &operator=(const Align &Other) = default;
+ Align &operator=(Align &&Other) = default;
+
+ explicit Align(uint64_t Value) {
+ assert(Value > 0 && "Value must not be 0");
+ assert(llvm::isPowerOf2_64(Value) && "Alignment is not a power of 2");
+ ShiftValue = Log2_64(Value);
+ assert(ShiftValue < 64 && "Broken invariant");
+ }
+
+ /// This is a hole in the type system and should not be abused.
+ /// Needed to interact with C for instance.
+ uint64_t value() const { return uint64_t(1) << ShiftValue; }
+
+ // Returns the previous alignment.
+ Align previous() const {
+ assert(ShiftValue != 0 && "Undefined operation");
+ Align Out;
+ Out.ShiftValue = ShiftValue - 1;
+ return Out;
+ }
+
+ /// Allow constructions of constexpr Align.
+ template <size_t kValue> constexpr static Align Constant() {
+ return LogValue{static_cast<uint8_t>(CTLog2<kValue>())};
+ }
+
+ /// Allow constructions of constexpr Align from types.
+ /// Compile time equivalent to Align(alignof(T)).
+ template <typename T> constexpr static Align Of() {
+ return Constant<std::alignment_of<T>::value>();
+ }
+
+ /// Constexpr constructor from LogValue type.
+ constexpr Align(LogValue CA) : ShiftValue(CA.Log) {}
+};
+
+/// Treats the value 0 as a 1, so Align is always at least 1.
+inline Align assumeAligned(uint64_t Value) {
+ return Value ? Align(Value) : Align();
+}
+
+/// This struct is a compact representation of a valid (power of two) or
+/// undefined (0) alignment.
+struct MaybeAlign : public std::optional<Align> {
+private:
+ using UP = std::optional<Align>;
+
+public:
+ /// Default is undefined.
+ MaybeAlign() = default;
+ /// Do not perform checks in case of copy/move construct/assign, because the
+ /// checks have been performed when building `Other`.
+ MaybeAlign(const MaybeAlign &Other) = default;
+ MaybeAlign &operator=(const MaybeAlign &Other) = default;
+ MaybeAlign(MaybeAlign &&Other) = default;
+ MaybeAlign &operator=(MaybeAlign &&Other) = default;
+
+ constexpr MaybeAlign(std::nullopt_t None) : UP(None) {}
+ constexpr MaybeAlign(Align Value) : UP(Value) {}
+ explicit MaybeAlign(uint64_t Value) {
+ assert((Value == 0 || llvm::isPowerOf2_64(Value)) &&
+ "Alignment is neither 0 nor a power of 2");
+ if (Value)
+ emplace(Value);
+ }
+
+ /// For convenience, returns a valid alignment or 1 if undefined.
+ Align valueOrOne() const { return value_or(Align()); }
+};
+
+/// Checks that SizeInBytes is a multiple of the alignment.
+inline bool isAligned(Align Lhs, uint64_t SizeInBytes) {
+ return SizeInBytes % Lhs.value() == 0;
+}
+
+/// Checks that Addr is a multiple of the alignment.
+inline bool isAddrAligned(Align Lhs, const void *Addr) {
+ return isAligned(Lhs, reinterpret_cast<uintptr_t>(Addr));
+}
+
+/// Returns a multiple of A needed to store `Size` bytes.
+inline uint64_t alignTo(uint64_t Size, Align A) {
+ const uint64_t Value = A.value();
+ // The following line is equivalent to `(Size + Value - 1) / Value * Value`.
+
+ // The division followed by a multiplication can be thought of as a right
+ // shift followed by a left shift which zeros out the extra bits produced in
+ // the bump; `~(Value - 1)` is a mask where all those bits being zeroed out
+ // are just zero.
+
+ // Most compilers can generate this code but the pattern may be missed when
+ // multiple functions gets inlined.
+ return (Size + Value - 1) & ~(Value - 1U);
+}
+
+/// If non-zero \p Skew is specified, the return value will be a minimal integer
+/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for
+/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p
+/// Skew mod \p A'.
+///
+/// Examples:
+/// \code
+/// alignTo(5, Align(8), 7) = 7
+/// alignTo(17, Align(8), 1) = 17
+/// alignTo(~0LL, Align(8), 3) = 3
+/// \endcode
+inline uint64_t alignTo(uint64_t Size, Align A, uint64_t Skew) {
+ const uint64_t Value = A.value();
+ Skew %= Value;
+ return alignTo(Size - Skew, A) + Skew;
+}
+
+/// Aligns `Addr` to `Alignment` bytes, rounding up.
+inline uintptr_t alignAddr(const void *Addr, Align Alignment) {
+ uintptr_t ArithAddr = reinterpret_cast<uintptr_t>(Addr);
+ assert(static_cast<uintptr_t>(ArithAddr + Alignment.value() - 1) >=
+ ArithAddr &&
+ "Overflow");
+ return alignTo(ArithAddr, Alignment);
+}
+
+/// Returns the offset to the next integer (mod 2**64) that is greater than
+/// or equal to \p Value and is a multiple of \p Align.
+inline uint64_t offsetToAlignment(uint64_t Value, Align Alignment) {
+ return alignTo(Value, Alignment) - Value;
+}
+
+/// Returns the necessary adjustment for aligning `Addr` to `Alignment`
+/// bytes, rounding up.
+inline uint64_t offsetToAlignedAddr(const void *Addr, Align Alignment) {
+ return offsetToAlignment(reinterpret_cast<uintptr_t>(Addr), Alignment);
+}
+
+/// Returns the log2 of the alignment.
+inline unsigned Log2(Align A) { return A.ShiftValue; }
+
+/// Returns the alignment that satisfies both alignments.
+/// Same semantic as MinAlign.
+inline Align commonAlignment(Align A, uint64_t Offset) {
+ return Align(MinAlign(A.value(), Offset));
+}
+
+/// Returns a representation of the alignment that encodes undefined as 0.
+inline unsigned encode(MaybeAlign A) { return A ? A->ShiftValue + 1 : 0; }
+
+/// Dual operation of the encode function above.
+inline MaybeAlign decodeMaybeAlign(unsigned Value) {
+ if (Value == 0)
+ return MaybeAlign();
+ Align Out;
+ Out.ShiftValue = Value - 1;
+ return Out;
+}
+
+/// Returns a representation of the alignment, the encoded value is positive by
+/// definition.
+inline unsigned encode(Align A) { return encode(MaybeAlign(A)); }
+
+/// Comparisons between Align and scalars. Rhs must be positive.
+inline bool operator==(Align Lhs, uint64_t Rhs) {
+ ALIGN_CHECK_ISPOSITIVE(Rhs);
+ return Lhs.value() == Rhs;
+}
+inline bool operator!=(Align Lhs, uint64_t Rhs) {
+ ALIGN_CHECK_ISPOSITIVE(Rhs);
+ return Lhs.value() != Rhs;
+}
+inline bool operator<=(Align Lhs, uint64_t Rhs) {
+ ALIGN_CHECK_ISPOSITIVE(Rhs);
+ return Lhs.value() <= Rhs;
+}
+inline bool operator>=(Align Lhs, uint64_t Rhs) {
+ ALIGN_CHECK_ISPOSITIVE(Rhs);
+ return Lhs.value() >= Rhs;
+}
+inline bool operator<(Align Lhs, uint64_t Rhs) {
+ ALIGN_CHECK_ISPOSITIVE(Rhs);
+ return Lhs.value() < Rhs;
+}
+inline bool operator>(Align Lhs, uint64_t Rhs) {
+ ALIGN_CHECK_ISPOSITIVE(Rhs);
+ return Lhs.value() > Rhs;
+}
+
+/// Comparisons operators between Align.
+inline bool operator==(Align Lhs, Align Rhs) {
+ return Lhs.ShiftValue == Rhs.ShiftValue;
+}
+inline bool operator!=(Align Lhs, Align Rhs) {
+ return Lhs.ShiftValue != Rhs.ShiftValue;
+}
+inline bool operator<=(Align Lhs, Align Rhs) {
+ return Lhs.ShiftValue <= Rhs.ShiftValue;
+}
+inline bool operator>=(Align Lhs, Align Rhs) {
+ return Lhs.ShiftValue >= Rhs.ShiftValue;
+}
+inline bool operator<(Align Lhs, Align Rhs) {
+ return Lhs.ShiftValue < Rhs.ShiftValue;
+}
+inline bool operator>(Align Lhs, Align Rhs) {
+ return Lhs.ShiftValue > Rhs.ShiftValue;
+}
+
+// Don't allow relational comparisons with MaybeAlign.
+bool operator<=(Align Lhs, MaybeAlign Rhs) = delete;
+bool operator>=(Align Lhs, MaybeAlign Rhs) = delete;
+bool operator<(Align Lhs, MaybeAlign Rhs) = delete;
+bool operator>(Align Lhs, MaybeAlign Rhs) = delete;
+
+bool operator<=(MaybeAlign Lhs, Align Rhs) = delete;
+bool operator>=(MaybeAlign Lhs, Align Rhs) = delete;
+bool operator<(MaybeAlign Lhs, Align Rhs) = delete;
+bool operator>(MaybeAlign Lhs, Align Rhs) = delete;
+
+bool operator<=(MaybeAlign Lhs, MaybeAlign Rhs) = delete;
+bool operator>=(MaybeAlign Lhs, MaybeAlign Rhs) = delete;
+bool operator<(MaybeAlign Lhs, MaybeAlign Rhs) = delete;
+bool operator>(MaybeAlign Lhs, MaybeAlign Rhs) = delete;
+
+// Allow equality comparisons between Align and MaybeAlign.
+inline bool operator==(MaybeAlign Lhs, Align Rhs) { return Lhs && *Lhs == Rhs; }
+inline bool operator!=(MaybeAlign Lhs, Align Rhs) { return !(Lhs == Rhs); }
+inline bool operator==(Align Lhs, MaybeAlign Rhs) { return Rhs == Lhs; }
+inline bool operator!=(Align Lhs, MaybeAlign Rhs) { return !(Rhs == Lhs); }
+// Allow equality comparisons with MaybeAlign.
+inline bool operator==(MaybeAlign Lhs, MaybeAlign Rhs) {
+ return (Lhs && Rhs && (*Lhs == *Rhs)) || (!Lhs && !Rhs);
+}
+inline bool operator!=(MaybeAlign Lhs, MaybeAlign Rhs) { return !(Lhs == Rhs); }
+// Allow equality comparisons with std::nullopt.
+inline bool operator==(MaybeAlign Lhs, std::nullopt_t) { return !bool(Lhs); }
+inline bool operator!=(MaybeAlign Lhs, std::nullopt_t) { return bool(Lhs); }
+inline bool operator==(std::nullopt_t, MaybeAlign Rhs) { return !bool(Rhs); }
+inline bool operator!=(std::nullopt_t, MaybeAlign Rhs) { return bool(Rhs); }
+
+#ifndef NDEBUG
+// For usage in LLVM_DEBUG macros.
+inline std::string DebugStr(const Align &A) {
+ return std::to_string(A.value());
+}
+// For usage in LLVM_DEBUG macros.
+inline std::string DebugStr(const MaybeAlign &MA) {
+ if (MA)
+ return std::to_string(MA->value());
+ return "None";
+}
+#endif // NDEBUG
+
+#undef ALIGN_CHECK_ISPOSITIVE
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_ALIGNMENT_H_
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Allocator.h b/contrib/libs/llvm16/include/llvm/Support/Allocator.h
new file mode 100644
index 00000000000..ed2920c8b9e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Allocator.h
@@ -0,0 +1,465 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- Allocator.h - Simple memory allocation abstraction -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines the BumpPtrAllocator interface. BumpPtrAllocator conforms
+/// to the LLVM "Allocator" concept and is similar to MallocAllocator, but
+/// objects cannot be deallocated. Their lifetime is tied to the lifetime of the
+/// allocator.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ALLOCATOR_H
+#define LLVM_SUPPORT_ALLOCATOR_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/AllocatorBase.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+#include <optional>
+#include <utility>
+
+namespace llvm {
+
+namespace detail {
+
+// We call out to an external function to actually print the message as the
+// printing code uses Allocator.h in its implementation.
+void printBumpPtrAllocatorStats(unsigned NumSlabs, size_t BytesAllocated,
+ size_t TotalMemory);
+
+} // end namespace detail
+
+/// Allocate memory in an ever growing pool, as if by bump-pointer.
+///
+/// This isn't strictly a bump-pointer allocator as it uses backing slabs of
+/// memory rather than relying on a boundless contiguous heap. However, it has
+/// bump-pointer semantics in that it is a monotonically growing pool of memory
+/// where every allocation is found by merely allocating the next N bytes in
+/// the slab, or the next N bytes in the next slab.
+///
+/// Note that this also has a threshold for forcing allocations above a certain
+/// size into their own slab.
+///
+/// The BumpPtrAllocatorImpl template defaults to using a MallocAllocator
+/// object, which wraps malloc, to allocate memory, but it can be changed to
+/// use a custom allocator.
+///
+/// The GrowthDelay specifies after how many allocated slabs the allocator
+/// increases the size of the slabs.
+template <typename AllocatorT = MallocAllocator, size_t SlabSize = 4096,
+ size_t SizeThreshold = SlabSize, size_t GrowthDelay = 128>
+class BumpPtrAllocatorImpl
+ : public AllocatorBase<BumpPtrAllocatorImpl<AllocatorT, SlabSize,
+ SizeThreshold, GrowthDelay>>,
+ private detail::AllocatorHolder<AllocatorT> {
+ using AllocTy = detail::AllocatorHolder<AllocatorT>;
+
+public:
+ static_assert(SizeThreshold <= SlabSize,
+ "The SizeThreshold must be at most the SlabSize to ensure "
+ "that objects larger than a slab go into their own memory "
+ "allocation.");
+ static_assert(GrowthDelay > 0,
+ "GrowthDelay must be at least 1 which already increases the"
+ "slab size after each allocated slab.");
+
+ BumpPtrAllocatorImpl() = default;
+
+ template <typename T>
+ BumpPtrAllocatorImpl(T &&Allocator)
+ : AllocTy(std::forward<T &&>(Allocator)) {}
+
+ // Manually implement a move constructor as we must clear the old allocator's
+ // slabs as a matter of correctness.
+ BumpPtrAllocatorImpl(BumpPtrAllocatorImpl &&Old)
+ : AllocTy(std::move(Old.getAllocator())), CurPtr(Old.CurPtr),
+ End(Old.End), Slabs(std::move(Old.Slabs)),
+ CustomSizedSlabs(std::move(Old.CustomSizedSlabs)),
+ BytesAllocated(Old.BytesAllocated), RedZoneSize(Old.RedZoneSize) {
+ Old.CurPtr = Old.End = nullptr;
+ Old.BytesAllocated = 0;
+ Old.Slabs.clear();
+ Old.CustomSizedSlabs.clear();
+ }
+
+ ~BumpPtrAllocatorImpl() {
+ DeallocateSlabs(Slabs.begin(), Slabs.end());
+ DeallocateCustomSizedSlabs();
+ }
+
+ BumpPtrAllocatorImpl &operator=(BumpPtrAllocatorImpl &&RHS) {
+ DeallocateSlabs(Slabs.begin(), Slabs.end());
+ DeallocateCustomSizedSlabs();
+
+ CurPtr = RHS.CurPtr;
+ End = RHS.End;
+ BytesAllocated = RHS.BytesAllocated;
+ RedZoneSize = RHS.RedZoneSize;
+ Slabs = std::move(RHS.Slabs);
+ CustomSizedSlabs = std::move(RHS.CustomSizedSlabs);
+ AllocTy::operator=(std::move(RHS.getAllocator()));
+
+ RHS.CurPtr = RHS.End = nullptr;
+ RHS.BytesAllocated = 0;
+ RHS.Slabs.clear();
+ RHS.CustomSizedSlabs.clear();
+ return *this;
+ }
+
+ /// Deallocate all but the current slab and reset the current pointer
+ /// to the beginning of it, freeing all memory allocated so far.
+ void Reset() {
+ // Deallocate all but the first slab, and deallocate all custom-sized slabs.
+ DeallocateCustomSizedSlabs();
+ CustomSizedSlabs.clear();
+
+ if (Slabs.empty())
+ return;
+
+ // Reset the state.
+ BytesAllocated = 0;
+ CurPtr = (char *)Slabs.front();
+ End = CurPtr + SlabSize;
+
+ __asan_poison_memory_region(*Slabs.begin(), computeSlabSize(0));
+ DeallocateSlabs(std::next(Slabs.begin()), Slabs.end());
+ Slabs.erase(std::next(Slabs.begin()), Slabs.end());
+ }
+
+ /// Allocate space at the specified alignment.
+ // This method is *not* marked noalias, because
+ // SpecificBumpPtrAllocator::DestroyAll() loops over all allocations, and
+ // that loop is not based on the Allocate() return value.
+ //
+ // Allocate(0, N) is valid, it returns a non-null pointer (which should not
+ // be dereferenced).
+ LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, Align Alignment) {
+ // Keep track of how many bytes we've allocated.
+ BytesAllocated += Size;
+
+ size_t Adjustment = offsetToAlignedAddr(CurPtr, Alignment);
+ assert(Adjustment + Size >= Size && "Adjustment + Size must not overflow");
+
+ size_t SizeToAllocate = Size;
+#if LLVM_ADDRESS_SANITIZER_BUILD
+ // Add trailing bytes as a "red zone" under ASan.
+ SizeToAllocate += RedZoneSize;
+#endif
+
+ // Check if we have enough space.
+ if (Adjustment + SizeToAllocate <= size_t(End - CurPtr)
+ // We can't return nullptr even for a zero-sized allocation!
+ && CurPtr != nullptr) {
+ char *AlignedPtr = CurPtr + Adjustment;
+ CurPtr = AlignedPtr + SizeToAllocate;
+ // Update the allocation point of this memory block in MemorySanitizer.
+ // Without this, MemorySanitizer messages for values originated from here
+ // will point to the allocation of the entire slab.
+ __msan_allocated_memory(AlignedPtr, Size);
+ // Similarly, tell ASan about this space.
+ __asan_unpoison_memory_region(AlignedPtr, Size);
+ return AlignedPtr;
+ }
+
+ // If Size is really big, allocate a separate slab for it.
+ size_t PaddedSize = SizeToAllocate + Alignment.value() - 1;
+ if (PaddedSize > SizeThreshold) {
+ void *NewSlab =
+ this->getAllocator().Allocate(PaddedSize, alignof(std::max_align_t));
+ // We own the new slab and don't want anyone reading anyting other than
+ // pieces returned from this method. So poison the whole slab.
+ __asan_poison_memory_region(NewSlab, PaddedSize);
+ CustomSizedSlabs.push_back(std::make_pair(NewSlab, PaddedSize));
+
+ uintptr_t AlignedAddr = alignAddr(NewSlab, Alignment);
+ assert(AlignedAddr + Size <= (uintptr_t)NewSlab + PaddedSize);
+ char *AlignedPtr = (char*)AlignedAddr;
+ __msan_allocated_memory(AlignedPtr, Size);
+ __asan_unpoison_memory_region(AlignedPtr, Size);
+ return AlignedPtr;
+ }
+
+ // Otherwise, start a new slab and try again.
+ StartNewSlab();
+ uintptr_t AlignedAddr = alignAddr(CurPtr, Alignment);
+ assert(AlignedAddr + SizeToAllocate <= (uintptr_t)End &&
+ "Unable to allocate memory!");
+ char *AlignedPtr = (char*)AlignedAddr;
+ CurPtr = AlignedPtr + SizeToAllocate;
+ __msan_allocated_memory(AlignedPtr, Size);
+ __asan_unpoison_memory_region(AlignedPtr, Size);
+ return AlignedPtr;
+ }
+
+ inline LLVM_ATTRIBUTE_RETURNS_NONNULL void *
+ Allocate(size_t Size, size_t Alignment) {
+ assert(Alignment > 0 && "0-byte alignment is not allowed. Use 1 instead.");
+ return Allocate(Size, Align(Alignment));
+ }
+
+ // Pull in base class overloads.
+ using AllocatorBase<BumpPtrAllocatorImpl>::Allocate;
+
+ // Bump pointer allocators are expected to never free their storage; and
+ // clients expect pointers to remain valid for non-dereferencing uses even
+ // after deallocation.
+ void Deallocate(const void *Ptr, size_t Size, size_t /*Alignment*/) {
+ __asan_poison_memory_region(Ptr, Size);
+ }
+
+ // Pull in base class overloads.
+ using AllocatorBase<BumpPtrAllocatorImpl>::Deallocate;
+
+ size_t GetNumSlabs() const { return Slabs.size() + CustomSizedSlabs.size(); }
+
+ /// \return An index uniquely and reproducibly identifying
+ /// an input pointer \p Ptr in the given allocator.
+ /// The returned value is negative iff the object is inside a custom-size
+ /// slab.
+ /// Returns an empty optional if the pointer is not found in the allocator.
+ std::optional<int64_t> identifyObject(const void *Ptr) {
+ const char *P = static_cast<const char *>(Ptr);
+ int64_t InSlabIdx = 0;
+ for (size_t Idx = 0, E = Slabs.size(); Idx < E; Idx++) {
+ const char *S = static_cast<const char *>(Slabs[Idx]);
+ if (P >= S && P < S + computeSlabSize(Idx))
+ return InSlabIdx + static_cast<int64_t>(P - S);
+ InSlabIdx += static_cast<int64_t>(computeSlabSize(Idx));
+ }
+
+ // Use negative index to denote custom sized slabs.
+ int64_t InCustomSizedSlabIdx = -1;
+ for (size_t Idx = 0, E = CustomSizedSlabs.size(); Idx < E; Idx++) {
+ const char *S = static_cast<const char *>(CustomSizedSlabs[Idx].first);
+ size_t Size = CustomSizedSlabs[Idx].second;
+ if (P >= S && P < S + Size)
+ return InCustomSizedSlabIdx - static_cast<int64_t>(P - S);
+ InCustomSizedSlabIdx -= static_cast<int64_t>(Size);
+ }
+ return std::nullopt;
+ }
+
+ /// A wrapper around identifyObject that additionally asserts that
+ /// the object is indeed within the allocator.
+ /// \return An index uniquely and reproducibly identifying
+ /// an input pointer \p Ptr in the given allocator.
+ int64_t identifyKnownObject(const void *Ptr) {
+ std::optional<int64_t> Out = identifyObject(Ptr);
+ assert(Out && "Wrong allocator used");
+ return *Out;
+ }
+
+ /// A wrapper around identifyKnownObject. Accepts type information
+ /// about the object and produces a smaller identifier by relying on
+ /// the alignment information. Note that sub-classes may have different
+ /// alignment, so the most base class should be passed as template parameter
+ /// in order to obtain correct results. For that reason automatic template
+ /// parameter deduction is disabled.
+ /// \return An index uniquely and reproducibly identifying
+ /// an input pointer \p Ptr in the given allocator. This identifier is
+ /// different from the ones produced by identifyObject and
+ /// identifyAlignedObject.
+ template <typename T>
+ int64_t identifyKnownAlignedObject(const void *Ptr) {
+ int64_t Out = identifyKnownObject(Ptr);
+ assert(Out % alignof(T) == 0 && "Wrong alignment information");
+ return Out / alignof(T);
+ }
+
+ size_t getTotalMemory() const {
+ size_t TotalMemory = 0;
+ for (auto I = Slabs.begin(), E = Slabs.end(); I != E; ++I)
+ TotalMemory += computeSlabSize(std::distance(Slabs.begin(), I));
+ for (const auto &PtrAndSize : CustomSizedSlabs)
+ TotalMemory += PtrAndSize.second;
+ return TotalMemory;
+ }
+
+ size_t getBytesAllocated() const { return BytesAllocated; }
+
+ void setRedZoneSize(size_t NewSize) {
+ RedZoneSize = NewSize;
+ }
+
+ void PrintStats() const {
+ detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated,
+ getTotalMemory());
+ }
+
+private:
+ /// The current pointer into the current slab.
+ ///
+ /// This points to the next free byte in the slab.
+ char *CurPtr = nullptr;
+
+ /// The end of the current slab.
+ char *End = nullptr;
+
+ /// The slabs allocated so far.
+ SmallVector<void *, 4> Slabs;
+
+ /// Custom-sized slabs allocated for too-large allocation requests.
+ SmallVector<std::pair<void *, size_t>, 0> CustomSizedSlabs;
+
+ /// How many bytes we've allocated.
+ ///
+ /// Used so that we can compute how much space was wasted.
+ size_t BytesAllocated = 0;
+
+ /// The number of bytes to put between allocations when running under
+ /// a sanitizer.
+ size_t RedZoneSize = 1;
+
+ static size_t computeSlabSize(unsigned SlabIdx) {
+ // Scale the actual allocated slab size based on the number of slabs
+ // allocated. Every GrowthDelay slabs allocated, we double
+ // the allocated size to reduce allocation frequency, but saturate at
+ // multiplying the slab size by 2^30.
+ return SlabSize *
+ ((size_t)1 << std::min<size_t>(30, SlabIdx / GrowthDelay));
+ }
+
+ /// Allocate a new slab and move the bump pointers over into the new
+ /// slab, modifying CurPtr and End.
+ void StartNewSlab() {
+ size_t AllocatedSlabSize = computeSlabSize(Slabs.size());
+
+ void *NewSlab = this->getAllocator().Allocate(AllocatedSlabSize,
+ alignof(std::max_align_t));
+ // We own the new slab and don't want anyone reading anything other than
+ // pieces returned from this method. So poison the whole slab.
+ __asan_poison_memory_region(NewSlab, AllocatedSlabSize);
+
+ Slabs.push_back(NewSlab);
+ CurPtr = (char *)(NewSlab);
+ End = ((char *)NewSlab) + AllocatedSlabSize;
+ }
+
+ /// Deallocate a sequence of slabs.
+ void DeallocateSlabs(SmallVectorImpl<void *>::iterator I,
+ SmallVectorImpl<void *>::iterator E) {
+ for (; I != E; ++I) {
+ size_t AllocatedSlabSize =
+ computeSlabSize(std::distance(Slabs.begin(), I));
+ this->getAllocator().Deallocate(*I, AllocatedSlabSize,
+ alignof(std::max_align_t));
+ }
+ }
+
+ /// Deallocate all memory for custom sized slabs.
+ void DeallocateCustomSizedSlabs() {
+ for (auto &PtrAndSize : CustomSizedSlabs) {
+ void *Ptr = PtrAndSize.first;
+ size_t Size = PtrAndSize.second;
+ this->getAllocator().Deallocate(Ptr, Size, alignof(std::max_align_t));
+ }
+ }
+
+ template <typename T> friend class SpecificBumpPtrAllocator;
+};
+
+/// The standard BumpPtrAllocator which just uses the default template
+/// parameters.
+typedef BumpPtrAllocatorImpl<> BumpPtrAllocator;
+
+/// A BumpPtrAllocator that allows only elements of a specific type to be
+/// allocated.
+///
+/// This allows calling the destructor in DestroyAll() and when the allocator is
+/// destroyed.
+template <typename T> class SpecificBumpPtrAllocator {
+ BumpPtrAllocator Allocator;
+
+public:
+ SpecificBumpPtrAllocator() {
+ // Because SpecificBumpPtrAllocator walks the memory to call destructors,
+ // it can't have red zones between allocations.
+ Allocator.setRedZoneSize(0);
+ }
+ SpecificBumpPtrAllocator(SpecificBumpPtrAllocator &&Old)
+ : Allocator(std::move(Old.Allocator)) {}
+ ~SpecificBumpPtrAllocator() { DestroyAll(); }
+
+ SpecificBumpPtrAllocator &operator=(SpecificBumpPtrAllocator &&RHS) {
+ Allocator = std::move(RHS.Allocator);
+ return *this;
+ }
+
+ /// Call the destructor of each allocated object and deallocate all but the
+ /// current slab and reset the current pointer to the beginning of it, freeing
+ /// all memory allocated so far.
+ void DestroyAll() {
+ auto DestroyElements = [](char *Begin, char *End) {
+ assert(Begin == (char *)alignAddr(Begin, Align::Of<T>()));
+ for (char *Ptr = Begin; Ptr + sizeof(T) <= End; Ptr += sizeof(T))
+ reinterpret_cast<T *>(Ptr)->~T();
+ };
+
+ for (auto I = Allocator.Slabs.begin(), E = Allocator.Slabs.end(); I != E;
+ ++I) {
+ size_t AllocatedSlabSize = BumpPtrAllocator::computeSlabSize(
+ std::distance(Allocator.Slabs.begin(), I));
+ char *Begin = (char *)alignAddr(*I, Align::Of<T>());
+ char *End = *I == Allocator.Slabs.back() ? Allocator.CurPtr
+ : (char *)*I + AllocatedSlabSize;
+
+ DestroyElements(Begin, End);
+ }
+
+ for (auto &PtrAndSize : Allocator.CustomSizedSlabs) {
+ void *Ptr = PtrAndSize.first;
+ size_t Size = PtrAndSize.second;
+ DestroyElements((char *)alignAddr(Ptr, Align::Of<T>()),
+ (char *)Ptr + Size);
+ }
+
+ Allocator.Reset();
+ }
+
+ /// Allocate space for an array of objects without constructing them.
+ T *Allocate(size_t num = 1) { return Allocator.Allocate<T>(num); }
+};
+
+} // end namespace llvm
+
+template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold,
+ size_t GrowthDelay>
+void *
+operator new(size_t Size,
+ llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize, SizeThreshold,
+ GrowthDelay> &Allocator) {
+ return Allocator.Allocate(Size, std::min((size_t)llvm::NextPowerOf2(Size),
+ alignof(std::max_align_t)));
+}
+
+template <typename AllocatorT, size_t SlabSize, size_t SizeThreshold,
+ size_t GrowthDelay>
+void operator delete(void *,
+ llvm::BumpPtrAllocatorImpl<AllocatorT, SlabSize,
+ SizeThreshold, GrowthDelay> &) {
+}
+
+#endif // LLVM_SUPPORT_ALLOCATOR_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/AllocatorBase.h b/contrib/libs/llvm16/include/llvm/Support/AllocatorBase.h
new file mode 100644
index 00000000000..94efa8a3993
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/AllocatorBase.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- AllocatorBase.h - Simple memory allocation abstraction ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines MallocAllocator. MallocAllocator conforms to the LLVM
+/// "Allocator" concept which consists of an Allocate method accepting a size
+/// and alignment, and a Deallocate accepting a pointer and size. Further, the
+/// LLVM "Allocator" concept has overloads of Allocate and Deallocate for
+/// setting size and alignment based on the final type. These overloads are
+/// typically provided by a base class template \c AllocatorBase.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ALLOCATORBASE_H
+#define LLVM_SUPPORT_ALLOCATORBASE_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MemAlloc.h"
+#include <type_traits>
+
+namespace llvm {
+
+/// CRTP base class providing obvious overloads for the core \c
+/// Allocate() methods of LLVM-style allocators.
+///
+/// This base class both documents the full public interface exposed by all
+/// LLVM-style allocators, and redirects all of the overloads to a single core
+/// set of methods which the derived class must define.
+template <typename DerivedT> class AllocatorBase {
+public:
+ /// Allocate \a Size bytes of \a Alignment aligned memory. This method
+ /// must be implemented by \c DerivedT.
+ void *Allocate(size_t Size, size_t Alignment) {
+#ifdef __clang__
+ static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>(
+ &AllocatorBase::Allocate) !=
+ static_cast<void *(DerivedT::*)(size_t, size_t)>(
+ &DerivedT::Allocate),
+ "Class derives from AllocatorBase without implementing the "
+ "core Allocate(size_t, size_t) overload!");
+#endif
+ return static_cast<DerivedT *>(this)->Allocate(Size, Alignment);
+ }
+
+ /// Deallocate \a Ptr to \a Size bytes of memory allocated by this
+ /// allocator.
+ void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
+#ifdef __clang__
+ static_assert(
+ static_cast<void (AllocatorBase::*)(const void *, size_t, size_t)>(
+ &AllocatorBase::Deallocate) !=
+ static_cast<void (DerivedT::*)(const void *, size_t, size_t)>(
+ &DerivedT::Deallocate),
+ "Class derives from AllocatorBase without implementing the "
+ "core Deallocate(void *) overload!");
+#endif
+ return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size, Alignment);
+ }
+
+ // The rest of these methods are helpers that redirect to one of the above
+ // core methods.
+
+ /// Allocate space for a sequence of objects without constructing them.
+ template <typename T> T *Allocate(size_t Num = 1) {
+ return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
+ }
+
+ /// Deallocate space for a sequence of objects without constructing them.
+ template <typename T>
+ std::enable_if_t<!std::is_same<std::remove_cv_t<T>, void>::value, void>
+ Deallocate(T *Ptr, size_t Num = 1) {
+ Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T));
+ }
+};
+
+class MallocAllocator : public AllocatorBase<MallocAllocator> {
+public:
+ void Reset() {}
+
+ LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) {
+ return allocate_buffer(Size, Alignment);
+ }
+
+ // Pull in base class overloads.
+ using AllocatorBase<MallocAllocator>::Allocate;
+
+ void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
+ deallocate_buffer(const_cast<void *>(Ptr), Size, Alignment);
+ }
+
+ // Pull in base class overloads.
+ using AllocatorBase<MallocAllocator>::Deallocate;
+
+ void PrintStats() const {}
+};
+
+namespace detail {
+
+template <typename Alloc> class AllocatorHolder : Alloc {
+public:
+ AllocatorHolder() = default;
+ AllocatorHolder(const Alloc &A) : Alloc(A) {}
+ AllocatorHolder(Alloc &&A) : Alloc(static_cast<Alloc &&>(A)) {}
+ Alloc &getAllocator() { return *this; }
+ const Alloc &getAllocator() const { return *this; }
+};
+
+template <typename Alloc> class AllocatorHolder<Alloc &> {
+ Alloc &A;
+
+public:
+ AllocatorHolder(Alloc &A) : A(A) {}
+ Alloc &getAllocator() { return A; }
+ const Alloc &getAllocator() const { return A; }
+};
+
+} // namespace detail
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_ALLOCATORBASE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ArrayRecycler.h b/contrib/libs/llvm16/include/llvm/Support/ArrayRecycler.h
new file mode 100644
index 00000000000..b77cd88162f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ArrayRecycler.h
@@ -0,0 +1,155 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//==- llvm/Support/ArrayRecycler.h - Recycling of Arrays ---------*- 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 defines the ArrayRecycler class template which can recycle small
+// arrays allocated from one of the allocators in Allocator.h
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ARRAYRECYCLER_H
+#define LLVM_SUPPORT_ARRAYRECYCLER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/MathExtras.h"
+
+namespace llvm {
+
+/// Recycle small arrays allocated from a BumpPtrAllocator.
+///
+/// Arrays are allocated in a small number of fixed sizes. For each supported
+/// array size, the ArrayRecycler keeps a free list of available arrays.
+///
+template <class T, size_t Align = alignof(T)> class ArrayRecycler {
+ // The free list for a given array size is a simple singly linked list.
+ // We can't use iplist or Recycler here since those classes can't be copied.
+ struct FreeList {
+ FreeList *Next;
+ };
+
+ static_assert(Align >= alignof(FreeList), "Object underaligned");
+ static_assert(sizeof(T) >= sizeof(FreeList), "Objects are too small");
+
+ // Keep a free list for each array size.
+ SmallVector<FreeList*, 8> Bucket;
+
+ // Remove an entry from the free list in Bucket[Idx] and return it.
+ // Return NULL if no entries are available.
+ T *pop(unsigned Idx) {
+ if (Idx >= Bucket.size())
+ return nullptr;
+ FreeList *Entry = Bucket[Idx];
+ if (!Entry)
+ return nullptr;
+ __asan_unpoison_memory_region(Entry, Capacity::get(Idx).getSize());
+ Bucket[Idx] = Entry->Next;
+ __msan_allocated_memory(Entry, Capacity::get(Idx).getSize());
+ return reinterpret_cast<T*>(Entry);
+ }
+
+ // Add an entry to the free list at Bucket[Idx].
+ void push(unsigned Idx, T *Ptr) {
+ assert(Ptr && "Cannot recycle NULL pointer");
+ FreeList *Entry = reinterpret_cast<FreeList*>(Ptr);
+ if (Idx >= Bucket.size())
+ Bucket.resize(size_t(Idx) + 1);
+ Entry->Next = Bucket[Idx];
+ Bucket[Idx] = Entry;
+ __asan_poison_memory_region(Ptr, Capacity::get(Idx).getSize());
+ }
+
+public:
+ /// The size of an allocated array is represented by a Capacity instance.
+ ///
+ /// This class is much smaller than a size_t, and it provides methods to work
+ /// with the set of legal array capacities.
+ class Capacity {
+ uint8_t Index;
+ explicit Capacity(uint8_t idx) : Index(idx) {}
+
+ public:
+ Capacity() : Index(0) {}
+
+ /// Get the capacity of an array that can hold at least N elements.
+ static Capacity get(size_t N) {
+ return Capacity(N ? Log2_64_Ceil(N) : 0);
+ }
+
+ /// Get the number of elements in an array with this capacity.
+ size_t getSize() const { return size_t(1u) << Index; }
+
+ /// Get the bucket number for this capacity.
+ unsigned getBucket() const { return Index; }
+
+ /// Get the next larger capacity. Large capacities grow exponentially, so
+ /// this function can be used to reallocate incrementally growing vectors
+ /// in amortized linear time.
+ Capacity getNext() const { return Capacity(Index + 1); }
+ };
+
+ ~ArrayRecycler() {
+ // The client should always call clear() so recycled arrays can be returned
+ // to the allocator.
+ assert(Bucket.empty() && "Non-empty ArrayRecycler deleted!");
+ }
+
+ /// Release all the tracked allocations to the allocator. The recycler must
+ /// be free of any tracked allocations before being deleted.
+ template<class AllocatorType>
+ void clear(AllocatorType &Allocator) {
+ for (; !Bucket.empty(); Bucket.pop_back())
+ while (T *Ptr = pop(Bucket.size() - 1))
+ Allocator.Deallocate(Ptr);
+ }
+
+ /// Special case for BumpPtrAllocator which has an empty Deallocate()
+ /// function.
+ ///
+ /// There is no need to traverse the free lists, pulling all the objects into
+ /// cache.
+ void clear(BumpPtrAllocator&) {
+ Bucket.clear();
+ }
+
+ /// Allocate an array of at least the requested capacity.
+ ///
+ /// Return an existing recycled array, or allocate one from Allocator if
+ /// none are available for recycling.
+ ///
+ template<class AllocatorType>
+ T *allocate(Capacity Cap, AllocatorType &Allocator) {
+ // Try to recycle an existing array.
+ if (T *Ptr = pop(Cap.getBucket()))
+ return Ptr;
+ // Nope, get more memory.
+ return static_cast<T*>(Allocator.Allocate(sizeof(T)*Cap.getSize(), Align));
+ }
+
+ /// Deallocate an array with the specified Capacity.
+ ///
+ /// Cap must be the same capacity that was given to allocate().
+ ///
+ void deallocate(Capacity Cap, T *Ptr) {
+ push(Cap.getBucket(), Ptr);
+ }
+};
+
+} // end llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Atomic.h b/contrib/libs/llvm16/include/llvm/Support/Atomic.h
new file mode 100644
index 00000000000..90cc634249b
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Atomic.h
@@ -0,0 +1,53 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Atomic.h - Atomic Operations -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys atomic operations.
+//
+// DO NOT USE IN NEW CODE!
+//
+// New code should always rely on the std::atomic facilities in C++11.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ATOMIC_H
+#define LLVM_SUPPORT_ATOMIC_H
+
+#include "llvm/Support/DataTypes.h"
+
+// Windows will at times define MemoryFence.
+#ifdef MemoryFence
+#undef MemoryFence
+#endif
+
+namespace llvm {
+ namespace sys {
+ void MemoryFence();
+
+#ifdef _MSC_VER
+ typedef long cas_flag;
+#else
+ typedef uint32_t cas_flag;
+#endif
+ cas_flag CompareAndSwap(volatile cas_flag* ptr,
+ cas_flag new_value,
+ cas_flag old_value);
+ }
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/AtomicOrdering.h b/contrib/libs/llvm16/include/llvm/Support/AtomicOrdering.h
new file mode 100644
index 00000000000..5c76a270e9d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/AtomicOrdering.h
@@ -0,0 +1,173 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/AtomicOrdering.h ---Atomic Ordering---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Atomic ordering constants.
+///
+/// These values are used by LLVM to represent atomic ordering for C++11's
+/// memory model and more, as detailed in docs/Atomics.rst.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ATOMICORDERING_H
+#define LLVM_SUPPORT_ATOMICORDERING_H
+
+#include <cstddef>
+
+namespace llvm {
+
+/// Atomic ordering for C11 / C++11's memory models.
+///
+/// These values cannot change because they are shared with standard library
+/// implementations as well as with other compilers.
+enum class AtomicOrderingCABI {
+ relaxed = 0,
+ consume = 1,
+ acquire = 2,
+ release = 3,
+ acq_rel = 4,
+ seq_cst = 5,
+};
+
+bool operator<(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
+bool operator>(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
+bool operator<=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
+bool operator>=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
+
+// Validate an integral value which isn't known to fit within the enum's range
+// is a valid AtomicOrderingCABI.
+template <typename Int> inline bool isValidAtomicOrderingCABI(Int I) {
+ return (Int)AtomicOrderingCABI::relaxed <= I &&
+ I <= (Int)AtomicOrderingCABI::seq_cst;
+}
+
+/// Atomic ordering for LLVM's memory model.
+///
+/// C++ defines ordering as a lattice. LLVM supplements this with NotAtomic and
+/// Unordered, which are both below the C++ orders.
+///
+/// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst
+/// \-->consume-->acquire--/
+enum class AtomicOrdering : unsigned {
+ NotAtomic = 0,
+ Unordered = 1,
+ Monotonic = 2, // Equivalent to C++'s relaxed.
+ // Consume = 3, // Not specified yet.
+ Acquire = 4,
+ Release = 5,
+ AcquireRelease = 6,
+ SequentiallyConsistent = 7,
+ LAST = SequentiallyConsistent
+};
+
+bool operator<(AtomicOrdering, AtomicOrdering) = delete;
+bool operator>(AtomicOrdering, AtomicOrdering) = delete;
+bool operator<=(AtomicOrdering, AtomicOrdering) = delete;
+bool operator>=(AtomicOrdering, AtomicOrdering) = delete;
+
+// Validate an integral value which isn't known to fit within the enum's range
+// is a valid AtomicOrdering.
+template <typename Int> inline bool isValidAtomicOrdering(Int I) {
+ return static_cast<Int>(AtomicOrdering::NotAtomic) <= I &&
+ I <= static_cast<Int>(AtomicOrdering::SequentiallyConsistent);
+}
+
+/// String used by LLVM IR to represent atomic ordering.
+inline const char *toIRString(AtomicOrdering ao) {
+ static const char *names[8] = {"not_atomic", "unordered", "monotonic",
+ "consume", "acquire", "release",
+ "acq_rel", "seq_cst"};
+ return names[static_cast<size_t>(ao)];
+}
+
+/// Returns true if ao is stronger than other as defined by the AtomicOrdering
+/// lattice, which is based on C++'s definition.
+inline bool isStrongerThan(AtomicOrdering AO, AtomicOrdering Other) {
+ static const bool lookup[8][8] = {
+ // NA UN RX CO AC RE AR SC
+ /* NotAtomic */ {false, false, false, false, false, false, false, false},
+ /* Unordered */ { true, false, false, false, false, false, false, false},
+ /* relaxed */ { true, true, false, false, false, false, false, false},
+ /* consume */ { true, true, true, false, false, false, false, false},
+ /* acquire */ { true, true, true, true, false, false, false, false},
+ /* release */ { true, true, true, false, false, false, false, false},
+ /* acq_rel */ { true, true, true, true, true, true, false, false},
+ /* seq_cst */ { true, true, true, true, true, true, true, false},
+ };
+ return lookup[static_cast<size_t>(AO)][static_cast<size_t>(Other)];
+}
+
+inline bool isAtLeastOrStrongerThan(AtomicOrdering AO, AtomicOrdering Other) {
+ static const bool lookup[8][8] = {
+ // NA UN RX CO AC RE AR SC
+ /* NotAtomic */ { true, false, false, false, false, false, false, false},
+ /* Unordered */ { true, true, false, false, false, false, false, false},
+ /* relaxed */ { true, true, true, false, false, false, false, false},
+ /* consume */ { true, true, true, true, false, false, false, false},
+ /* acquire */ { true, true, true, true, true, false, false, false},
+ /* release */ { true, true, true, false, false, true, false, false},
+ /* acq_rel */ { true, true, true, true, true, true, true, false},
+ /* seq_cst */ { true, true, true, true, true, true, true, true},
+ };
+ return lookup[static_cast<size_t>(AO)][static_cast<size_t>(Other)];
+}
+
+inline bool isStrongerThanUnordered(AtomicOrdering AO) {
+ return isStrongerThan(AO, AtomicOrdering::Unordered);
+}
+
+inline bool isStrongerThanMonotonic(AtomicOrdering AO) {
+ return isStrongerThan(AO, AtomicOrdering::Monotonic);
+}
+
+inline bool isAcquireOrStronger(AtomicOrdering AO) {
+ return isAtLeastOrStrongerThan(AO, AtomicOrdering::Acquire);
+}
+
+inline bool isReleaseOrStronger(AtomicOrdering AO) {
+ return isAtLeastOrStrongerThan(AO, AtomicOrdering::Release);
+}
+
+/// Return a single atomic ordering that is at least as strong as both the \p AO
+/// and \p Other orderings for an atomic operation.
+inline AtomicOrdering getMergedAtomicOrdering(AtomicOrdering AO,
+ AtomicOrdering Other) {
+ if ((AO == AtomicOrdering::Acquire && Other == AtomicOrdering::Release) ||
+ (AO == AtomicOrdering::Release && Other == AtomicOrdering::Acquire))
+ return AtomicOrdering::AcquireRelease;
+ return isStrongerThan(AO, Other) ? AO : Other;
+}
+
+inline AtomicOrderingCABI toCABI(AtomicOrdering AO) {
+ static const AtomicOrderingCABI lookup[8] = {
+ /* NotAtomic */ AtomicOrderingCABI::relaxed,
+ /* Unordered */ AtomicOrderingCABI::relaxed,
+ /* relaxed */ AtomicOrderingCABI::relaxed,
+ /* consume */ AtomicOrderingCABI::consume,
+ /* acquire */ AtomicOrderingCABI::acquire,
+ /* release */ AtomicOrderingCABI::release,
+ /* acq_rel */ AtomicOrderingCABI::acq_rel,
+ /* seq_cst */ AtomicOrderingCABI::seq_cst,
+ };
+ return lookup[static_cast<size_t>(AO)];
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ATOMICORDERING_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/AutoConvert.h b/contrib/libs/llvm16/include/llvm/Support/AutoConvert.h
new file mode 100644
index 00000000000..94fa3f597f5
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/AutoConvert.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- AutoConvert.h - Auto conversion between ASCII/EBCDIC -----*- 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 functions used for auto conversion between
+// ASCII/EBCDIC codepages specific to z/OS.
+//
+//===----------------------------------------------------------------------===//i
+
+#ifndef LLVM_SUPPORT_AUTOCONVERT_H
+#define LLVM_SUPPORT_AUTOCONVERT_H
+
+#ifdef __MVS__
+#define CCSID_IBM_1047 1047
+#define CCSID_UTF_8 1208
+#include <system_error>
+
+namespace llvm {
+
+/// \brief Disable the z/OS enhanced ASCII auto-conversion for the file
+/// descriptor.
+std::error_code disableAutoConversion(int FD);
+
+/// \brief Query the z/OS enhanced ASCII auto-conversion status of a file
+/// descriptor and force the conversion if the file is not tagged with a
+/// codepage.
+std::error_code enableAutoConversion(int FD);
+
+/// \brief Set the tag information for a file descriptor.
+std::error_code setFileTag(int FD, int CCSID, bool Text);
+
+} // namespace llvm
+
+#endif // __MVS__
+
+#endif // LLVM_SUPPORT_AUTOCONVERT_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BCD.h b/contrib/libs/llvm16/include/llvm/Support/BCD.h
new file mode 100644
index 00000000000..6da429546d4
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BCD.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/BCD.h - Binary-Coded Decimal utility functions -*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares some utility functions for encoding/decoding BCD values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BCD_H
+#define LLVM_SUPPORT_BCD_H
+
+#include <assert.h>
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+
+// Decode a packed BCD value.
+// Maximum value of int64_t is 9,223,372,036,854,775,807. These are 18 usable
+// decimal digits. Thus BCD numbers of up to 9 bytes can be converted.
+// Please note that s390 supports BCD numbers up to a length of 16 bytes.
+inline int64_t decodePackedBCD(const uint8_t *Ptr, size_t ByteLen,
+ bool IsSigned = true) {
+ assert(ByteLen >= 1 && ByteLen <= 9 && "Invalid BCD number");
+ int64_t Value = 0;
+ size_t RunLen = ByteLen - static_cast<unsigned>(IsSigned);
+ for (size_t I = 0; I < RunLen; ++I) {
+ uint8_t DecodedByteValue = ((Ptr[I] >> 4) & 0x0f) * 10 + (Ptr[I] & 0x0f);
+ Value = (Value * 100) + DecodedByteValue;
+ }
+ if (IsSigned) {
+ uint8_t DecodedByteValue = (Ptr[ByteLen - 1] >> 4) & 0x0f;
+ uint8_t Sign = Ptr[ByteLen - 1] & 0x0f;
+ Value = (Value * 10) + DecodedByteValue;
+ if (Sign == 0x0d || Sign == 0x0b)
+ Value *= -1;
+ }
+ return Value;
+}
+
+template <typename ResultT, typename ValT>
+inline ResultT decodePackedBCD(const ValT Val, bool IsSigned = true) {
+ return static_cast<ResultT>(decodePackedBCD(
+ reinterpret_cast<const uint8_t *>(&Val), sizeof(ValT), IsSigned));
+}
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_BCD_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BLAKE3.h b/contrib/libs/llvm16/include/llvm/Support/BLAKE3.h
new file mode 100644
index 00000000000..eb38e12052f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BLAKE3.h
@@ -0,0 +1,135 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//==- BLAKE3.h - BLAKE3 C++ wrapper for LLVM ---------------------*- 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 is a C++ wrapper of the BLAKE3 C interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BLAKE3_H
+#define LLVM_SUPPORT_BLAKE3_H
+
+#include "llvm-c/blake3.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+/// The constant \p LLVM_BLAKE3_OUT_LEN provides the default output length,
+/// 32 bytes, which is recommended for most callers.
+///
+/// Outputs shorter than the default length of 32 bytes (256 bits) provide
+/// less security. An N-bit BLAKE3 output is intended to provide N bits of
+/// first and second preimage resistance and N/2 bits of collision
+/// resistance, for any N up to 256. Longer outputs don't provide any
+/// additional security.
+///
+/// Shorter BLAKE3 outputs are prefixes of longer ones. Explicitly
+/// requesting a short output is equivalent to truncating the default-length
+/// output.
+template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
+using BLAKE3Result = std::array<uint8_t, NumBytes>;
+
+/// A class that wraps the BLAKE3 algorithm.
+class BLAKE3 {
+public:
+ BLAKE3() { init(); }
+
+ /// Reinitialize the internal state
+ void init() { llvm_blake3_hasher_init(&Hasher); }
+
+ /// Digest more data.
+ void update(ArrayRef<uint8_t> Data) {
+ llvm_blake3_hasher_update(&Hasher, Data.data(), Data.size());
+ }
+
+ /// Digest more data.
+ void update(StringRef Str) {
+ llvm_blake3_hasher_update(&Hasher, Str.data(), Str.size());
+ }
+
+ /// Finalize the hasher and put the result in \p Result.
+ /// This doesn't modify the hasher itself, and it's possible to finalize again
+ /// after adding more input.
+ template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
+ void final(BLAKE3Result<NumBytes> &Result) {
+ llvm_blake3_hasher_finalize(&Hasher, Result.data(), Result.size());
+ }
+
+ /// Finalize the hasher and return an output of any length, given in bytes.
+ /// This doesn't modify the hasher itself, and it's possible to finalize again
+ /// after adding more input.
+ template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
+ BLAKE3Result<NumBytes> final() {
+ BLAKE3Result<NumBytes> Result;
+ llvm_blake3_hasher_finalize(&Hasher, Result.data(), Result.size());
+ return Result;
+ }
+
+ /// Return the current output for the digested data since the last call to
+ /// init().
+ ///
+ /// Other hash functions distinguish between \p result() and \p final(), with
+ /// \p result() allowing more calls into \p update(), but there's no
+ // difference for the BLAKE3 hash function.
+ template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
+ BLAKE3Result<NumBytes> result() {
+ return final<NumBytes>();
+ }
+
+ /// Returns a BLAKE3 hash for the given data.
+ template <size_t NumBytes = LLVM_BLAKE3_OUT_LEN>
+ static BLAKE3Result<NumBytes> hash(ArrayRef<uint8_t> Data) {
+ BLAKE3 Hasher;
+ Hasher.update(Data);
+ return Hasher.final<NumBytes>();
+ }
+
+private:
+ llvm_blake3_hasher Hasher;
+};
+
+/// Like \p BLAKE3 but using a class-level template parameter for specifying the
+/// hash size of the \p final() and \p result() functions.
+///
+/// This is useful for using BLAKE3 as the hasher type for \p HashBuilder with
+/// non-default hash sizes.
+template <size_t NumBytes> class TruncatedBLAKE3 : public BLAKE3 {
+public:
+ /// Finalize the hasher and put the result in \p Result.
+ /// This doesn't modify the hasher itself, and it's possible to finalize again
+ /// after adding more input.
+ void final(BLAKE3Result<NumBytes> &Result) { return BLAKE3::final(Result); }
+
+ /// Finalize the hasher and return an output of any length, given in bytes.
+ /// This doesn't modify the hasher itself, and it's possible to finalize again
+ /// after adding more input.
+ BLAKE3Result<NumBytes> final() { return BLAKE3::final<NumBytes>(); }
+
+ /// Return the current output for the digested data since the last call to
+ /// init().
+ ///
+ /// Other hash functions distinguish between \p result() and \p final(), with
+ /// \p result() allowing more calls into \p update(), but there's no
+ // difference for the BLAKE3 hash function.
+ BLAKE3Result<NumBytes> result() { return BLAKE3::result<NumBytes>(); }
+};
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Base64.h b/contrib/libs/llvm16/include/llvm/Support/Base64.h
new file mode 100644
index 00000000000..7a3781249a9
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Base64.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- Base64.h - Base64 Encoder/Decoder ----------------------*- 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 provides generic base64 encoder/decoder.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BASE64_H
+#define LLVM_SUPPORT_BASE64_H
+
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+template <class InputBytes> std::string encodeBase64(InputBytes const &Bytes) {
+ static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ std::string Buffer;
+ Buffer.resize(((Bytes.size() + 2) / 3) * 4);
+
+ size_t i = 0, j = 0;
+ for (size_t n = Bytes.size() / 3 * 3; i < n; i += 3, j += 4) {
+ uint32_t x = ((unsigned char)Bytes[i] << 16) |
+ ((unsigned char)Bytes[i + 1] << 8) |
+ (unsigned char)Bytes[i + 2];
+ Buffer[j + 0] = Table[(x >> 18) & 63];
+ Buffer[j + 1] = Table[(x >> 12) & 63];
+ Buffer[j + 2] = Table[(x >> 6) & 63];
+ Buffer[j + 3] = Table[x & 63];
+ }
+ if (i + 1 == Bytes.size()) {
+ uint32_t x = ((unsigned char)Bytes[i] << 16);
+ Buffer[j + 0] = Table[(x >> 18) & 63];
+ Buffer[j + 1] = Table[(x >> 12) & 63];
+ Buffer[j + 2] = '=';
+ Buffer[j + 3] = '=';
+ } else if (i + 2 == Bytes.size()) {
+ uint32_t x =
+ ((unsigned char)Bytes[i] << 16) | ((unsigned char)Bytes[i + 1] << 8);
+ Buffer[j + 0] = Table[(x >> 18) & 63];
+ Buffer[j + 1] = Table[(x >> 12) & 63];
+ Buffer[j + 2] = Table[(x >> 6) & 63];
+ Buffer[j + 3] = '=';
+ }
+ return Buffer;
+}
+
+llvm::Error decodeBase64(llvm::StringRef Input, std::vector<char> &Output);
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BinaryByteStream.h b/contrib/libs/llvm16/include/llvm/Support/BinaryByteStream.h
new file mode 100644
index 00000000000..9f256329340
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BinaryByteStream.h
@@ -0,0 +1,281 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BinaryByteStream.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//===----------------------------------------------------------------------===//
+// A BinaryStream which stores data in a single continguous memory buffer.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
+#define LLVM_SUPPORT_BINARYBYTESTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <cstdint>
+#include <cstring>
+#include <memory>
+
+namespace llvm {
+
+/// An implementation of BinaryStream which holds its entire data set
+/// in a single contiguous buffer. BinaryByteStream guarantees that no read
+/// operation will ever incur a copy. Note that BinaryByteStream does not
+/// own the underlying buffer.
+class BinaryByteStream : public BinaryStream {
+public:
+ BinaryByteStream() = default;
+ BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian)
+ : Endian(Endian), Data(Data) {}
+ BinaryByteStream(StringRef Data, llvm::support::endianness Endian)
+ : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {}
+
+ llvm::support::endianness getEndian() const override { return Endian; }
+
+ Error readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffsetForRead(Offset, Size))
+ return EC;
+ Buffer = Data.slice(Offset, Size);
+ return Error::success();
+ }
+
+ Error readLongestContiguousChunk(uint64_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffsetForRead(Offset, 1))
+ return EC;
+ Buffer = Data.slice(Offset);
+ return Error::success();
+ }
+
+ uint64_t getLength() override { return Data.size(); }
+
+ ArrayRef<uint8_t> data() const { return Data; }
+
+ StringRef str() const {
+ const char *CharData = reinterpret_cast<const char *>(Data.data());
+ return StringRef(CharData, Data.size());
+ }
+
+protected:
+ llvm::support::endianness Endian;
+ ArrayRef<uint8_t> Data;
+};
+
+/// An implementation of BinaryStream whose data is backed by an llvm
+/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in
+/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream
+/// will never cause a copy.
+class MemoryBufferByteStream : public BinaryByteStream {
+public:
+ MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
+ llvm::support::endianness Endian)
+ : BinaryByteStream(Buffer->getBuffer(), Endian),
+ MemBuffer(std::move(Buffer)) {}
+
+ std::unique_ptr<MemoryBuffer> MemBuffer;
+};
+
+/// An implementation of BinaryStream which holds its entire data set
+/// in a single contiguous buffer. As with BinaryByteStream, the mutable
+/// version also guarantees that no read operation will ever incur a copy,
+/// and similarly it does not own the underlying buffer.
+class MutableBinaryByteStream : public WritableBinaryStream {
+public:
+ MutableBinaryByteStream() = default;
+ MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
+ llvm::support::endianness Endian)
+ : Data(Data), ImmutableStream(Data, Endian) {}
+
+ llvm::support::endianness getEndian() const override {
+ return ImmutableStream.getEndian();
+ }
+
+ Error readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ return ImmutableStream.readBytes(Offset, Size, Buffer);
+ }
+
+ Error readLongestContiguousChunk(uint64_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
+ }
+
+ uint64_t getLength() override { return ImmutableStream.getLength(); }
+
+ Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Buffer) override {
+ if (Buffer.empty())
+ return Error::success();
+
+ if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
+ return EC;
+
+ uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
+ ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
+ return Error::success();
+ }
+
+ Error commit() override { return Error::success(); }
+
+ MutableArrayRef<uint8_t> data() const { return Data; }
+
+private:
+ MutableArrayRef<uint8_t> Data;
+ BinaryByteStream ImmutableStream;
+};
+
+/// An implementation of WritableBinaryStream which can write at its end
+/// causing the underlying data to grow. This class owns the underlying data.
+class AppendingBinaryByteStream : public WritableBinaryStream {
+ std::vector<uint8_t> Data;
+ llvm::support::endianness Endian = llvm::support::little;
+
+public:
+ AppendingBinaryByteStream() = default;
+ AppendingBinaryByteStream(llvm::support::endianness Endian)
+ : Endian(Endian) {}
+
+ void clear() { Data.clear(); }
+
+ llvm::support::endianness getEndian() const override { return Endian; }
+
+ Error readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
+ return EC;
+
+ Buffer = ArrayRef(Data).slice(Offset, Size);
+ return Error::success();
+ }
+
+ void insert(uint64_t Offset, ArrayRef<uint8_t> Bytes) {
+ Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
+ }
+
+ Error readLongestContiguousChunk(uint64_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ if (auto EC = checkOffsetForWrite(Offset, 1))
+ return EC;
+
+ Buffer = ArrayRef(Data).slice(Offset);
+ return Error::success();
+ }
+
+ uint64_t getLength() override { return Data.size(); }
+
+ Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Buffer) override {
+ if (Buffer.empty())
+ return Error::success();
+
+ // This is well-defined for any case except where offset is strictly
+ // greater than the current length. If offset is equal to the current
+ // length, we can still grow. If offset is beyond the current length, we
+ // would have to decide how to deal with the intermediate uninitialized
+ // bytes. So we punt on that case for simplicity and just say it's an
+ // error.
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+
+ uint64_t RequiredSize = Offset + Buffer.size();
+ if (RequiredSize > Data.size())
+ Data.resize(RequiredSize);
+
+ ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
+ return Error::success();
+ }
+
+ Error commit() override { return Error::success(); }
+
+ /// Return the properties of this stream.
+ BinaryStreamFlags getFlags() const override { return BSF_Write | BSF_Append; }
+
+ MutableArrayRef<uint8_t> data() { return Data; }
+};
+
+/// An implementation of WritableBinaryStream backed by an llvm
+/// FileOutputBuffer.
+class FileBufferByteStream : public WritableBinaryStream {
+private:
+ class StreamImpl : public MutableBinaryByteStream {
+ public:
+ StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
+ llvm::support::endianness Endian)
+ : MutableBinaryByteStream(
+ MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
+ Buffer->getBufferEnd()),
+ Endian),
+ FileBuffer(std::move(Buffer)) {}
+
+ Error commit() override {
+ if (FileBuffer->commit())
+ return make_error<BinaryStreamError>(
+ stream_error_code::filesystem_error);
+ return Error::success();
+ }
+
+ /// Returns a pointer to the start of the buffer.
+ uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
+
+ /// Returns a pointer to the end of the buffer.
+ uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
+
+ private:
+ std::unique_ptr<FileOutputBuffer> FileBuffer;
+ };
+
+public:
+ FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
+ llvm::support::endianness Endian)
+ : Impl(std::move(Buffer), Endian) {}
+
+ llvm::support::endianness getEndian() const override {
+ return Impl.getEndian();
+ }
+
+ Error readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ return Impl.readBytes(Offset, Size, Buffer);
+ }
+
+ Error readLongestContiguousChunk(uint64_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ return Impl.readLongestContiguousChunk(Offset, Buffer);
+ }
+
+ uint64_t getLength() override { return Impl.getLength(); }
+
+ Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Data) override {
+ return Impl.writeBytes(Offset, Data);
+ }
+
+ Error commit() override { return Impl.commit(); }
+
+ /// Returns a pointer to the start of the buffer.
+ uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
+
+ /// Returns a pointer to the end of the buffer.
+ uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
+
+private:
+ StreamImpl Impl;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYBYTESTREAM_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BinaryItemStream.h b/contrib/libs/llvm16/include/llvm/Support/BinaryItemStream.h
new file mode 100644
index 00000000000..acb3235a806
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BinaryItemStream.h
@@ -0,0 +1,117 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BinaryItemStream.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYITEMSTREAM_H
+#define LLVM_SUPPORT_BINARYITEMSTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+
+template <typename T> struct BinaryItemTraits {
+ static size_t length(const T &Item) = delete;
+ static ArrayRef<uint8_t> bytes(const T &Item) = delete;
+};
+
+/// BinaryItemStream represents a sequence of objects stored in some kind of
+/// external container but for which it is useful to view as a stream of
+/// contiguous bytes. An example of this might be if you have a collection of
+/// records and you serialize each one into a buffer, and store these serialized
+/// records in a container. The pointers themselves are not laid out
+/// contiguously in memory, but we may wish to read from or write to these
+/// records as if they were.
+template <typename T, typename Traits = BinaryItemTraits<T>>
+class BinaryItemStream : public BinaryStream {
+public:
+ explicit BinaryItemStream(llvm::support::endianness Endian)
+ : Endian(Endian) {}
+
+ llvm::support::endianness getEndian() const override { return Endian; }
+
+ Error readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) override {
+ auto ExpectedIndex = translateOffsetIndex(Offset);
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ const auto &Item = Items[*ExpectedIndex];
+ if (auto EC = checkOffsetForRead(Offset, Size))
+ return EC;
+ if (Size > Traits::length(Item))
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ Buffer = Traits::bytes(Item).take_front(Size);
+ return Error::success();
+ }
+
+ Error readLongestContiguousChunk(uint64_t Offset,
+ ArrayRef<uint8_t> &Buffer) override {
+ auto ExpectedIndex = translateOffsetIndex(Offset);
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ Buffer = Traits::bytes(Items[*ExpectedIndex]);
+ return Error::success();
+ }
+
+ void setItems(ArrayRef<T> ItemArray) {
+ Items = ItemArray;
+ computeItemOffsets();
+ }
+
+ uint64_t getLength() override {
+ return ItemEndOffsets.empty() ? 0 : ItemEndOffsets.back();
+ }
+
+private:
+ void computeItemOffsets() {
+ ItemEndOffsets.clear();
+ ItemEndOffsets.reserve(Items.size());
+ uint64_t CurrentOffset = 0;
+ for (const auto &Item : Items) {
+ uint64_t Len = Traits::length(Item);
+ assert(Len > 0 && "no empty items");
+ CurrentOffset += Len;
+ ItemEndOffsets.push_back(CurrentOffset);
+ }
+ }
+
+ Expected<uint32_t> translateOffsetIndex(uint64_t Offset) {
+ // Make sure the offset is somewhere in our items array.
+ if (Offset >= getLength())
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ ++Offset;
+ auto Iter = llvm::lower_bound(ItemEndOffsets, Offset);
+ size_t Idx = std::distance(ItemEndOffsets.begin(), Iter);
+ assert(Idx < Items.size() && "binary search for offset failed");
+ return Idx;
+ }
+
+ llvm::support::endianness Endian;
+ ArrayRef<T> Items;
+
+ // Sorted vector of offsets to accelerate lookup.
+ std::vector<uint64_t> ItemEndOffsets;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYITEMSTREAM_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BinaryStream.h b/contrib/libs/llvm16/include/llvm/Support/BinaryStream.h
new file mode 100644
index 00000000000..5882290ddd3
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BinaryStream.h
@@ -0,0 +1,112 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BinaryStream.h - Base interface for a stream of data -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAM_H
+#define LLVM_SUPPORT_BINARYSTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+
+namespace llvm {
+
+enum BinaryStreamFlags {
+ BSF_None = 0,
+ BSF_Write = 1, // Stream supports writing.
+ BSF_Append = 2, // Writing can occur at offset == length.
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ BSF_Append)
+};
+
+/// An interface for accessing data in a stream-like format, but which
+/// discourages copying. Instead of specifying a buffer in which to copy
+/// data on a read, the API returns an ArrayRef to data owned by the stream's
+/// implementation. Since implementations may not necessarily store data in a
+/// single contiguous buffer (or even in memory at all), in such cases a it may
+/// be necessary for an implementation to cache such a buffer so that it can
+/// return it.
+class BinaryStream {
+public:
+ virtual ~BinaryStream() = default;
+
+ virtual llvm::support::endianness getEndian() const = 0;
+
+ /// Given an offset into the stream and a number of bytes, attempt to
+ /// read the bytes and set the output ArrayRef to point to data owned by the
+ /// stream.
+ virtual Error readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) = 0;
+
+ /// Given an offset into the stream, read as much as possible without
+ /// copying any data.
+ virtual Error readLongestContiguousChunk(uint64_t Offset,
+ ArrayRef<uint8_t> &Buffer) = 0;
+
+ /// Return the number of bytes of data in this stream.
+ virtual uint64_t getLength() = 0;
+
+ /// Return the properties of this stream.
+ virtual BinaryStreamFlags getFlags() const { return BSF_None; }
+
+protected:
+ Error checkOffsetForRead(uint64_t Offset, uint64_t DataSize) {
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+ if (getLength() < DataSize + Offset)
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ return Error::success();
+ }
+};
+
+/// A BinaryStream which can be read from as well as written to. Note
+/// that writing to a BinaryStream always necessitates copying from the input
+/// buffer to the stream's backing store. Streams are assumed to be buffered
+/// so that to be portable it is necessary to call commit() on the stream when
+/// all data has been written.
+class WritableBinaryStream : public BinaryStream {
+public:
+ ~WritableBinaryStream() override = default;
+
+ /// Attempt to write the given bytes into the stream at the desired
+ /// offset. This will always necessitate a copy. Cannot shrink or grow the
+ /// stream, only writes into existing allocated space.
+ virtual Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Data) = 0;
+
+ /// For buffered streams, commits changes to the backing store.
+ virtual Error commit() = 0;
+
+ /// Return the properties of this stream.
+ BinaryStreamFlags getFlags() const override { return BSF_Write; }
+
+protected:
+ Error checkOffsetForWrite(uint64_t Offset, uint64_t DataSize) {
+ if (!(getFlags() & BSF_Append))
+ return checkOffsetForRead(Offset, DataSize);
+
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+ return Error::success();
+ }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAM_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BinaryStreamArray.h b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamArray.h
new file mode 100644
index 00000000000..9bde33a81ed
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamArray.h
@@ -0,0 +1,385 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BinaryStreamArray.h - Array backed by an arbitrary stream *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Lightweight arrays that are backed by an arbitrary BinaryStream. This file
+/// provides two different array implementations.
+///
+/// VarStreamArray - Arrays of variable length records. The user specifies
+/// an Extractor type that can extract a record from a given offset and
+/// return the number of bytes consumed by the record.
+///
+/// FixedStreamArray - Arrays of fixed length records. This is similar in
+/// spirit to ArrayRef<T>, but since it is backed by a BinaryStream, the
+/// elements of the array need not be laid out in contiguous memory.
+///
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMARRAY_H
+#define LLVM_SUPPORT_BINARYSTREAMARRAY_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+
+namespace llvm {
+
+/// VarStreamArrayExtractor is intended to be specialized to provide customized
+/// extraction logic. On input it receives a BinaryStreamRef pointing to the
+/// beginning of the next record, but where the length of the record is not yet
+/// known. Upon completion, it should return an appropriate Error instance if
+/// a record could not be extracted, or if one could be extracted it should
+/// return success and set Len to the number of bytes this record occupied in
+/// the underlying stream, and it should fill out the fields of the value type
+/// Item appropriately to represent the current record.
+///
+/// You can specialize this template for your own custom value types to avoid
+/// having to specify a second template argument to VarStreamArray (documented
+/// below).
+template <typename T> struct VarStreamArrayExtractor {
+ // Method intentionally deleted. You must provide an explicit specialization
+ // with the following method implemented.
+ Error operator()(BinaryStreamRef Stream, uint32_t &Len,
+ T &Item) const = delete;
+};
+
+/// VarStreamArray represents an array of variable length records backed by a
+/// stream. This could be a contiguous sequence of bytes in memory, it could
+/// be a file on disk, or it could be a PDB stream where bytes are stored as
+/// discontiguous blocks in a file. Usually it is desirable to treat arrays
+/// as contiguous blocks of memory, but doing so with large PDB files, for
+/// example, could mean allocating huge amounts of memory just to allow
+/// re-ordering of stream data to be contiguous before iterating over it. By
+/// abstracting this out, we need not duplicate this memory, and we can
+/// iterate over arrays in arbitrarily formatted streams. Elements are parsed
+/// lazily on iteration, so there is no upfront cost associated with building
+/// or copying a VarStreamArray, no matter how large it may be.
+///
+/// You create a VarStreamArray by specifying a ValueType and an Extractor type.
+/// If you do not specify an Extractor type, you are expected to specialize
+/// VarStreamArrayExtractor<T> for your ValueType.
+///
+/// By default an Extractor is default constructed in the class, but in some
+/// cases you might find it useful for an Extractor to maintain state across
+/// extractions. In this case you can provide your own Extractor through a
+/// secondary constructor. The following examples show various ways of
+/// creating a VarStreamArray.
+///
+/// // Will use VarStreamArrayExtractor<MyType> as the extractor.
+/// VarStreamArray<MyType> MyTypeArray;
+///
+/// // Will use a default-constructed MyExtractor as the extractor.
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray2;
+///
+/// // Will use the specific instance of MyExtractor provided.
+/// // MyExtractor need not be default-constructible in this case.
+/// MyExtractor E(SomeContext);
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray3(E);
+///
+
+template <typename ValueType, typename Extractor> class VarStreamArrayIterator;
+
+template <typename ValueType,
+ typename Extractor = VarStreamArrayExtractor<ValueType>>
+class VarStreamArray {
+ friend class VarStreamArrayIterator<ValueType, Extractor>;
+
+public:
+ typedef VarStreamArrayIterator<ValueType, Extractor> Iterator;
+
+ VarStreamArray() = default;
+
+ explicit VarStreamArray(const Extractor &E) : E(E) {}
+
+ explicit VarStreamArray(BinaryStreamRef Stream, uint32_t Skew = 0)
+ : Stream(Stream), Skew(Skew) {}
+
+ VarStreamArray(BinaryStreamRef Stream, const Extractor &E, uint32_t Skew = 0)
+ : Stream(Stream), E(E), Skew(Skew) {}
+
+ Iterator begin(bool *HadError = nullptr) const {
+ return Iterator(*this, E, Skew, nullptr);
+ }
+
+ bool valid() const { return Stream.valid(); }
+
+ bool isOffsetValid(uint32_t Offset) const { return at(Offset) != end(); }
+
+ uint32_t skew() const { return Skew; }
+ Iterator end() const { return Iterator(E); }
+
+ bool empty() const { return Stream.getLength() == 0; }
+
+ VarStreamArray<ValueType, Extractor> substream(uint32_t Begin,
+ uint32_t End) const {
+ assert(Begin >= Skew);
+ // We should never cut off the beginning of the stream since it might be
+ // skewed, meaning the initial bytes are important.
+ BinaryStreamRef NewStream = Stream.slice(0, End);
+ return {NewStream, E, Begin};
+ }
+
+ /// given an offset into the array's underlying stream, return an
+ /// iterator to the record at that offset. This is considered unsafe
+ /// since the behavior is undefined if \p Offset does not refer to the
+ /// beginning of a valid record.
+ Iterator at(uint32_t Offset) const {
+ return Iterator(*this, E, Offset, nullptr);
+ }
+
+ const Extractor &getExtractor() const { return E; }
+ Extractor &getExtractor() { return E; }
+
+ BinaryStreamRef getUnderlyingStream() const { return Stream; }
+ void setUnderlyingStream(BinaryStreamRef NewStream, uint32_t NewSkew = 0) {
+ Stream = NewStream;
+ Skew = NewSkew;
+ }
+
+ void drop_front() { Skew += begin()->length(); }
+
+private:
+ BinaryStreamRef Stream;
+ Extractor E;
+ uint32_t Skew = 0;
+};
+
+template <typename ValueType, typename Extractor>
+class VarStreamArrayIterator
+ : public iterator_facade_base<VarStreamArrayIterator<ValueType, Extractor>,
+ std::forward_iterator_tag, const ValueType> {
+ typedef VarStreamArrayIterator<ValueType, Extractor> IterType;
+ typedef VarStreamArray<ValueType, Extractor> ArrayType;
+
+public:
+ VarStreamArrayIterator(const ArrayType &Array, const Extractor &E,
+ uint32_t Offset, bool *HadError)
+ : IterRef(Array.Stream.drop_front(Offset)), Extract(E),
+ Array(&Array), AbsOffset(Offset), HadError(HadError) {
+ if (IterRef.getLength() == 0)
+ moveToEnd();
+ else {
+ auto EC = Extract(IterRef, ThisLen, ThisValue);
+ if (EC) {
+ consumeError(std::move(EC));
+ markError();
+ }
+ }
+ }
+
+ VarStreamArrayIterator() = default;
+ explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {}
+ ~VarStreamArrayIterator() = default;
+
+ bool operator==(const IterType &R) const {
+ if (Array && R.Array) {
+ // Both have a valid array, make sure they're same.
+ assert(Array == R.Array);
+ return IterRef == R.IterRef;
+ }
+
+ // Both iterators are at the end.
+ if (!Array && !R.Array)
+ return true;
+
+ // One is not at the end and one is.
+ return false;
+ }
+
+ const ValueType &operator*() const {
+ assert(Array && !HasError);
+ return ThisValue;
+ }
+
+ IterType &operator+=(unsigned N) {
+ for (unsigned I = 0; I < N; ++I) {
+ // We are done with the current record, discard it so that we are
+ // positioned at the next record.
+ AbsOffset += ThisLen;
+ IterRef = IterRef.drop_front(ThisLen);
+ if (IterRef.getLength() == 0) {
+ // There is nothing after the current record, we must make this an end
+ // iterator.
+ moveToEnd();
+ } else {
+ // There is some data after the current record.
+ auto EC = Extract(IterRef, ThisLen, ThisValue);
+ if (EC) {
+ consumeError(std::move(EC));
+ markError();
+ } else if (ThisLen == 0) {
+ // An empty record? Make this an end iterator.
+ moveToEnd();
+ }
+ }
+ }
+ return *this;
+ }
+
+ uint32_t offset() const { return AbsOffset; }
+ uint32_t getRecordLength() const { return ThisLen; }
+
+private:
+ void moveToEnd() {
+ Array = nullptr;
+ ThisLen = 0;
+ }
+ void markError() {
+ moveToEnd();
+ HasError = true;
+ if (HadError != nullptr)
+ *HadError = true;
+ }
+
+ ValueType ThisValue;
+ BinaryStreamRef IterRef;
+ Extractor Extract;
+ const ArrayType *Array{nullptr};
+ uint32_t ThisLen{0};
+ uint32_t AbsOffset{0};
+ bool HasError{false};
+ bool *HadError{nullptr};
+};
+
+template <typename T> class FixedStreamArrayIterator;
+
+/// FixedStreamArray is similar to VarStreamArray, except with each record
+/// having a fixed-length. As with VarStreamArray, there is no upfront
+/// cost associated with building or copying a FixedStreamArray, as the
+/// memory for each element is not read from the backing stream until that
+/// element is iterated.
+template <typename T> class FixedStreamArray {
+ friend class FixedStreamArrayIterator<T>;
+
+public:
+ typedef FixedStreamArrayIterator<T> Iterator;
+
+ FixedStreamArray() = default;
+ explicit FixedStreamArray(BinaryStreamRef Stream) : Stream(Stream) {
+ assert(Stream.getLength() % sizeof(T) == 0);
+ }
+
+ bool operator==(const FixedStreamArray<T> &Other) const {
+ return Stream == Other.Stream;
+ }
+
+ bool operator!=(const FixedStreamArray<T> &Other) const {
+ return !(*this == Other);
+ }
+
+ FixedStreamArray(const FixedStreamArray &) = default;
+ FixedStreamArray &operator=(const FixedStreamArray &) = default;
+
+ const T &operator[](uint32_t Index) const {
+ assert(Index < size());
+ uint32_t Off = Index * sizeof(T);
+ ArrayRef<uint8_t> Data;
+ if (auto EC = Stream.readBytes(Off, sizeof(T), Data)) {
+ assert(false && "Unexpected failure reading from stream");
+ // This should never happen since we asserted that the stream length was
+ // an exact multiple of the element size.
+ consumeError(std::move(EC));
+ }
+ assert(isAddrAligned(Align::Of<T>(), Data.data()));
+ return *reinterpret_cast<const T *>(Data.data());
+ }
+
+ uint32_t size() const { return Stream.getLength() / sizeof(T); }
+
+ bool empty() const { return size() == 0; }
+
+ FixedStreamArrayIterator<T> begin() const {
+ return FixedStreamArrayIterator<T>(*this, 0);
+ }
+
+ FixedStreamArrayIterator<T> end() const {
+ return FixedStreamArrayIterator<T>(*this, size());
+ }
+
+ const T &front() const { return *begin(); }
+ const T &back() const {
+ FixedStreamArrayIterator<T> I = end();
+ return *(--I);
+ }
+
+ BinaryStreamRef getUnderlyingStream() const { return Stream; }
+
+private:
+ BinaryStreamRef Stream;
+};
+
+template <typename T>
+class FixedStreamArrayIterator
+ : public iterator_facade_base<FixedStreamArrayIterator<T>,
+ std::random_access_iterator_tag, const T> {
+
+public:
+ FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t Index)
+ : Array(Array), Index(Index) {}
+
+ FixedStreamArrayIterator(const FixedStreamArrayIterator<T> &Other)
+ : Array(Other.Array), Index(Other.Index) {}
+ FixedStreamArrayIterator<T> &
+ operator=(const FixedStreamArrayIterator<T> &Other) {
+ Array = Other.Array;
+ Index = Other.Index;
+ return *this;
+ }
+
+ const T &operator*() const { return Array[Index]; }
+ const T &operator*() { return Array[Index]; }
+
+ bool operator==(const FixedStreamArrayIterator<T> &R) const {
+ assert(Array == R.Array);
+ return (Index == R.Index) && (Array == R.Array);
+ }
+
+ FixedStreamArrayIterator<T> &operator+=(std::ptrdiff_t N) {
+ Index += N;
+ return *this;
+ }
+
+ FixedStreamArrayIterator<T> &operator-=(std::ptrdiff_t N) {
+ assert(std::ptrdiff_t(Index) >= N);
+ Index -= N;
+ return *this;
+ }
+
+ std::ptrdiff_t operator-(const FixedStreamArrayIterator<T> &R) const {
+ assert(Array == R.Array);
+ assert(Index >= R.Index);
+ return Index - R.Index;
+ }
+
+ bool operator<(const FixedStreamArrayIterator<T> &RHS) const {
+ assert(Array == RHS.Array);
+ return Index < RHS.Index;
+ }
+
+private:
+ FixedStreamArray<T> Array;
+ uint32_t Index;
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMARRAY_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BinaryStreamError.h b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamError.h
new file mode 100644
index 00000000000..73d9cadf930
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamError.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BinaryStreamError.h - Error extensions for Binary Streams *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMERROR_H
+#define LLVM_SUPPORT_BINARYSTREAMERROR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <string>
+
+namespace llvm {
+enum class stream_error_code {
+ unspecified,
+ stream_too_short,
+ invalid_array_size,
+ invalid_offset,
+ filesystem_error
+};
+
+/// Base class for errors originating when parsing raw PDB files
+class BinaryStreamError : public ErrorInfo<BinaryStreamError> {
+public:
+ static char ID;
+ explicit BinaryStreamError(stream_error_code C);
+ explicit BinaryStreamError(StringRef Context);
+ BinaryStreamError(stream_error_code C, StringRef Context);
+
+ void log(raw_ostream &OS) const override;
+ std::error_code convertToErrorCode() const override;
+
+ StringRef getErrorMessage() const;
+
+ stream_error_code getErrorCode() const { return Code; }
+
+private:
+ std::string ErrMsg;
+ stream_error_code Code;
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMERROR_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BinaryStreamReader.h b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamReader.h
new file mode 100644
index 00000000000..24d9198a99f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamReader.h
@@ -0,0 +1,286 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H
+#define LLVM_SUPPORT_BINARYSTREAMREADER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <type_traits>
+
+namespace llvm {
+
+/// Provides read only access to a subclass of `BinaryStream`. Provides
+/// bounds checking and helpers for writing certain common data types such as
+/// null-terminated strings, integers in various flavors of endianness, etc.
+/// Can be subclassed to provide reading of custom datatypes, although no
+/// are overridable.
+class BinaryStreamReader {
+public:
+ BinaryStreamReader() = default;
+ explicit BinaryStreamReader(BinaryStreamRef Ref);
+ explicit BinaryStreamReader(BinaryStream &Stream);
+ explicit BinaryStreamReader(ArrayRef<uint8_t> Data,
+ llvm::support::endianness Endian);
+ explicit BinaryStreamReader(StringRef Data, llvm::support::endianness Endian);
+
+ BinaryStreamReader(const BinaryStreamReader &Other) = default;
+
+ BinaryStreamReader &operator=(const BinaryStreamReader &Other) = default;
+
+ virtual ~BinaryStreamReader() = default;
+
+ /// Read as much as possible from the underlying string at the current offset
+ /// without invoking a copy, and set \p Buffer to the resulting data slice.
+ /// Updates the stream's offset to point after the newly read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
+
+ /// Read \p Size bytes from the underlying stream at the current offset and
+ /// and set \p Buffer to the resulting data slice. Whether a copy occurs
+ /// depends on the implementation of the underlying stream. Updates the
+ /// stream's offset to point after the newly read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
+
+ /// Read an integer of the specified endianness into \p Dest and update the
+ /// stream's offset. The data is always copied from the stream's underlying
+ /// buffer into \p Dest. Updates the stream's offset to point after the newly
+ /// read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T> Error readInteger(T &Dest) {
+ static_assert(std::is_integral_v<T>,
+ "Cannot call readInteger with non-integral value!");
+
+ ArrayRef<uint8_t> Bytes;
+ if (auto EC = readBytes(Bytes, sizeof(T)))
+ return EC;
+
+ Dest = llvm::support::endian::read<T, llvm::support::unaligned>(
+ Bytes.data(), Stream.getEndian());
+ return Error::success();
+ }
+
+ /// Similar to readInteger.
+ template <typename T> Error readEnum(T &Dest) {
+ static_assert(std::is_enum<T>::value,
+ "Cannot call readEnum with non-enum value!");
+ std::underlying_type_t<T> N;
+ if (auto EC = readInteger(N))
+ return EC;
+ Dest = static_cast<T>(N);
+ return Error::success();
+ }
+
+ /// Read an unsigned LEB128 encoded value.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readULEB128(uint64_t &Dest);
+
+ /// Read a signed LEB128 encoded value.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readSLEB128(int64_t &Dest);
+
+ /// Read a null terminated string from \p Dest. Whether a copy occurs depends
+ /// on the implementation of the underlying stream. Updates the stream's
+ /// offset to point after the newly read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readCString(StringRef &Dest);
+
+ /// Similar to readCString, however read a null-terminated UTF16 string
+ /// instead.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readWideString(ArrayRef<UTF16> &Dest);
+
+ /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends
+ /// on the implementation of the underlying stream. Updates the stream's
+ /// offset to point after the newly read data.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readFixedString(StringRef &Dest, uint32_t Length);
+
+ /// Read the entire remainder of the underlying stream into \p Ref. This is
+ /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the
+ /// stream's offset to point to the end of the stream. Never causes a copy.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readStreamRef(BinaryStreamRef &Ref);
+
+ /// Read \p Length bytes from the underlying stream into \p Ref. This is
+ /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
+ /// Updates the stream's offset to point after the newly read object. Never
+ /// causes a copy.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length);
+
+ /// Read \p Length bytes from the underlying stream into \p Ref. This is
+ /// equivalent to calling getUnderlyingStream().slice(Offset, Length).
+ /// Updates the stream's offset to point after the newly read object. Never
+ /// causes a copy.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ Error readSubstream(BinarySubstreamRef &Ref, uint32_t Length);
+
+ /// Get a pointer to an object of type T from the underlying stream, as if by
+ /// memcpy, and store the result into \p Dest. It is up to the caller to
+ /// ensure that objects of type T can be safely treated in this manner.
+ /// Updates the stream's offset to point after the newly read object. Whether
+ /// a copy occurs depends upon the implementation of the underlying
+ /// stream.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T> Error readObject(const T *&Dest) {
+ ArrayRef<uint8_t> Buffer;
+ if (auto EC = readBytes(Buffer, sizeof(T)))
+ return EC;
+ Dest = reinterpret_cast<const T *>(Buffer.data());
+ return Error::success();
+ }
+
+ /// Get a reference to a \p NumElements element array of objects of type T
+ /// from the underlying stream as if by memcpy, and store the resulting array
+ /// slice into \p array. It is up to the caller to ensure that objects of
+ /// type T can be safely treated in this manner. Updates the stream's offset
+ /// to point after the newly read object. Whether a copy occurs depends upon
+ /// the implementation of the underlying stream.
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T>
+ Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
+ ArrayRef<uint8_t> Bytes;
+ if (NumElements == 0) {
+ Array = ArrayRef<T>();
+ return Error::success();
+ }
+
+ if (NumElements > UINT32_MAX / sizeof(T))
+ return make_error<BinaryStreamError>(
+ stream_error_code::invalid_array_size);
+
+ if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
+ return EC;
+
+ assert(isAddrAligned(Align::Of<T>(), Bytes.data()) &&
+ "Reading at invalid alignment!");
+
+ Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
+ return Error::success();
+ }
+
+ /// Read a VarStreamArray of size \p Size bytes and store the result into
+ /// \p Array. Updates the stream's offset to point after the newly read
+ /// array. Never causes a copy (although iterating the elements of the
+ /// VarStreamArray may, depending upon the implementation of the underlying
+ /// stream).
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T, typename U>
+ Error readArray(VarStreamArray<T, U> &Array, uint32_t Size,
+ uint32_t Skew = 0) {
+ BinaryStreamRef S;
+ if (auto EC = readStreamRef(S, Size))
+ return EC;
+ Array.setUnderlyingStream(S, Skew);
+ return Error::success();
+ }
+
+ /// Read a FixedStreamArray of \p NumItems elements and store the result into
+ /// \p Array. Updates the stream's offset to point after the newly read
+ /// array. Never causes a copy (although iterating the elements of the
+ /// FixedStreamArray may, depending upon the implementation of the underlying
+ /// stream).
+ ///
+ /// \returns a success error code if the data was successfully read, otherwise
+ /// returns an appropriate error code.
+ template <typename T>
+ Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
+ if (NumItems == 0) {
+ Array = FixedStreamArray<T>();
+ return Error::success();
+ }
+
+ if (NumItems > UINT32_MAX / sizeof(T))
+ return make_error<BinaryStreamError>(
+ stream_error_code::invalid_array_size);
+
+ BinaryStreamRef View;
+ if (auto EC = readStreamRef(View, NumItems * sizeof(T)))
+ return EC;
+
+ Array = FixedStreamArray<T>(View);
+ return Error::success();
+ }
+
+ bool empty() const { return bytesRemaining() == 0; }
+ void setOffset(uint64_t Off) { Offset = Off; }
+ uint64_t getOffset() const { return Offset; }
+ uint64_t getLength() const { return Stream.getLength(); }
+ uint64_t bytesRemaining() const { return getLength() - getOffset(); }
+
+ /// Advance the stream's offset by \p Amount bytes.
+ ///
+ /// \returns a success error code if at least \p Amount bytes remain in the
+ /// stream, otherwise returns an appropriate error code.
+ Error skip(uint64_t Amount);
+
+ /// Examine the next byte of the underlying stream without advancing the
+ /// stream's offset. If the stream is empty the behavior is undefined.
+ ///
+ /// \returns the next byte in the stream.
+ uint8_t peek() const;
+
+ Error padToAlignment(uint32_t Align);
+
+ std::pair<BinaryStreamReader, BinaryStreamReader>
+ split(uint64_t Offset) const;
+
+private:
+ BinaryStreamRef Stream;
+ uint64_t Offset = 0;
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMREADER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BinaryStreamRef.h b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamRef.h
new file mode 100644
index 00000000000..4f3e17baa0b
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamRef.h
@@ -0,0 +1,283 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BinaryStreamRef.h - A copyable reference to a stream -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMREF_H
+#define LLVM_SUPPORT_BINARYSTREAMREF_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <memory>
+#include <optional>
+
+namespace llvm {
+
+/// Common stuff for mutable and immutable StreamRefs.
+template <class RefType, class StreamType> class BinaryStreamRefBase {
+protected:
+ BinaryStreamRefBase() = default;
+ explicit BinaryStreamRefBase(StreamType &BorrowedImpl)
+ : BorrowedImpl(&BorrowedImpl), ViewOffset(0) {
+ if (!(BorrowedImpl.getFlags() & BSF_Append))
+ Length = BorrowedImpl.getLength();
+ }
+
+ BinaryStreamRefBase(std::shared_ptr<StreamType> SharedImpl, uint64_t Offset,
+ std::optional<uint64_t> Length)
+ : SharedImpl(SharedImpl), BorrowedImpl(SharedImpl.get()),
+ ViewOffset(Offset), Length(Length) {}
+ BinaryStreamRefBase(StreamType &BorrowedImpl, uint64_t Offset,
+ std::optional<uint64_t> Length)
+ : BorrowedImpl(&BorrowedImpl), ViewOffset(Offset), Length(Length) {}
+ BinaryStreamRefBase(const BinaryStreamRefBase &Other) = default;
+ BinaryStreamRefBase &operator=(const BinaryStreamRefBase &Other) = default;
+
+ BinaryStreamRefBase &operator=(BinaryStreamRefBase &&Other) = default;
+ BinaryStreamRefBase(BinaryStreamRefBase &&Other) = default;
+
+public:
+ llvm::support::endianness getEndian() const {
+ return BorrowedImpl->getEndian();
+ }
+
+ uint64_t getLength() const {
+ if (Length)
+ return *Length;
+
+ return BorrowedImpl ? (BorrowedImpl->getLength() - ViewOffset) : 0;
+ }
+
+ /// Return a new BinaryStreamRef with the first \p N elements removed. If
+ /// this BinaryStreamRef is length-tracking, then the resulting one will be
+ /// too.
+ RefType drop_front(uint64_t N) const {
+ if (!BorrowedImpl)
+ return RefType();
+
+ N = std::min(N, getLength());
+ RefType Result(static_cast<const RefType &>(*this));
+ if (N == 0)
+ return Result;
+
+ Result.ViewOffset += N;
+ if (Result.Length)
+ *Result.Length -= N;
+ return Result;
+ }
+
+ /// Return a new BinaryStreamRef with the last \p N elements removed. If
+ /// this BinaryStreamRef is length-tracking and \p N is greater than 0, then
+ /// this BinaryStreamRef will no longer length-track.
+ RefType drop_back(uint64_t N) const {
+ if (!BorrowedImpl)
+ return RefType();
+
+ RefType Result(static_cast<const RefType &>(*this));
+ N = std::min(N, getLength());
+
+ if (N == 0)
+ return Result;
+
+ // Since we're dropping non-zero bytes from the end, stop length-tracking
+ // by setting the length of the resulting StreamRef to an explicit value.
+ if (!Result.Length)
+ Result.Length = getLength();
+
+ *Result.Length -= N;
+ return Result;
+ }
+
+ /// Return a new BinaryStreamRef with only the first \p N elements remaining.
+ RefType keep_front(uint64_t N) const {
+ assert(N <= getLength());
+ return drop_back(getLength() - N);
+ }
+
+ /// Return a new BinaryStreamRef with only the last \p N elements remaining.
+ RefType keep_back(uint64_t N) const {
+ assert(N <= getLength());
+ return drop_front(getLength() - N);
+ }
+
+ /// Return a new BinaryStreamRef with the first and last \p N elements
+ /// removed.
+ RefType drop_symmetric(uint64_t N) const {
+ return drop_front(N).drop_back(N);
+ }
+
+ /// Return a new BinaryStreamRef with the first \p Offset elements removed,
+ /// and retaining exactly \p Len elements.
+ RefType slice(uint64_t Offset, uint64_t Len) const {
+ return drop_front(Offset).keep_front(Len);
+ }
+
+ bool valid() const { return BorrowedImpl != nullptr; }
+
+ friend bool operator==(const RefType &LHS, const RefType &RHS) {
+ if (LHS.BorrowedImpl != RHS.BorrowedImpl)
+ return false;
+ if (LHS.ViewOffset != RHS.ViewOffset)
+ return false;
+ if (LHS.Length != RHS.Length)
+ return false;
+ return true;
+ }
+
+protected:
+ Error checkOffsetForRead(uint64_t Offset, uint64_t DataSize) const {
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+ if (getLength() < DataSize + Offset)
+ return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
+ return Error::success();
+ }
+
+ std::shared_ptr<StreamType> SharedImpl;
+ StreamType *BorrowedImpl = nullptr;
+ uint64_t ViewOffset = 0;
+ std::optional<uint64_t> Length;
+};
+
+/// BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It
+/// provides copy-semantics and read only access to a "window" of the underlying
+/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to
+/// say, it does not inherit and override the methods of BinaryStream. In
+/// general, you should not pass around pointers or references to BinaryStreams
+/// and use inheritance to achieve polymorphism. Instead, you should pass
+/// around BinaryStreamRefs by value and achieve polymorphism that way.
+class BinaryStreamRef
+ : public BinaryStreamRefBase<BinaryStreamRef, BinaryStream> {
+ friend BinaryStreamRefBase<BinaryStreamRef, BinaryStream>;
+ friend class WritableBinaryStreamRef;
+ BinaryStreamRef(std::shared_ptr<BinaryStream> Impl, uint64_t ViewOffset,
+ std::optional<uint64_t> Length)
+ : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
+
+public:
+ BinaryStreamRef() = default;
+ BinaryStreamRef(BinaryStream &Stream);
+ BinaryStreamRef(BinaryStream &Stream, uint64_t Offset,
+ std::optional<uint64_t> Length);
+ explicit BinaryStreamRef(ArrayRef<uint8_t> Data,
+ llvm::support::endianness Endian);
+ explicit BinaryStreamRef(StringRef Data, llvm::support::endianness Endian);
+
+ BinaryStreamRef(const BinaryStreamRef &Other) = default;
+ BinaryStreamRef &operator=(const BinaryStreamRef &Other) = default;
+ BinaryStreamRef(BinaryStreamRef &&Other) = default;
+ BinaryStreamRef &operator=(BinaryStreamRef &&Other) = default;
+
+ // Use BinaryStreamRef.slice() instead.
+ BinaryStreamRef(BinaryStreamRef &S, uint64_t Offset,
+ uint64_t Length) = delete;
+
+ /// Given an Offset into this StreamRef and a Size, return a reference to a
+ /// buffer owned by the stream.
+ ///
+ /// \returns a success error code if the entire range of data is within the
+ /// bounds of this BinaryStreamRef's view and the implementation could read
+ /// the data, and an appropriate error code otherwise.
+ Error readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) const;
+
+ /// Given an Offset into this BinaryStreamRef, return a reference to the
+ /// largest buffer the stream could support without necessitating a copy.
+ ///
+ /// \returns a success error code if implementation could read the data,
+ /// and an appropriate error code otherwise.
+ Error readLongestContiguousChunk(uint64_t Offset,
+ ArrayRef<uint8_t> &Buffer) const;
+};
+
+struct BinarySubstreamRef {
+ uint64_t Offset = 0; // Offset in the parent stream
+ BinaryStreamRef StreamData; // Stream Data
+
+ BinarySubstreamRef slice(uint64_t Off, uint64_t Size) const {
+ BinaryStreamRef SubSub = StreamData.slice(Off, Size);
+ return {Off + Offset, SubSub};
+ }
+ BinarySubstreamRef drop_front(uint64_t N) const {
+ return slice(N, size() - N);
+ }
+ BinarySubstreamRef keep_front(uint64_t N) const { return slice(0, N); }
+
+ std::pair<BinarySubstreamRef, BinarySubstreamRef> split(uint64_t Off) const {
+ return std::make_pair(keep_front(Off), drop_front(Off));
+ }
+
+ uint64_t size() const { return StreamData.getLength(); }
+ bool empty() const { return size() == 0; }
+};
+
+class WritableBinaryStreamRef
+ : public BinaryStreamRefBase<WritableBinaryStreamRef,
+ WritableBinaryStream> {
+ friend BinaryStreamRefBase<WritableBinaryStreamRef, WritableBinaryStream>;
+ WritableBinaryStreamRef(std::shared_ptr<WritableBinaryStream> Impl,
+ uint64_t ViewOffset, std::optional<uint64_t> Length)
+ : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
+
+ Error checkOffsetForWrite(uint64_t Offset, uint64_t DataSize) const {
+ if (!(BorrowedImpl->getFlags() & BSF_Append))
+ return checkOffsetForRead(Offset, DataSize);
+
+ if (Offset > getLength())
+ return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
+ return Error::success();
+ }
+
+public:
+ WritableBinaryStreamRef() = default;
+ WritableBinaryStreamRef(WritableBinaryStream &Stream);
+ WritableBinaryStreamRef(WritableBinaryStream &Stream, uint64_t Offset,
+ std::optional<uint64_t> Length);
+ explicit WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data,
+ llvm::support::endianness Endian);
+ WritableBinaryStreamRef(const WritableBinaryStreamRef &Other) = default;
+ WritableBinaryStreamRef &
+ operator=(const WritableBinaryStreamRef &Other) = default;
+
+ WritableBinaryStreamRef(WritableBinaryStreamRef &&Other) = default;
+ WritableBinaryStreamRef &operator=(WritableBinaryStreamRef &&Other) = default;
+
+ // Use WritableBinaryStreamRef.slice() instead.
+ WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint64_t Offset,
+ uint64_t Length) = delete;
+
+ /// Given an Offset into this WritableBinaryStreamRef and some input data,
+ /// writes the data to the underlying stream.
+ ///
+ /// \returns a success error code if the data could fit within the underlying
+ /// stream at the specified location and the implementation could write the
+ /// data, and an appropriate error code otherwise.
+ Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Data) const;
+
+ /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef.
+ operator BinaryStreamRef() const;
+
+ /// For buffered streams, commits changes to the backing store.
+ Error commit();
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMREF_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BinaryStreamWriter.h b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamWriter.h
new file mode 100644
index 00000000000..9b934b2f391
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BinaryStreamWriter.h
@@ -0,0 +1,201 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BINARYSTREAMWRITER_H
+#define LLVM_SUPPORT_BINARYSTREAMWRITER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamError.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+/// Provides write only access to a subclass of `WritableBinaryStream`.
+/// Provides bounds checking and helpers for writing certain common data types
+/// such as null-terminated strings, integers in various flavors of endianness,
+/// etc. Can be subclassed to provide reading and writing of custom datatypes,
+/// although no methods are overridable.
+class BinaryStreamWriter {
+public:
+ BinaryStreamWriter() = default;
+ explicit BinaryStreamWriter(WritableBinaryStreamRef Ref);
+ explicit BinaryStreamWriter(WritableBinaryStream &Stream);
+ explicit BinaryStreamWriter(MutableArrayRef<uint8_t> Data,
+ llvm::support::endianness Endian);
+
+ BinaryStreamWriter(const BinaryStreamWriter &Other) = default;
+
+ BinaryStreamWriter &operator=(const BinaryStreamWriter &Other) = default;
+
+ virtual ~BinaryStreamWriter() = default;
+
+ /// Write the bytes specified in \p Buffer to the underlying stream.
+ /// On success, updates the offset so that subsequent writes will occur
+ /// at the next unwritten position.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeBytes(ArrayRef<uint8_t> Buffer);
+
+ /// Write the integer \p Value to the underlying stream in the
+ /// specified endianness. On success, updates the offset so that
+ /// subsequent writes occur at the next unwritten position.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T> Error writeInteger(T Value) {
+ static_assert(std::is_integral_v<T>,
+ "Cannot call writeInteger with non-integral value!");
+ uint8_t Buffer[sizeof(T)];
+ llvm::support::endian::write<T, llvm::support::unaligned>(
+ Buffer, Value, Stream.getEndian());
+ return writeBytes(Buffer);
+ }
+
+ /// Similar to writeInteger
+ template <typename T> Error writeEnum(T Num) {
+ static_assert(std::is_enum<T>::value,
+ "Cannot call writeEnum with non-Enum type");
+
+ using U = std::underlying_type_t<T>;
+ return writeInteger<U>(static_cast<U>(Num));
+ }
+
+ /// Write the unsigned integer Value to the underlying stream using ULEB128
+ /// encoding.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeULEB128(uint64_t Value);
+
+ /// Write the unsigned integer Value to the underlying stream using ULEB128
+ /// encoding.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeSLEB128(int64_t Value);
+
+ /// Write the string \p Str to the underlying stream followed by a null
+ /// terminator. On success, updates the offset so that subsequent writes
+ /// occur at the next unwritten position. \p Str need not be null terminated
+ /// on input.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeCString(StringRef Str);
+
+ /// Write the string \p Str to the underlying stream without a null
+ /// terminator. On success, updates the offset so that subsequent writes
+ /// occur at the next unwritten position.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeFixedString(StringRef Str);
+
+ /// Efficiently reads all data from \p Ref, and writes it to this stream.
+ /// This operation will not invoke any copies of the source data, regardless
+ /// of the source stream's implementation.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeStreamRef(BinaryStreamRef Ref);
+
+ /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream.
+ /// This operation will not invoke any copies of the source data, regardless
+ /// of the source stream's implementation.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ Error writeStreamRef(BinaryStreamRef Ref, uint64_t Size);
+
+ /// Writes the object \p Obj to the underlying stream, as if by using memcpy.
+ /// It is up to the caller to ensure that type of \p Obj can be safely copied
+ /// in this fashion, as no checks are made to ensure that this is safe.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T> Error writeObject(const T &Obj) {
+ static_assert(!std::is_pointer<T>::value,
+ "writeObject should not be used with pointers, to write "
+ "the pointed-to value dereference the pointer before calling "
+ "writeObject");
+ return writeBytes(
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T)));
+ }
+
+ /// Writes an array of objects of type T to the underlying stream, as if by
+ /// using memcpy. It is up to the caller to ensure that type of \p Obj can
+ /// be safely copied in this fashion, as no checks are made to ensure that
+ /// this is safe.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T> Error writeArray(ArrayRef<T> Array) {
+ if (Array.empty())
+ return Error::success();
+ if (Array.size() > UINT32_MAX / sizeof(T))
+ return make_error<BinaryStreamError>(
+ stream_error_code::invalid_array_size);
+
+ return writeBytes(
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()),
+ Array.size() * sizeof(T)));
+ }
+
+ /// Writes all data from the array \p Array to the underlying stream.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T, typename U>
+ Error writeArray(VarStreamArray<T, U> Array) {
+ return writeStreamRef(Array.getUnderlyingStream());
+ }
+
+ /// Writes all elements from the array \p Array to the underlying stream.
+ ///
+ /// \returns a success error code if the data was successfully written,
+ /// otherwise returns an appropriate error code.
+ template <typename T> Error writeArray(FixedStreamArray<T> Array) {
+ return writeStreamRef(Array.getUnderlyingStream());
+ }
+
+ /// Splits the Writer into two Writers at a given offset.
+ std::pair<BinaryStreamWriter, BinaryStreamWriter> split(uint64_t Off) const;
+
+ void setOffset(uint64_t Off) { Offset = Off; }
+ uint64_t getOffset() const { return Offset; }
+ uint64_t getLength() const { return Stream.getLength(); }
+ uint64_t bytesRemaining() const { return getLength() - getOffset(); }
+ Error padToAlignment(uint32_t Align);
+
+protected:
+ WritableBinaryStreamRef Stream;
+ uint64_t Offset = 0;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BlockFrequency.h b/contrib/libs/llvm16/include/llvm/Support/BlockFrequency.h
new file mode 100644
index 00000000000..9c2a3a4113e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BlockFrequency.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-------- BlockFrequency.h - Block Frequency Wrapper --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Block Frequency class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BLOCKFREQUENCY_H
+#define LLVM_SUPPORT_BLOCKFREQUENCY_H
+
+#include <cstdint>
+
+namespace llvm {
+
+class BranchProbability;
+
+// This class represents Block Frequency as a 64-bit value.
+class BlockFrequency {
+ uint64_t Frequency;
+
+public:
+ BlockFrequency(uint64_t Freq = 0) : Frequency(Freq) { }
+
+ /// Returns the maximum possible frequency, the saturation value.
+ static uint64_t getMaxFrequency() { return -1ULL; }
+
+ /// Returns the frequency as a fixpoint number scaled by the entry
+ /// frequency.
+ uint64_t getFrequency() const { return Frequency; }
+
+ /// Multiplies with a branch probability. The computation will never
+ /// overflow.
+ BlockFrequency &operator*=(BranchProbability Prob);
+ BlockFrequency operator*(BranchProbability Prob) const;
+
+ /// Divide by a non-zero branch probability using saturating
+ /// arithmetic.
+ BlockFrequency &operator/=(BranchProbability Prob);
+ BlockFrequency operator/(BranchProbability Prob) const;
+
+ /// Adds another block frequency using saturating arithmetic.
+ BlockFrequency &operator+=(BlockFrequency Freq);
+ BlockFrequency operator+(BlockFrequency Freq) const;
+
+ /// Subtracts another block frequency using saturating arithmetic.
+ BlockFrequency &operator-=(BlockFrequency Freq);
+ BlockFrequency operator-(BlockFrequency Freq) const;
+
+ /// Shift block frequency to the right by count digits saturating to 1.
+ BlockFrequency &operator>>=(const unsigned count);
+
+ bool operator<(BlockFrequency RHS) const {
+ return Frequency < RHS.Frequency;
+ }
+
+ bool operator<=(BlockFrequency RHS) const {
+ return Frequency <= RHS.Frequency;
+ }
+
+ bool operator>(BlockFrequency RHS) const {
+ return Frequency > RHS.Frequency;
+ }
+
+ bool operator>=(BlockFrequency RHS) const {
+ return Frequency >= RHS.Frequency;
+ }
+
+ bool operator==(BlockFrequency RHS) const {
+ return Frequency == RHS.Frequency;
+ }
+};
+
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BranchProbability.h b/contrib/libs/llvm16/include/llvm/Support/BranchProbability.h
new file mode 100644
index 00000000000..b05b2be3c0e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BranchProbability.h
@@ -0,0 +1,259 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- BranchProbability.h - Branch Probability Wrapper ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Definition of BranchProbability shared by IR and Machine Instructions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BRANCHPROBABILITY_H
+#define LLVM_SUPPORT_BRANCHPROBABILITY_H
+
+#include "llvm/Support/DataTypes.h"
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <numeric>
+
+namespace llvm {
+
+class raw_ostream;
+
+// This class represents Branch Probability as a non-negative fraction that is
+// no greater than 1. It uses a fixed-point-like implementation, in which the
+// denominator is always a constant value (here we use 1<<31 for maximum
+// precision).
+class BranchProbability {
+ // Numerator
+ uint32_t N;
+
+ // Denominator, which is a constant value.
+ static constexpr uint32_t D = 1u << 31;
+ static constexpr uint32_t UnknownN = UINT32_MAX;
+
+ // Construct a BranchProbability with only numerator assuming the denominator
+ // is 1<<31. For internal use only.
+ explicit BranchProbability(uint32_t n) : N(n) {}
+
+public:
+ BranchProbability() : N(UnknownN) {}
+ BranchProbability(uint32_t Numerator, uint32_t Denominator);
+
+ bool isZero() const { return N == 0; }
+ bool isUnknown() const { return N == UnknownN; }
+
+ static BranchProbability getZero() { return BranchProbability(0); }
+ static BranchProbability getOne() { return BranchProbability(D); }
+ static BranchProbability getUnknown() { return BranchProbability(UnknownN); }
+ // Create a BranchProbability object with the given numerator and 1<<31
+ // as denominator.
+ static BranchProbability getRaw(uint32_t N) { return BranchProbability(N); }
+ // Create a BranchProbability object from 64-bit integers.
+ static BranchProbability getBranchProbability(uint64_t Numerator,
+ uint64_t Denominator);
+
+ // Normalize given probabilties so that the sum of them becomes approximate
+ // one.
+ template <class ProbabilityIter>
+ static void normalizeProbabilities(ProbabilityIter Begin,
+ ProbabilityIter End);
+
+ uint32_t getNumerator() const { return N; }
+ static uint32_t getDenominator() { return D; }
+
+ // Return (1 - Probability).
+ BranchProbability getCompl() const { return BranchProbability(D - N); }
+
+ raw_ostream &print(raw_ostream &OS) const;
+
+ void dump() const;
+
+ /// Scale a large integer.
+ ///
+ /// Scales \c Num. Guarantees full precision. Returns the floor of the
+ /// result.
+ ///
+ /// \return \c Num times \c this.
+ uint64_t scale(uint64_t Num) const;
+
+ /// Scale a large integer by the inverse.
+ ///
+ /// Scales \c Num by the inverse of \c this. Guarantees full precision.
+ /// Returns the floor of the result.
+ ///
+ /// \return \c Num divided by \c this.
+ uint64_t scaleByInverse(uint64_t Num) const;
+
+ BranchProbability &operator+=(BranchProbability RHS) {
+ assert(N != UnknownN && RHS.N != UnknownN &&
+ "Unknown probability cannot participate in arithmetics.");
+ // Saturate the result in case of overflow.
+ N = (uint64_t(N) + RHS.N > D) ? D : N + RHS.N;
+ return *this;
+ }
+
+ BranchProbability &operator-=(BranchProbability RHS) {
+ assert(N != UnknownN && RHS.N != UnknownN &&
+ "Unknown probability cannot participate in arithmetics.");
+ // Saturate the result in case of underflow.
+ N = N < RHS.N ? 0 : N - RHS.N;
+ return *this;
+ }
+
+ BranchProbability &operator*=(BranchProbability RHS) {
+ assert(N != UnknownN && RHS.N != UnknownN &&
+ "Unknown probability cannot participate in arithmetics.");
+ N = (static_cast<uint64_t>(N) * RHS.N + D / 2) / D;
+ return *this;
+ }
+
+ BranchProbability &operator*=(uint32_t RHS) {
+ assert(N != UnknownN &&
+ "Unknown probability cannot participate in arithmetics.");
+ N = (uint64_t(N) * RHS > D) ? D : N * RHS;
+ return *this;
+ }
+
+ BranchProbability &operator/=(BranchProbability RHS) {
+ assert(N != UnknownN && RHS.N != UnknownN &&
+ "Unknown probability cannot participate in arithmetics.");
+ N = (static_cast<uint64_t>(N) * D + RHS.N / 2) / RHS.N;
+ return *this;
+ }
+
+ BranchProbability &operator/=(uint32_t RHS) {
+ assert(N != UnknownN &&
+ "Unknown probability cannot participate in arithmetics.");
+ assert(RHS > 0 && "The divider cannot be zero.");
+ N /= RHS;
+ return *this;
+ }
+
+ BranchProbability operator+(BranchProbability RHS) const {
+ BranchProbability Prob(*this);
+ Prob += RHS;
+ return Prob;
+ }
+
+ BranchProbability operator-(BranchProbability RHS) const {
+ BranchProbability Prob(*this);
+ Prob -= RHS;
+ return Prob;
+ }
+
+ BranchProbability operator*(BranchProbability RHS) const {
+ BranchProbability Prob(*this);
+ Prob *= RHS;
+ return Prob;
+ }
+
+ BranchProbability operator*(uint32_t RHS) const {
+ BranchProbability Prob(*this);
+ Prob *= RHS;
+ return Prob;
+ }
+
+ BranchProbability operator/(BranchProbability RHS) const {
+ BranchProbability Prob(*this);
+ Prob /= RHS;
+ return Prob;
+ }
+
+ BranchProbability operator/(uint32_t RHS) const {
+ BranchProbability Prob(*this);
+ Prob /= RHS;
+ return Prob;
+ }
+
+ bool operator==(BranchProbability RHS) const { return N == RHS.N; }
+ bool operator!=(BranchProbability RHS) const { return !(*this == RHS); }
+
+ bool operator<(BranchProbability RHS) const {
+ assert(N != UnknownN && RHS.N != UnknownN &&
+ "Unknown probability cannot participate in comparisons.");
+ return N < RHS.N;
+ }
+
+ bool operator>(BranchProbability RHS) const {
+ assert(N != UnknownN && RHS.N != UnknownN &&
+ "Unknown probability cannot participate in comparisons.");
+ return RHS < *this;
+ }
+
+ bool operator<=(BranchProbability RHS) const {
+ assert(N != UnknownN && RHS.N != UnknownN &&
+ "Unknown probability cannot participate in comparisons.");
+ return !(RHS < *this);
+ }
+
+ bool operator>=(BranchProbability RHS) const {
+ assert(N != UnknownN && RHS.N != UnknownN &&
+ "Unknown probability cannot participate in comparisons.");
+ return !(*this < RHS);
+ }
+};
+
+inline raw_ostream &operator<<(raw_ostream &OS, BranchProbability Prob) {
+ return Prob.print(OS);
+}
+
+template <class ProbabilityIter>
+void BranchProbability::normalizeProbabilities(ProbabilityIter Begin,
+ ProbabilityIter End) {
+ if (Begin == End)
+ return;
+
+ unsigned UnknownProbCount = 0;
+ uint64_t Sum = std::accumulate(Begin, End, uint64_t(0),
+ [&](uint64_t S, const BranchProbability &BP) {
+ if (!BP.isUnknown())
+ return S + BP.N;
+ UnknownProbCount++;
+ return S;
+ });
+
+ if (UnknownProbCount > 0) {
+ BranchProbability ProbForUnknown = BranchProbability::getZero();
+ // If the sum of all known probabilities is less than one, evenly distribute
+ // the complement of sum to unknown probabilities. Otherwise, set unknown
+ // probabilities to zeros and continue to normalize known probabilities.
+ if (Sum < BranchProbability::getDenominator())
+ ProbForUnknown = BranchProbability::getRaw(
+ (BranchProbability::getDenominator() - Sum) / UnknownProbCount);
+
+ std::replace_if(Begin, End,
+ [](const BranchProbability &BP) { return BP.isUnknown(); },
+ ProbForUnknown);
+
+ if (Sum <= BranchProbability::getDenominator())
+ return;
+ }
+
+ if (Sum == 0) {
+ BranchProbability BP(1, std::distance(Begin, End));
+ std::fill(Begin, End, BP);
+ return;
+ }
+
+ for (auto I = Begin; I != End; ++I)
+ I->N = (I->N * uint64_t(D) + Sum / 2) / Sum;
+}
+
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/BuryPointer.h b/contrib/libs/llvm16/include/llvm/Support/BuryPointer.h
new file mode 100644
index 00000000000..30dfecd025b
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/BuryPointer.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/BuryPointer.h - Memory Manipulation/Leak ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_BURYPOINTER_H
+#define LLVM_SUPPORT_BURYPOINTER_H
+
+#include <memory>
+
+namespace llvm {
+
+// In tools that will exit soon anyway, going through the process of explicitly
+// deallocating resources can be unnecessary - better to leak the resources and
+// let the OS clean them up when the process ends. Use this function to ensure
+// the memory is not misdiagnosed as an unintentional leak by leak detection
+// tools (this is achieved by preserving pointers to the object in a globally
+// visible array).
+void BuryPointer(const void *Ptr);
+template <typename T> void BuryPointer(std::unique_ptr<T> Ptr) {
+ BuryPointer(Ptr.release());
+}
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CBindingWrapping.h b/contrib/libs/llvm16/include/llvm/Support/CBindingWrapping.h
new file mode 100644
index 00000000000..5b49d226117
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CBindingWrapping.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/CBindingWrapping.h - C Interface Wrapping ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the wrapping macros for the C interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CBINDINGWRAPPING_H
+#define LLVM_SUPPORT_CBINDINGWRAPPING_H
+
+#include "llvm-c/Types.h"
+#include "llvm/Support/Casting.h"
+
+#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \
+ inline ty *unwrap(ref P) { \
+ return reinterpret_cast<ty*>(P); \
+ } \
+ \
+ inline ref wrap(const ty *P) { \
+ return reinterpret_cast<ref>(const_cast<ty*>(P)); \
+ }
+
+#define DEFINE_ISA_CONVERSION_FUNCTIONS(ty, ref) \
+ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \
+ \
+ template<typename T> \
+ inline T *unwrap(ref P) { \
+ return cast<T>(unwrap(P)); \
+ }
+
+#define DEFINE_STDCXX_CONVERSION_FUNCTIONS(ty, ref) \
+ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref) \
+ \
+ template<typename T> \
+ inline T *unwrap(ref P) { \
+ T *Q = (T*)unwrap(P); \
+ assert(Q && "Invalid cast!"); \
+ return Q; \
+ }
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CFGDiff.h b/contrib/libs/llvm16/include/llvm/Support/CFGDiff.h
new file mode 100644
index 00000000000..398314b4fce
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CFGDiff.h
@@ -0,0 +1,188 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- CFGDiff.h - Define a CFG snapshot. -----------------------*- 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 defines specializations of GraphTraits that allows generic
+// algorithms to see a different snapshot of a CFG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CFGDIFF_H
+#define LLVM_SUPPORT_CFGDIFF_H
+
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/CFGUpdate.h"
+#include "llvm/Support/type_traits.h"
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+
+// Two booleans are used to define orders in graphs:
+// InverseGraph defines when we need to reverse the whole graph and is as such
+// also equivalent to applying updates in reverse.
+// InverseEdge defines whether we want to change the edges direction. E.g., for
+// a non-inversed graph, the children are naturally the successors when
+// InverseEdge is false and the predecessors when InverseEdge is true.
+
+namespace llvm {
+
+namespace detail {
+template <typename Range>
+auto reverse_if_helper(Range &&R, std::integral_constant<bool, false>) {
+ return std::forward<Range>(R);
+}
+
+template <typename Range>
+auto reverse_if_helper(Range &&R, std::integral_constant<bool, true>) {
+ return llvm::reverse(std::forward<Range>(R));
+}
+
+template <bool B, typename Range> auto reverse_if(Range &&R) {
+ return reverse_if_helper(std::forward<Range>(R),
+ std::integral_constant<bool, B>{});
+}
+} // namespace detail
+
+// GraphDiff defines a CFG snapshot: given a set of Update<NodePtr>, provides
+// a getChildren method to get a Node's children based on the additional updates
+// in the snapshot. The current diff treats the CFG as a graph rather than a
+// multigraph. Added edges are pruned to be unique, and deleted edges will
+// remove all existing edges between two blocks.
+template <typename NodePtr, bool InverseGraph = false> class GraphDiff {
+ struct DeletesInserts {
+ SmallVector<NodePtr, 2> DI[2];
+ };
+ using UpdateMapType = SmallDenseMap<NodePtr, DeletesInserts>;
+ UpdateMapType Succ;
+ UpdateMapType Pred;
+
+ // By default, it is assumed that, given a CFG and a set of updates, we wish
+ // to apply these updates as given. If UpdatedAreReverseApplied is set, the
+ // updates will be applied in reverse: deleted edges are considered re-added
+ // and inserted edges are considered deleted when returning children.
+ bool UpdatedAreReverseApplied;
+
+ // Keep the list of legalized updates for a deterministic order of updates
+ // when using a GraphDiff for incremental updates in the DominatorTree.
+ // The list is kept in reverse to allow popping from end.
+ SmallVector<cfg::Update<NodePtr>, 4> LegalizedUpdates;
+
+ void printMap(raw_ostream &OS, const UpdateMapType &M) const {
+ StringRef DIText[2] = {"Delete", "Insert"};
+ for (auto Pair : M) {
+ for (unsigned IsInsert = 0; IsInsert <= 1; ++IsInsert) {
+ OS << DIText[IsInsert] << " edges: \n";
+ for (auto Child : Pair.second.DI[IsInsert]) {
+ OS << "(";
+ Pair.first->printAsOperand(OS, false);
+ OS << ", ";
+ Child->printAsOperand(OS, false);
+ OS << ") ";
+ }
+ }
+ }
+ OS << "\n";
+ }
+
+public:
+ GraphDiff() : UpdatedAreReverseApplied(false) {}
+ GraphDiff(ArrayRef<cfg::Update<NodePtr>> Updates,
+ bool ReverseApplyUpdates = false) {
+ cfg::LegalizeUpdates<NodePtr>(Updates, LegalizedUpdates, InverseGraph);
+ for (auto U : LegalizedUpdates) {
+ unsigned IsInsert =
+ (U.getKind() == cfg::UpdateKind::Insert) == !ReverseApplyUpdates;
+ Succ[U.getFrom()].DI[IsInsert].push_back(U.getTo());
+ Pred[U.getTo()].DI[IsInsert].push_back(U.getFrom());
+ }
+ UpdatedAreReverseApplied = ReverseApplyUpdates;
+ }
+
+ auto getLegalizedUpdates() const {
+ return make_range(LegalizedUpdates.begin(), LegalizedUpdates.end());
+ }
+
+ unsigned getNumLegalizedUpdates() const { return LegalizedUpdates.size(); }
+
+ cfg::Update<NodePtr> popUpdateForIncrementalUpdates() {
+ assert(!LegalizedUpdates.empty() && "No updates to apply!");
+ auto U = LegalizedUpdates.pop_back_val();
+ unsigned IsInsert =
+ (U.getKind() == cfg::UpdateKind::Insert) == !UpdatedAreReverseApplied;
+ auto &SuccDIList = Succ[U.getFrom()];
+ auto &SuccList = SuccDIList.DI[IsInsert];
+ assert(SuccList.back() == U.getTo());
+ SuccList.pop_back();
+ if (SuccList.empty() && SuccDIList.DI[!IsInsert].empty())
+ Succ.erase(U.getFrom());
+
+ auto &PredDIList = Pred[U.getTo()];
+ auto &PredList = PredDIList.DI[IsInsert];
+ assert(PredList.back() == U.getFrom());
+ PredList.pop_back();
+ if (PredList.empty() && PredDIList.DI[!IsInsert].empty())
+ Pred.erase(U.getTo());
+ return U;
+ }
+
+ using VectRet = SmallVector<NodePtr, 8>;
+ template <bool InverseEdge> VectRet getChildren(NodePtr N) const {
+ using DirectedNodeT =
+ std::conditional_t<InverseEdge, Inverse<NodePtr>, NodePtr>;
+ auto R = children<DirectedNodeT>(N);
+ VectRet Res = VectRet(detail::reverse_if<!InverseEdge>(R));
+
+ // Remove nullptr children for clang.
+ llvm::erase_value(Res, nullptr);
+
+ auto &Children = (InverseEdge != InverseGraph) ? Pred : Succ;
+ auto It = Children.find(N);
+ if (It == Children.end())
+ return Res;
+
+ // Remove children present in the CFG but not in the snapshot.
+ for (auto *Child : It->second.DI[0])
+ llvm::erase_value(Res, Child);
+
+ // Add children present in the snapshot for not in the real CFG.
+ auto &AddedChildren = It->second.DI[1];
+ llvm::append_range(Res, AddedChildren);
+
+ return Res;
+ }
+
+ void print(raw_ostream &OS) const {
+ OS << "===== GraphDiff: CFG edge changes to create a CFG snapshot. \n"
+ "===== (Note: notion of children/inverse_children depends on "
+ "the direction of edges and the graph.)\n";
+ OS << "Children to delete/insert:\n\t";
+ printMap(OS, Succ);
+ OS << "Inverse_children to delete/insert:\n\t";
+ printMap(OS, Pred);
+ OS << "\n";
+ }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
+#endif
+};
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_CFGDIFF_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CFGUpdate.h b/contrib/libs/llvm16/include/llvm/Support/CFGUpdate.h
new file mode 100644
index 00000000000..41ea4d0fcb9
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CFGUpdate.h
@@ -0,0 +1,128 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- CFGUpdate.h - Encode a CFG Edge Update. ------------------*- 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 defines a CFG Edge Update: Insert or Delete, and two Nodes as the
+// Edge ends.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CFGUPDATE_H
+#define LLVM_SUPPORT_CFGUPDATE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace cfg {
+enum class UpdateKind : unsigned char { Insert, Delete };
+
+template <typename NodePtr> class Update {
+ using NodeKindPair = PointerIntPair<NodePtr, 1, UpdateKind>;
+ NodePtr From;
+ NodeKindPair ToAndKind;
+
+public:
+ Update(UpdateKind Kind, NodePtr From, NodePtr To)
+ : From(From), ToAndKind(To, Kind) {}
+
+ UpdateKind getKind() const { return ToAndKind.getInt(); }
+ NodePtr getFrom() const { return From; }
+ NodePtr getTo() const { return ToAndKind.getPointer(); }
+ bool operator==(const Update &RHS) const {
+ return From == RHS.From && ToAndKind == RHS.ToAndKind;
+ }
+
+ void print(raw_ostream &OS) const {
+ OS << (getKind() == UpdateKind::Insert ? "Insert " : "Delete ");
+ getFrom()->printAsOperand(OS, false);
+ OS << " -> ";
+ getTo()->printAsOperand(OS, false);
+ }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
+#endif
+};
+
+// LegalizeUpdates function simplifies updates assuming a graph structure.
+// This function serves double purpose:
+// a) It removes redundant updates, which makes it easier to reverse-apply
+// them when traversing CFG.
+// b) It optimizes away updates that cancel each other out, as the end result
+// is the same.
+template <typename NodePtr>
+void LegalizeUpdates(ArrayRef<Update<NodePtr>> AllUpdates,
+ SmallVectorImpl<Update<NodePtr>> &Result,
+ bool InverseGraph, bool ReverseResultOrder = false) {
+ // Count the total number of inserions of each edge.
+ // Each insertion adds 1 and deletion subtracts 1. The end number should be
+ // one of {-1 (deletion), 0 (NOP), +1 (insertion)}. Otherwise, the sequence
+ // of updates contains multiple updates of the same kind and we assert for
+ // that case.
+ SmallDenseMap<std::pair<NodePtr, NodePtr>, int, 4> Operations;
+ Operations.reserve(AllUpdates.size());
+
+ for (const auto &U : AllUpdates) {
+ NodePtr From = U.getFrom();
+ NodePtr To = U.getTo();
+ if (InverseGraph)
+ std::swap(From, To); // Reverse edge for postdominators.
+
+ Operations[{From, To}] += (U.getKind() == UpdateKind::Insert ? 1 : -1);
+ }
+
+ Result.clear();
+ Result.reserve(Operations.size());
+ for (auto &Op : Operations) {
+ const int NumInsertions = Op.second;
+ assert(std::abs(NumInsertions) <= 1 && "Unbalanced operations!");
+ if (NumInsertions == 0)
+ continue;
+ const UpdateKind UK =
+ NumInsertions > 0 ? UpdateKind::Insert : UpdateKind::Delete;
+ Result.push_back({UK, Op.first.first, Op.first.second});
+ }
+
+ // Make the order consistent by not relying on pointer values within the
+ // set. Reuse the old Operations map.
+ // In the future, we should sort by something else to minimize the amount
+ // of work needed to perform the series of updates.
+ for (size_t i = 0, e = AllUpdates.size(); i != e; ++i) {
+ const auto &U = AllUpdates[i];
+ if (!InverseGraph)
+ Operations[{U.getFrom(), U.getTo()}] = int(i);
+ else
+ Operations[{U.getTo(), U.getFrom()}] = int(i);
+ }
+
+ llvm::sort(Result, [&](const Update<NodePtr> &A, const Update<NodePtr> &B) {
+ const auto &OpA = Operations[{A.getFrom(), A.getTo()}];
+ const auto &OpB = Operations[{B.getFrom(), B.getTo()}];
+ return ReverseResultOrder ? OpA < OpB : OpA > OpB;
+ });
+}
+
+} // end namespace cfg
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_CFGUPDATE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/COM.h b/contrib/libs/llvm16/include/llvm/Support/COM.h
new file mode 100644
index 00000000000..5f927107315
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/COM.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/COM.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// Provides a library for accessing COM functionality of the Host OS.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_COM_H
+#define LLVM_SUPPORT_COM_H
+
+namespace llvm {
+namespace sys {
+
+enum class COMThreadingMode { SingleThreaded, MultiThreaded };
+
+class InitializeCOMRAII {
+public:
+ explicit InitializeCOMRAII(COMThreadingMode Threading,
+ bool SpeedOverMemory = false);
+ ~InitializeCOMRAII();
+
+private:
+ InitializeCOMRAII(const InitializeCOMRAII &) = delete;
+ void operator=(const InitializeCOMRAII &) = delete;
+};
+}
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CRC.h b/contrib/libs/llvm16/include/llvm/Support/CRC.h
new file mode 100644
index 00000000000..22d2768fc50
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CRC.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/CRC.h - Cyclic Redundancy Check-------------*- 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 implementations of CRC functions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CRC_H
+#define LLVM_SUPPORT_CRC_H
+
+#include "llvm/Support/DataTypes.h"
+
+namespace llvm {
+template <typename T> class ArrayRef;
+
+// Compute the CRC-32 of Data.
+uint32_t crc32(ArrayRef<uint8_t> Data);
+
+// Compute the running CRC-32 of Data, with CRC being the previous value of the
+// checksum.
+uint32_t crc32(uint32_t CRC, ArrayRef<uint8_t> Data);
+
+// Class for computing the JamCRC.
+//
+// We will use the "Rocksoft^tm Model CRC Algorithm" to describe the properties
+// of this CRC:
+// Width : 32
+// Poly : 04C11DB7
+// Init : FFFFFFFF
+// RefIn : True
+// RefOut : True
+// XorOut : 00000000
+// Check : 340BC6D9 (result of CRC for "123456789")
+//
+// In other words, this is the same as CRC-32, except that XorOut is 0 instead
+// of FFFFFFFF.
+//
+// N.B. We permit flexibility of the "Init" value. Some consumers of this need
+// it to be zero.
+class JamCRC {
+public:
+ JamCRC(uint32_t Init = 0xFFFFFFFFU) : CRC(Init) {}
+
+ // Update the CRC calculation with Data.
+ void update(ArrayRef<uint8_t> Data);
+
+ uint32_t getCRC() const { return CRC; }
+
+private:
+ uint32_t CRC;
+};
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CSKYAttributeParser.h b/contrib/libs/llvm16/include/llvm/Support/CSKYAttributeParser.h
new file mode 100644
index 00000000000..082427b42a5
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CSKYAttributeParser.h
@@ -0,0 +1,54 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===---- CSKYAttributeParser.h - CSKY Attribute Parser ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CSKYATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_CSKYATTRIBUTEPARSER_H
+
+#include "llvm/Support/CSKYAttributes.h"
+#include "llvm/Support/ELFAttributeParser.h"
+
+namespace llvm {
+class CSKYAttributeParser : public ELFAttributeParser {
+ struct DisplayHandler {
+ CSKYAttrs::AttrType attribute;
+ Error (CSKYAttributeParser::*routine)(unsigned);
+ };
+ static const DisplayHandler displayRoutines[];
+
+ Error dspVersion(unsigned tag);
+ Error vdspVersion(unsigned tag);
+ Error fpuVersion(unsigned tag);
+ Error fpuABI(unsigned tag);
+ Error fpuRounding(unsigned tag);
+ Error fpuDenormal(unsigned tag);
+ Error fpuException(unsigned tag);
+ Error fpuHardFP(unsigned tag);
+
+ Error handler(uint64_t tag, bool &handled) override;
+
+public:
+ CSKYAttributeParser(ScopedPrinter *sw)
+ : ELFAttributeParser(sw, CSKYAttrs::getCSKYAttributeTags(), "csky") {}
+ CSKYAttributeParser()
+ : ELFAttributeParser(CSKYAttrs::getCSKYAttributeTags(), "csky") {}
+};
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CSKYAttributes.h b/contrib/libs/llvm16/include/llvm/Support/CSKYAttributes.h
new file mode 100644
index 00000000000..824bec45f93
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CSKYAttributes.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===---- CSKYAttributes.h - CSKY Attributes --------------------*- 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 enumerations for CSKY attributes.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_CSKYATTRIBUTES_H
+#define LLVM_SUPPORT_CSKYATTRIBUTES_H
+
+#include "llvm/Support/ELFAttributes.h"
+
+namespace llvm {
+namespace CSKYAttrs {
+
+const TagNameMap &getCSKYAttributeTags();
+
+enum AttrType {
+ CSKY_ARCH_NAME = 4,
+ CSKY_CPU_NAME = 5,
+ CSKY_ISA_FLAGS = 6,
+ CSKY_ISA_EXT_FLAGS = 7,
+ CSKY_DSP_VERSION = 8,
+ CSKY_VDSP_VERSION = 9,
+ CSKY_FPU_VERSION = 16,
+ CSKY_FPU_ABI = 17,
+ CSKY_FPU_ROUNDING = 18,
+ CSKY_FPU_DENORMAL = 19,
+ CSKY_FPU_EXCEPTION = 20,
+ CSKY_FPU_NUMBER_MODULE = 21,
+ CSKY_FPU_HARDFP = 22
+};
+
+enum ISA_FLAGS {
+ V2_ISA_E1 = 1 << 1,
+ V2_ISA_1E2 = 1 << 2,
+ V2_ISA_2E3 = 1 << 3,
+ V2_ISA_3E7 = 1 << 4,
+ V2_ISA_7E10 = 1 << 5,
+ V2_ISA_3E3R1 = 1 << 6,
+ V2_ISA_3E3R2 = 1 << 7,
+ V2_ISA_10E60 = 1 << 8,
+ V2_ISA_3E3R3 = 1 << 9,
+ ISA_TRUST = 1 << 11,
+ ISA_CACHE = 1 << 12,
+ ISA_NVIC = 1 << 13,
+ ISA_CP = 1 << 14,
+ ISA_MP = 1 << 15,
+ ISA_MP_1E2 = 1 << 16,
+ ISA_JAVA = 1 << 17,
+ ISA_MAC = 1 << 18,
+ ISA_MAC_DSP = 1 << 19,
+ ISA_DSP = 1 << 20,
+ ISA_DSP_1E2 = 1 << 21,
+ ISA_DSP_ENHANCE = 1 << 22,
+ ISA_DSP_SILAN = 1 << 23,
+ ISA_VDSP = 1 << 24,
+ ISA_VDSP_2 = 1 << 25,
+ ISA_VDSP_2E3 = 1 << 26,
+ V2_ISA_DSPE60 = 1 << 27,
+ ISA_VDSP_2E60F = 1 << 28
+};
+
+enum ISA_EXT_FLAGS {
+ ISA_FLOAT_E1 = 1 << 0,
+ ISA_FLOAT_1E2 = 1 << 1,
+ ISA_FLOAT_1E3 = 1 << 2,
+ ISA_FLOAT_3E4 = 1 << 3,
+ ISA_FLOAT_7E60 = 1 << 4
+};
+
+enum { NONE = 0, NEEDED = 1 };
+
+enum DSP_VERSION { DSP_VERSION_EXTENSION = 1, DSP_VERSION_2 = 2 };
+
+enum VDSP_VERSION { VDSP_VERSION_1 = 1, VDSP_VERSION_2 = 2 };
+
+enum FPU_VERSION { FPU_VERSION_1 = 1, FPU_VERSION_2 = 2, FPU_VERSION_3 = 3 };
+
+enum FPU_ABI { FPU_ABI_SOFT = 1, FPU_ABI_SOFTFP = 2, FPU_ABI_HARD = 3 };
+
+enum FPU_HARDFP {
+ FPU_HARDFP_HALF = 1,
+ FPU_HARDFP_SINGLE = 2,
+ FPU_HARDFP_DOUBLE = 4
+};
+
+} // namespace CSKYAttrs
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CSKYTargetParser.h b/contrib/libs/llvm16/include/llvm/Support/CSKYTargetParser.h
new file mode 100644
index 00000000000..d4214c6df68
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CSKYTargetParser.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/CSKYTargetParser.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This header is deprecated in favour of
+/// `llvm/TargetParser/CSKYTargetParser.h`.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/CSKYTargetParser.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CachePruning.h b/contrib/libs/llvm16/include/llvm/Support/CachePruning.h
new file mode 100644
index 00000000000..d0ed0a1d28c
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CachePruning.h
@@ -0,0 +1,97 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//=- CachePruning.h - Helper to manage the pruning of a cache dir -*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements pruning of a directory intended for cache storage, using
+// various policies.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CACHEPRUNING_H
+#define LLVM_SUPPORT_CACHEPRUNING_H
+
+#include "llvm/Support/MemoryBuffer.h"
+#include <chrono>
+#include <optional>
+
+namespace llvm {
+
+template <typename T> class Expected;
+class StringRef;
+
+/// Policy for the pruneCache() function. A default constructed
+/// CachePruningPolicy provides a reasonable default policy.
+struct CachePruningPolicy {
+ /// The pruning interval. This is intended to be used to avoid scanning the
+ /// directory too often. It does not impact the decision of which file to
+ /// prune. A value of 0 forces the scan to occur. A value of None disables
+ /// pruning.
+ std::optional<std::chrono::seconds> Interval = std::chrono::seconds(1200);
+
+ /// The expiration for a file. When a file hasn't been accessed for Expiration
+ /// seconds, it is removed from the cache. A value of 0 disables the
+ /// expiration-based pruning.
+ std::chrono::seconds Expiration = std::chrono::hours(7 * 24); // 1w
+
+ /// The maximum size for the cache directory, in terms of percentage of the
+ /// available space on the disk. Set to 100 to indicate no limit, 50 to
+ /// indicate that the cache size will not be left over half the available disk
+ /// space. A value over 100 will be reduced to 100. A value of 0 disables the
+ /// percentage size-based pruning.
+ unsigned MaxSizePercentageOfAvailableSpace = 75;
+
+ /// The maximum size for the cache directory in bytes. A value over the amount
+ /// of available space on the disk will be reduced to the amount of available
+ /// space. A value of 0 disables the absolute size-based pruning.
+ uint64_t MaxSizeBytes = 0;
+
+ /// The maximum number of files in the cache directory. A value of 0 disables
+ /// the number of files based pruning.
+ ///
+ /// This defaults to 1000000 because with that many files there are
+ /// diminishing returns on the effectiveness of the cache. Some systems have a
+ /// limit on total number of files, and some also limit the number of files
+ /// per directory, such as Linux ext4, with the default setting (block size is
+ /// 4096 and large_dir disabled), there is a per-directory entry limit of
+ /// 508*510*floor(4096/(40+8))~=20M for average filename length of 40.
+ uint64_t MaxSizeFiles = 1000000;
+};
+
+/// Parse the given string as a cache pruning policy. Defaults are taken from a
+/// default constructed CachePruningPolicy object.
+/// For example: "prune_interval=30s:prune_after=24h:cache_size=50%"
+/// which means a pruning interval of 30 seconds, expiration time of 24 hours
+/// and maximum cache size of 50% of available disk space.
+Expected<CachePruningPolicy> parseCachePruningPolicy(StringRef PolicyStr);
+
+/// Peform pruning using the supplied policy, returns true if pruning
+/// occurred, i.e. if Policy.Interval was expired.
+///
+/// Check whether cache pruning happens using the supplied policy, adds a
+/// ThinLTO warning if cache_size_bytes or cache_size_files is too small for the
+/// current link job. The warning recommends the user to consider adjusting
+/// --thinlto-cache-policy.
+///
+/// As a safeguard against data loss if the user specifies the wrong directory
+/// as their cache directory, this function will ignore files not matching the
+/// pattern "llvmcache-*".
+bool pruneCache(StringRef Path, CachePruningPolicy Policy,
+ const std::vector<std::unique_ptr<MemoryBuffer>> &Files = {});
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Caching.h b/contrib/libs/llvm16/include/llvm/Support/Caching.h
new file mode 100644
index 00000000000..68c7111b0e2
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Caching.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- Caching.h - LLVM Local File Cache ------------------------*- 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 defines the CachedFileStream and the localCache function, which
+// simplifies caching files on the local filesystem in a directory whose
+// contents are managed by a CachePruningPolicy.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CACHING_H
+#define LLVM_SUPPORT_CACHING_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+class MemoryBuffer;
+
+/// This class wraps an output stream for a file. Most clients should just be
+/// able to return an instance of this base class from the stream callback, but
+/// if a client needs to perform some action after the stream is written to,
+/// that can be done by deriving from this class and overriding the destructor.
+class CachedFileStream {
+public:
+ CachedFileStream(std::unique_ptr<raw_pwrite_stream> OS,
+ std::string OSPath = "")
+ : OS(std::move(OS)), ObjectPathName(OSPath) {}
+ std::unique_ptr<raw_pwrite_stream> OS;
+ std::string ObjectPathName;
+ virtual ~CachedFileStream() = default;
+};
+
+/// This type defines the callback to add a file that is generated on the fly.
+///
+/// Stream callbacks must be thread safe.
+using AddStreamFn = std::function<Expected<std::unique_ptr<CachedFileStream>>(
+ unsigned Task, const Twine &ModuleName)>;
+
+/// This is the type of a file cache. To request an item from the cache, pass a
+/// unique string as the Key. For hits, the cached file will be added to the
+/// link and this function will return AddStreamFn(). For misses, the cache will
+/// return a stream callback which must be called at most once to produce
+/// content for the stream. The file stream produced by the stream callback will
+/// add the file to the link after the stream is written to. ModuleName is the
+/// unique module identifier for the bitcode module the cache is being checked
+/// for.
+///
+/// Clients generally look like this:
+///
+/// if (AddStreamFn AddStream = Cache(Task, Key, ModuleName))
+/// ProduceContent(AddStream);
+using FileCache = std::function<Expected<AddStreamFn>(
+ unsigned Task, StringRef Key, const Twine &ModuleName)>;
+
+/// This type defines the callback to add a pre-existing file (e.g. in a cache).
+///
+/// Buffer callbacks must be thread safe.
+using AddBufferFn = std::function<void(unsigned Task, const Twine &ModuleName,
+ std::unique_ptr<MemoryBuffer> MB)>;
+
+/// Create a local file system cache which uses the given cache name, temporary
+/// file prefix, cache directory and file callback. This function does not
+/// immediately create the cache directory if it does not yet exist; this is
+/// done lazily the first time a file is added. The cache name appears in error
+/// messages for errors during caching. The temporary file prefix is used in the
+/// temporary file naming scheme used when writing files atomically.
+Expected<FileCache> localCache(
+ const Twine &CacheNameRef, const Twine &TempFilePrefixRef,
+ const Twine &CacheDirectoryPathRef,
+ AddBufferFn AddBuffer = [](size_t Task, const Twine &ModuleName,
+ std::unique_ptr<MemoryBuffer> MB) {});
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Capacity.h b/contrib/libs/llvm16/include/llvm/Support/Capacity.h
new file mode 100644
index 00000000000..263a5475095
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Capacity.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- Capacity.h - Generic computation of ADT memory use -----*- 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 defines the capacity function that computes the amount of
+// memory used by an ADT.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CAPACITY_H
+#define LLVM_SUPPORT_CAPACITY_H
+
+#include <cstddef>
+
+namespace llvm {
+
+template <typename T>
+static inline size_t capacity_in_bytes(const T &x) {
+ // This default definition of capacity should work for things like std::vector
+ // and friends. More specialized versions will work for others.
+ return x.capacity() * sizeof(typename T::value_type);
+}
+
+} // end namespace llvm
+
+#endif
+
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Casting.h b/contrib/libs/llvm16/include/llvm/Support/Casting.h
new file mode 100644
index 00000000000..d2cf49b7fd4
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Casting.h
@@ -0,0 +1,819 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Casting.h - Allow flexible, checked, casts --*- 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 defines the isa<X>(), cast<X>(), dyn_cast<X>(),
+// cast_if_present<X>(), and dyn_cast_if_present<X>() templates.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CASTING_H
+#define LLVM_SUPPORT_CASTING_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/type_traits.h"
+#include <cassert>
+#include <memory>
+#include <optional>
+#include <type_traits>
+
+namespace llvm {
+
+//===----------------------------------------------------------------------===//
+// simplify_type
+//===----------------------------------------------------------------------===//
+
+/// Define a template that can be specialized by smart pointers to reflect the
+/// fact that they are automatically dereferenced, and are not involved with the
+/// template selection process... the default implementation is a noop.
+// TODO: rename this and/or replace it with other cast traits.
+template <typename From> struct simplify_type {
+ using SimpleType = From; // The real type this represents...
+
+ // An accessor to get the real value...
+ static SimpleType &getSimplifiedValue(From &Val) { return Val; }
+};
+
+template <typename From> struct simplify_type<const From> {
+ using NonConstSimpleType = typename simplify_type<From>::SimpleType;
+ using SimpleType = typename add_const_past_pointer<NonConstSimpleType>::type;
+ using RetType =
+ typename add_lvalue_reference_if_not_pointer<SimpleType>::type;
+
+ static RetType getSimplifiedValue(const From &Val) {
+ return simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val));
+ }
+};
+
+// TODO: add this namespace once everyone is switched to using the new
+// interface.
+// namespace detail {
+
+//===----------------------------------------------------------------------===//
+// isa_impl
+//===----------------------------------------------------------------------===//
+
+// The core of the implementation of isa<X> is here; To and From should be
+// the names of classes. This template can be specialized to customize the
+// implementation of isa<> without rewriting it from scratch.
+template <typename To, typename From, typename Enabler = void> struct isa_impl {
+ static inline bool doit(const From &Val) { return To::classof(&Val); }
+};
+
+// Always allow upcasts, and perform no dynamic check for them.
+template <typename To, typename From>
+struct isa_impl<To, From, std::enable_if_t<std::is_base_of<To, From>::value>> {
+ static inline bool doit(const From &) { return true; }
+};
+
+template <typename To, typename From> struct isa_impl_cl {
+ static inline bool doit(const From &Val) {
+ return isa_impl<To, From>::doit(Val);
+ }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, const From> {
+ static inline bool doit(const From &Val) {
+ return isa_impl<To, From>::doit(Val);
+ }
+};
+
+template <typename To, typename From>
+struct isa_impl_cl<To, const std::unique_ptr<From>> {
+ static inline bool doit(const std::unique_ptr<From> &Val) {
+ assert(Val && "isa<> used on a null pointer");
+ return isa_impl_cl<To, From>::doit(*Val);
+ }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, From *> {
+ static inline bool doit(const From *Val) {
+ assert(Val && "isa<> used on a null pointer");
+ return isa_impl<To, From>::doit(*Val);
+ }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, From *const> {
+ static inline bool doit(const From *Val) {
+ assert(Val && "isa<> used on a null pointer");
+ return isa_impl<To, From>::doit(*Val);
+ }
+};
+
+template <typename To, typename From> struct isa_impl_cl<To, const From *> {
+ static inline bool doit(const From *Val) {
+ assert(Val && "isa<> used on a null pointer");
+ return isa_impl<To, From>::doit(*Val);
+ }
+};
+
+template <typename To, typename From>
+struct isa_impl_cl<To, const From *const> {
+ static inline bool doit(const From *Val) {
+ assert(Val && "isa<> used on a null pointer");
+ return isa_impl<To, From>::doit(*Val);
+ }
+};
+
+template <typename To, typename From, typename SimpleFrom>
+struct isa_impl_wrap {
+ // When From != SimplifiedType, we can simplify the type some more by using
+ // the simplify_type template.
+ static bool doit(const From &Val) {
+ return isa_impl_wrap<To, SimpleFrom,
+ typename simplify_type<SimpleFrom>::SimpleType>::
+ doit(simplify_type<const From>::getSimplifiedValue(Val));
+ }
+};
+
+template <typename To, typename FromTy>
+struct isa_impl_wrap<To, FromTy, FromTy> {
+ // When From == SimpleType, we are as simple as we are going to get.
+ static bool doit(const FromTy &Val) {
+ return isa_impl_cl<To, FromTy>::doit(Val);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// cast_retty + cast_retty_impl
+//===----------------------------------------------------------------------===//
+
+template <class To, class From> struct cast_retty;
+
+// Calculate what type the 'cast' function should return, based on a requested
+// type of To and a source type of From.
+template <class To, class From> struct cast_retty_impl {
+ using ret_type = To &; // Normal case, return Ty&
+};
+template <class To, class From> struct cast_retty_impl<To, const From> {
+ using ret_type = const To &; // Normal case, return Ty&
+};
+
+template <class To, class From> struct cast_retty_impl<To, From *> {
+ using ret_type = To *; // Pointer arg case, return Ty*
+};
+
+template <class To, class From> struct cast_retty_impl<To, const From *> {
+ using ret_type = const To *; // Constant pointer arg case, return const Ty*
+};
+
+template <class To, class From> struct cast_retty_impl<To, const From *const> {
+ using ret_type = const To *; // Constant pointer arg case, return const Ty*
+};
+
+template <class To, class From>
+struct cast_retty_impl<To, std::unique_ptr<From>> {
+private:
+ using PointerType = typename cast_retty_impl<To, From *>::ret_type;
+ using ResultType = std::remove_pointer_t<PointerType>;
+
+public:
+ using ret_type = std::unique_ptr<ResultType>;
+};
+
+template <class To, class From, class SimpleFrom> struct cast_retty_wrap {
+ // When the simplified type and the from type are not the same, use the type
+ // simplifier to reduce the type, then reuse cast_retty_impl to get the
+ // resultant type.
+ using ret_type = typename cast_retty<To, SimpleFrom>::ret_type;
+};
+
+template <class To, class FromTy> struct cast_retty_wrap<To, FromTy, FromTy> {
+ // When the simplified type is equal to the from type, use it directly.
+ using ret_type = typename cast_retty_impl<To, FromTy>::ret_type;
+};
+
+template <class To, class From> struct cast_retty {
+ using ret_type = typename cast_retty_wrap<
+ To, From, typename simplify_type<From>::SimpleType>::ret_type;
+};
+
+//===----------------------------------------------------------------------===//
+// cast_convert_val
+//===----------------------------------------------------------------------===//
+
+// Ensure the non-simple values are converted using the simplify_type template
+// that may be specialized by smart pointers...
+//
+template <class To, class From, class SimpleFrom> struct cast_convert_val {
+ // This is not a simple type, use the template to simplify it...
+ static typename cast_retty<To, From>::ret_type doit(const From &Val) {
+ return cast_convert_val<To, SimpleFrom,
+ typename simplify_type<SimpleFrom>::SimpleType>::
+ doit(simplify_type<From>::getSimplifiedValue(const_cast<From &>(Val)));
+ }
+};
+
+template <class To, class FromTy> struct cast_convert_val<To, FromTy, FromTy> {
+ // If it's a reference, switch to a pointer to do the cast and then deref it.
+ static typename cast_retty<To, FromTy>::ret_type doit(const FromTy &Val) {
+ return *(std::remove_reference_t<typename cast_retty<To, FromTy>::ret_type>
+ *)&const_cast<FromTy &>(Val);
+ }
+};
+
+template <class To, class FromTy>
+struct cast_convert_val<To, FromTy *, FromTy *> {
+ // If it's a pointer, we can use c-style casting directly.
+ static typename cast_retty<To, FromTy *>::ret_type doit(const FromTy *Val) {
+ return (typename cast_retty<To, FromTy *>::ret_type) const_cast<FromTy *>(
+ Val);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// is_simple_type
+//===----------------------------------------------------------------------===//
+
+template <class X> struct is_simple_type {
+ static const bool value =
+ std::is_same<X, typename simplify_type<X>::SimpleType>::value;
+};
+
+// } // namespace detail
+
+//===----------------------------------------------------------------------===//
+// CastIsPossible
+//===----------------------------------------------------------------------===//
+
+/// This struct provides a way to check if a given cast is possible. It provides
+/// a static function called isPossible that is used to check if a cast can be
+/// performed. It should be overridden like this:
+///
+/// template<> struct CastIsPossible<foo, bar> {
+/// static inline bool isPossible(const bar &b) {
+/// return bar.isFoo();
+/// }
+/// };
+template <typename To, typename From, typename Enable = void>
+struct CastIsPossible {
+ static inline bool isPossible(const From &f) {
+ return isa_impl_wrap<
+ To, const From,
+ typename simplify_type<const From>::SimpleType>::doit(f);
+ }
+};
+
+// Needed for optional unwrapping. This could be implemented with isa_impl, but
+// we want to implement things in the new method and move old implementations
+// over. In fact, some of the isa_impl templates should be moved over to
+// CastIsPossible.
+template <typename To, typename From>
+struct CastIsPossible<To, std::optional<From>> {
+ static inline bool isPossible(const std::optional<From> &f) {
+ assert(f && "CastIsPossible::isPossible called on a nullopt!");
+ return isa_impl_wrap<
+ To, const From,
+ typename simplify_type<const From>::SimpleType>::doit(*f);
+ }
+};
+
+/// Upcasting (from derived to base) and casting from a type to itself should
+/// always be possible.
+template <typename To, typename From>
+struct CastIsPossible<To, From,
+ std::enable_if_t<std::is_base_of<To, From>::value>> {
+ static inline bool isPossible(const From &f) { return true; }
+};
+
+//===----------------------------------------------------------------------===//
+// Cast traits
+//===----------------------------------------------------------------------===//
+
+/// All of these cast traits are meant to be implementations for useful casts
+/// that users may want to use that are outside the standard behavior. An
+/// example of how to use a special cast called `CastTrait` is:
+///
+/// template<> struct CastInfo<foo, bar> : public CastTrait<foo, bar> {};
+///
+/// Essentially, if your use case falls directly into one of the use cases
+/// supported by a given cast trait, simply inherit your special CastInfo
+/// directly from one of these to avoid having to reimplement the boilerplate
+/// `isPossible/castFailed/doCast/doCastIfPossible`. A cast trait can also
+/// provide a subset of those functions.
+
+/// This cast trait just provides castFailed for the specified `To` type to make
+/// CastInfo specializations more declarative. In order to use this, the target
+/// result type must be `To` and `To` must be constructible from `nullptr`.
+template <typename To> struct NullableValueCastFailed {
+ static To castFailed() { return To(nullptr); }
+};
+
+/// This cast trait just provides the default implementation of doCastIfPossible
+/// to make CastInfo specializations more declarative. The `Derived` template
+/// parameter *must* be provided for forwarding castFailed and doCast.
+template <typename To, typename From, typename Derived>
+struct DefaultDoCastIfPossible {
+ static To doCastIfPossible(From f) {
+ if (!Derived::isPossible(f))
+ return Derived::castFailed();
+ return Derived::doCast(f);
+ }
+};
+
+namespace detail {
+/// A helper to derive the type to use with `Self` for cast traits, when the
+/// provided CRTP derived type is allowed to be void.
+template <typename OptionalDerived, typename Default>
+using SelfType = std::conditional_t<std::is_same<OptionalDerived, void>::value,
+ Default, OptionalDerived>;
+} // namespace detail
+
+/// This cast trait provides casting for the specific case of casting to a
+/// value-typed object from a pointer-typed object. Note that `To` must be
+/// nullable/constructible from a pointer to `From` to use this cast.
+template <typename To, typename From, typename Derived = void>
+struct ValueFromPointerCast
+ : public CastIsPossible<To, From *>,
+ public NullableValueCastFailed<To>,
+ public DefaultDoCastIfPossible<
+ To, From *,
+ detail::SelfType<Derived, ValueFromPointerCast<To, From>>> {
+ static inline To doCast(From *f) { return To(f); }
+};
+
+/// This cast trait provides std::unique_ptr casting. It has the semantics of
+/// moving the contents of the input unique_ptr into the output unique_ptr
+/// during the cast. It's also a good example of how to implement a move-only
+/// cast.
+template <typename To, typename From, typename Derived = void>
+struct UniquePtrCast : public CastIsPossible<To, From *> {
+ using Self = detail::SelfType<Derived, UniquePtrCast<To, From>>;
+ using CastResultType = std::unique_ptr<
+ std::remove_reference_t<typename cast_retty<To, From>::ret_type>>;
+
+ static inline CastResultType doCast(std::unique_ptr<From> &&f) {
+ return CastResultType((typename CastResultType::element_type *)f.release());
+ }
+
+ static inline CastResultType castFailed() { return CastResultType(nullptr); }
+
+ static inline CastResultType doCastIfPossible(std::unique_ptr<From> &&f) {
+ if (!Self::isPossible(f))
+ return castFailed();
+ return doCast(f);
+ }
+};
+
+/// This cast trait provides std::optional<T> casting. This means that if you
+/// have a value type, you can cast it to another value type and have dyn_cast
+/// return an std::optional<T>.
+template <typename To, typename From, typename Derived = void>
+struct OptionalValueCast
+ : public CastIsPossible<To, From>,
+ public DefaultDoCastIfPossible<
+ std::optional<To>, From,
+ detail::SelfType<Derived, OptionalValueCast<To, From>>> {
+ static inline std::optional<To> castFailed() { return std::optional<To>{}; }
+
+ static inline std::optional<To> doCast(const From &f) { return To(f); }
+};
+
+/// Provides a cast trait that strips `const` from types to make it easier to
+/// implement a const-version of a non-const cast. It just removes boilerplate
+/// and reduces the amount of code you as the user need to implement. You can
+/// use it like this:
+///
+/// template<> struct CastInfo<foo, bar> {
+/// ...verbose implementation...
+/// };
+///
+/// template<> struct CastInfo<foo, const bar> : public
+/// ConstStrippingForwardingCast<foo, const bar, CastInfo<foo, bar>> {};
+///
+template <typename To, typename From, typename ForwardTo>
+struct ConstStrippingForwardingCast {
+ // Remove the pointer if it exists, then we can get rid of consts/volatiles.
+ using DecayedFrom = std::remove_cv_t<std::remove_pointer_t<From>>;
+ // Now if it's a pointer, add it back. Otherwise, we want a ref.
+ using NonConstFrom = std::conditional_t<std::is_pointer<From>::value,
+ DecayedFrom *, DecayedFrom &>;
+
+ static inline bool isPossible(const From &f) {
+ return ForwardTo::isPossible(const_cast<NonConstFrom>(f));
+ }
+
+ static inline decltype(auto) castFailed() { return ForwardTo::castFailed(); }
+
+ static inline decltype(auto) doCast(const From &f) {
+ return ForwardTo::doCast(const_cast<NonConstFrom>(f));
+ }
+
+ static inline decltype(auto) doCastIfPossible(const From &f) {
+ return ForwardTo::doCastIfPossible(const_cast<NonConstFrom>(f));
+ }
+};
+
+/// Provides a cast trait that uses a defined pointer to pointer cast as a base
+/// for reference-to-reference casts. Note that it does not provide castFailed
+/// and doCastIfPossible because a pointer-to-pointer cast would likely just
+/// return `nullptr` which could cause nullptr dereference. You can use it like
+/// this:
+///
+/// template <> struct CastInfo<foo, bar *> { ... verbose implementation... };
+///
+/// template <>
+/// struct CastInfo<foo, bar>
+/// : public ForwardToPointerCast<foo, bar, CastInfo<foo, bar *>> {};
+///
+template <typename To, typename From, typename ForwardTo>
+struct ForwardToPointerCast {
+ static inline bool isPossible(const From &f) {
+ return ForwardTo::isPossible(&f);
+ }
+
+ static inline decltype(auto) doCast(const From &f) {
+ return *ForwardTo::doCast(&f);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// CastInfo
+//===----------------------------------------------------------------------===//
+
+/// This struct provides a method for customizing the way a cast is performed.
+/// It inherits from CastIsPossible, to support the case of declaring many
+/// CastIsPossible specializations without having to specialize the full
+/// CastInfo.
+///
+/// In order to specialize different behaviors, specify different functions in
+/// your CastInfo specialization.
+/// For isa<> customization, provide:
+///
+/// `static bool isPossible(const From &f)`
+///
+/// For cast<> customization, provide:
+///
+/// `static To doCast(const From &f)`
+///
+/// For dyn_cast<> and the *_if_present<> variants' customization, provide:
+///
+/// `static To castFailed()` and `static To doCastIfPossible(const From &f)`
+///
+/// Your specialization might look something like this:
+///
+/// template<> struct CastInfo<foo, bar> : public CastIsPossible<foo, bar> {
+/// static inline foo doCast(const bar &b) {
+/// return foo(const_cast<bar &>(b));
+/// }
+/// static inline foo castFailed() { return foo(); }
+/// static inline foo doCastIfPossible(const bar &b) {
+/// if (!CastInfo<foo, bar>::isPossible(b))
+/// return castFailed();
+/// return doCast(b);
+/// }
+/// };
+
+// The default implementations of CastInfo don't use cast traits for now because
+// we need to specify types all over the place due to the current expected
+// casting behavior and the way cast_retty works. New use cases can and should
+// take advantage of the cast traits whenever possible!
+
+template <typename To, typename From, typename Enable = void>
+struct CastInfo : public CastIsPossible<To, From> {
+ using Self = CastInfo<To, From, Enable>;
+
+ using CastReturnType = typename cast_retty<To, From>::ret_type;
+
+ static inline CastReturnType doCast(const From &f) {
+ return cast_convert_val<
+ To, From,
+ typename simplify_type<From>::SimpleType>::doit(const_cast<From &>(f));
+ }
+
+ // This assumes that you can construct the cast return type from `nullptr`.
+ // This is largely to support legacy use cases - if you don't want this
+ // behavior you should specialize CastInfo for your use case.
+ static inline CastReturnType castFailed() { return CastReturnType(nullptr); }
+
+ static inline CastReturnType doCastIfPossible(const From &f) {
+ if (!Self::isPossible(f))
+ return castFailed();
+ return doCast(f);
+ }
+};
+
+/// This struct provides an overload for CastInfo where From has simplify_type
+/// defined. This simply forwards to the appropriate CastInfo with the
+/// simplified type/value, so you don't have to implement both.
+template <typename To, typename From>
+struct CastInfo<To, From, std::enable_if_t<!is_simple_type<From>::value>> {
+ using Self = CastInfo<To, From>;
+ using SimpleFrom = typename simplify_type<From>::SimpleType;
+ using SimplifiedSelf = CastInfo<To, SimpleFrom>;
+
+ static inline bool isPossible(From &f) {
+ return SimplifiedSelf::isPossible(
+ simplify_type<From>::getSimplifiedValue(f));
+ }
+
+ static inline decltype(auto) doCast(From &f) {
+ return SimplifiedSelf::doCast(simplify_type<From>::getSimplifiedValue(f));
+ }
+
+ static inline decltype(auto) castFailed() {
+ return SimplifiedSelf::castFailed();
+ }
+
+ static inline decltype(auto) doCastIfPossible(From &f) {
+ return SimplifiedSelf::doCastIfPossible(
+ simplify_type<From>::getSimplifiedValue(f));
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Pre-specialized CastInfo
+//===----------------------------------------------------------------------===//
+
+/// Provide a CastInfo specialized for std::unique_ptr.
+template <typename To, typename From>
+struct CastInfo<To, std::unique_ptr<From>> : public UniquePtrCast<To, From> {};
+
+/// Provide a CastInfo specialized for std::optional<From>. It's assumed that if
+/// the input is std::optional<From> that the output can be std::optional<To>.
+/// If that's not the case, specialize CastInfo for your use case.
+template <typename To, typename From>
+struct CastInfo<To, std::optional<From>> : public OptionalValueCast<To, From> {
+};
+
+/// isa<X> - Return true if the parameter to the template is an instance of one
+/// of the template type arguments. Used like this:
+///
+/// if (isa<Type>(myVal)) { ... }
+/// if (isa<Type0, Type1, Type2>(myVal)) { ... }
+template <typename To, typename From>
+[[nodiscard]] inline bool isa(const From &Val) {
+ return CastInfo<To, const From>::isPossible(Val);
+}
+
+template <typename First, typename Second, typename... Rest, typename From>
+[[nodiscard]] inline bool isa(const From &Val) {
+ return isa<First>(Val) || isa<Second, Rest...>(Val);
+}
+
+/// cast<X> - Return the argument parameter cast to the specified type. This
+/// casting operator asserts that the type is correct, so it does not return
+/// null on failure. It does not allow a null argument (use cast_if_present for
+/// that). It is typically used like this:
+///
+/// cast<Instruction>(myVal)->getParent()
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) cast(const From &Val) {
+ assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
+ return CastInfo<To, const From>::doCast(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) cast(From &Val) {
+ assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
+ return CastInfo<To, From>::doCast(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) cast(From *Val) {
+ assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
+ return CastInfo<To, From *>::doCast(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) cast(std::unique_ptr<From> &&Val) {
+ assert(isa<To>(Val) && "cast<Ty>() argument of incompatible type!");
+ return CastInfo<To, std::unique_ptr<From>>::doCast(std::move(Val));
+}
+
+//===----------------------------------------------------------------------===//
+// ValueIsPresent
+//===----------------------------------------------------------------------===//
+
+template <typename T>
+constexpr bool IsNullable =
+ std::is_pointer_v<T> || std::is_constructible_v<T, std::nullptr_t>;
+
+/// ValueIsPresent provides a way to check if a value is, well, present. For
+/// pointers, this is the equivalent of checking against nullptr, for Optionals
+/// this is the equivalent of checking hasValue(). It also provides a method for
+/// unwrapping a value (think calling .value() on an optional).
+
+// Generic values can't *not* be present.
+template <typename T, typename Enable = void> struct ValueIsPresent {
+ using UnwrappedType = T;
+ static inline bool isPresent(const T &t) { return true; }
+ static inline decltype(auto) unwrapValue(T &t) { return t; }
+};
+
+// Optional provides its own way to check if something is present.
+template <typename T> struct ValueIsPresent<std::optional<T>> {
+ using UnwrappedType = T;
+ static inline bool isPresent(const std::optional<T> &t) {
+ return t.has_value();
+ }
+ static inline decltype(auto) unwrapValue(std::optional<T> &t) { return *t; }
+};
+
+// If something is "nullable" then we just compare it to nullptr to see if it
+// exists.
+template <typename T>
+struct ValueIsPresent<T, std::enable_if_t<IsNullable<T>>> {
+ using UnwrappedType = T;
+ static inline bool isPresent(const T &t) { return t != T(nullptr); }
+ static inline decltype(auto) unwrapValue(T &t) { return t; }
+};
+
+namespace detail {
+// Convenience function we can use to check if a value is present. Because of
+// simplify_type, we have to call it on the simplified type for now.
+template <typename T> inline bool isPresent(const T &t) {
+ return ValueIsPresent<typename simplify_type<T>::SimpleType>::isPresent(
+ simplify_type<T>::getSimplifiedValue(const_cast<T &>(t)));
+}
+
+// Convenience function we can use to unwrap a value.
+template <typename T> inline decltype(auto) unwrapValue(T &t) {
+ return ValueIsPresent<T>::unwrapValue(t);
+}
+} // namespace detail
+
+/// dyn_cast<X> - Return the argument parameter cast to the specified type. This
+/// casting operator returns null if the argument is of the wrong type, so it
+/// can be used to test for a type as well as cast if successful. The value
+/// passed in must be present, if not, use dyn_cast_if_present. This should be
+/// used in the context of an if statement like this:
+///
+/// if (const Instruction *I = dyn_cast<Instruction>(myVal)) { ... }
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) dyn_cast(const From &Val) {
+ assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
+ return CastInfo<To, const From>::doCastIfPossible(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) dyn_cast(From &Val) {
+ assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
+ return CastInfo<To, From>::doCastIfPossible(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) dyn_cast(From *Val) {
+ assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
+ return CastInfo<To, From *>::doCastIfPossible(Val);
+}
+
+template <typename To, typename From>
+[[nodiscard]] inline decltype(auto) dyn_cast(std::unique_ptr<From> &&Val) {
+ assert(detail::isPresent(Val) && "dyn_cast on a non-existent value");
+ return CastInfo<To, std::unique_ptr<From>>::doCastIfPossible(
+ std::forward<std::unique_ptr<From> &&>(Val));
+}
+
+/// isa_and_present<X> - Functionally identical to isa, except that a null value
+/// is accepted.
+template <typename... X, class Y>
+[[nodiscard]] inline bool isa_and_present(const Y &Val) {
+ if (!detail::isPresent(Val))
+ return false;
+ return isa<X...>(Val);
+}
+
+template <typename... X, class Y>
+[[nodiscard]] inline bool isa_and_nonnull(const Y &Val) {
+ return isa_and_present<X...>(Val);
+}
+
+/// cast_if_present<X> - Functionally identical to cast, except that a null
+/// value is accepted.
+template <class X, class Y>
+[[nodiscard]] inline auto cast_if_present(const Y &Val) {
+ if (!detail::isPresent(Val))
+ return CastInfo<X, const Y>::castFailed();
+ assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
+ return cast<X>(detail::unwrapValue(Val));
+}
+
+template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y &Val) {
+ if (!detail::isPresent(Val))
+ return CastInfo<X, Y>::castFailed();
+ assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
+ return cast<X>(detail::unwrapValue(Val));
+}
+
+template <class X, class Y> [[nodiscard]] inline auto cast_if_present(Y *Val) {
+ if (!detail::isPresent(Val))
+ return CastInfo<X, Y *>::castFailed();
+ assert(isa<X>(Val) && "cast_if_present<Ty>() argument of incompatible type!");
+ return cast<X>(detail::unwrapValue(Val));
+}
+
+template <class X, class Y>
+[[nodiscard]] inline auto cast_if_present(std::unique_ptr<Y> &&Val) {
+ if (!detail::isPresent(Val))
+ return UniquePtrCast<X, Y>::castFailed();
+ return UniquePtrCast<X, Y>::doCast(std::move(Val));
+}
+
+// Provide a forwarding from cast_or_null to cast_if_present for current
+// users. This is deprecated and will be removed in a future patch, use
+// cast_if_present instead.
+template <class X, class Y> auto cast_or_null(const Y &Val) {
+ return cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto cast_or_null(Y &Val) {
+ return cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto cast_or_null(Y *Val) {
+ return cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto cast_or_null(std::unique_ptr<Y> &&Val) {
+ return cast_if_present<X>(std::move(Val));
+}
+
+/// dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a
+/// null (or none in the case of optionals) value is accepted.
+template <class X, class Y> auto dyn_cast_if_present(const Y &Val) {
+ if (!detail::isPresent(Val))
+ return CastInfo<X, const Y>::castFailed();
+ return CastInfo<X, const Y>::doCastIfPossible(detail::unwrapValue(Val));
+}
+
+template <class X, class Y> auto dyn_cast_if_present(Y &Val) {
+ if (!detail::isPresent(Val))
+ return CastInfo<X, Y>::castFailed();
+ return CastInfo<X, Y>::doCastIfPossible(detail::unwrapValue(Val));
+}
+
+template <class X, class Y> auto dyn_cast_if_present(Y *Val) {
+ if (!detail::isPresent(Val))
+ return CastInfo<X, Y *>::castFailed();
+ return CastInfo<X, Y *>::doCastIfPossible(detail::unwrapValue(Val));
+}
+
+// Forwards to dyn_cast_if_present to avoid breaking current users. This is
+// deprecated and will be removed in a future patch, use
+// cast_if_present instead.
+template <class X, class Y> auto dyn_cast_or_null(const Y &Val) {
+ return dyn_cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto dyn_cast_or_null(Y &Val) {
+ return dyn_cast_if_present<X>(Val);
+}
+
+template <class X, class Y> auto dyn_cast_or_null(Y *Val) {
+ return dyn_cast_if_present<X>(Val);
+}
+
+/// unique_dyn_cast<X> - Given a unique_ptr<Y>, try to return a unique_ptr<X>,
+/// taking ownership of the input pointer iff isa<X>(Val) is true. If the
+/// cast is successful, From refers to nullptr on exit and the casted value
+/// is returned. If the cast is unsuccessful, the function returns nullptr
+/// and From is unchanged.
+template <class X, class Y>
+[[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType
+unique_dyn_cast(std::unique_ptr<Y> &Val) {
+ if (!isa<X>(Val))
+ return nullptr;
+ return cast<X>(std::move(Val));
+}
+
+template <class X, class Y>
+[[nodiscard]] inline auto unique_dyn_cast(std::unique_ptr<Y> &&Val) {
+ return unique_dyn_cast<X, Y>(Val);
+}
+
+// unique_dyn_cast_or_null<X> - Functionally identical to unique_dyn_cast,
+// except that a null value is accepted.
+template <class X, class Y>
+[[nodiscard]] inline typename CastInfo<X, std::unique_ptr<Y>>::CastResultType
+unique_dyn_cast_or_null(std::unique_ptr<Y> &Val) {
+ if (!Val)
+ return nullptr;
+ return unique_dyn_cast<X, Y>(Val);
+}
+
+template <class X, class Y>
+[[nodiscard]] inline auto unique_dyn_cast_or_null(std::unique_ptr<Y> &&Val) {
+ return unique_dyn_cast_or_null<X, Y>(Val);
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_CASTING_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CheckedArithmetic.h b/contrib/libs/llvm16/include/llvm/Support/CheckedArithmetic.h
new file mode 100644
index 00000000000..190b17c63ce
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CheckedArithmetic.h
@@ -0,0 +1,123 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//==-- llvm/Support/CheckedArithmetic.h - Safe arithmetical operations *- 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 generic functions for operating on integers which
+// give the indication on whether the operation has overflown.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CHECKEDARITHMETIC_H
+#define LLVM_SUPPORT_CHECKEDARITHMETIC_H
+
+#include "llvm/ADT/APInt.h"
+
+#include <optional>
+#include <type_traits>
+
+namespace {
+
+/// Utility function to apply a given method of \c APInt \p F to \p LHS and
+/// \p RHS.
+/// \return Empty optional if the operation overflows, or result otherwise.
+template <typename T, typename F>
+std::enable_if_t<std::is_integral<T>::value && sizeof(T) * 8 <= 64,
+ std::optional<T>>
+checkedOp(T LHS, T RHS, F Op, bool Signed = true) {
+ llvm::APInt ALHS(sizeof(T) * 8, LHS, Signed);
+ llvm::APInt ARHS(sizeof(T) * 8, RHS, Signed);
+ bool Overflow;
+ llvm::APInt Out = (ALHS.*Op)(ARHS, Overflow);
+ if (Overflow)
+ return std::nullopt;
+ return Signed ? Out.getSExtValue() : Out.getZExtValue();
+}
+}
+
+namespace llvm {
+
+/// Add two signed integers \p LHS and \p RHS.
+/// \return Optional of sum if no signed overflow occurred,
+/// \c std::nullopt otherwise.
+template <typename T>
+std::enable_if_t<std::is_signed<T>::value, std::optional<T>>
+checkedAdd(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::sadd_ov);
+}
+
+/// Subtract two signed integers \p LHS and \p RHS.
+/// \return Optional of sum if no signed overflow occurred,
+/// \c std::nullopt otherwise.
+template <typename T>
+std::enable_if_t<std::is_signed<T>::value, std::optional<T>>
+checkedSub(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::ssub_ov);
+}
+
+/// Multiply two signed integers \p LHS and \p RHS.
+/// \return Optional of product if no signed overflow occurred,
+/// \c std::nullopt otherwise.
+template <typename T>
+std::enable_if_t<std::is_signed<T>::value, std::optional<T>>
+checkedMul(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::smul_ov);
+}
+
+/// Multiply A and B, and add C to the resulting product.
+/// \return Optional of result if no signed overflow occurred,
+/// \c std::nullopt otherwise.
+template <typename T>
+std::enable_if_t<std::is_signed<T>::value, std::optional<T>>
+checkedMulAdd(T A, T B, T C) {
+ if (auto Product = checkedMul(A, B))
+ return checkedAdd(*Product, C);
+ return std::nullopt;
+}
+
+/// Add two unsigned integers \p LHS and \p RHS.
+/// \return Optional of sum if no unsigned overflow occurred,
+/// \c std::nullopt otherwise.
+template <typename T>
+std::enable_if_t<std::is_unsigned<T>::value, std::optional<T>>
+checkedAddUnsigned(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::uadd_ov, /*Signed=*/false);
+}
+
+/// Multiply two unsigned integers \p LHS and \p RHS.
+/// \return Optional of product if no unsigned overflow occurred,
+/// \c std::nullopt otherwise.
+template <typename T>
+std::enable_if_t<std::is_unsigned<T>::value, std::optional<T>>
+checkedMulUnsigned(T LHS, T RHS) {
+ return checkedOp(LHS, RHS, &llvm::APInt::umul_ov, /*Signed=*/false);
+}
+
+/// Multiply unsigned integers A and B, and add C to the resulting product.
+/// \return Optional of result if no unsigned overflow occurred,
+/// \c std::nullopt otherwise.
+template <typename T>
+std::enable_if_t<std::is_unsigned<T>::value, std::optional<T>>
+checkedMulAddUnsigned(T A, T B, T C) {
+ if (auto Product = checkedMulUnsigned(A, B))
+ return checkedAddUnsigned(*Product, C);
+ return std::nullopt;
+}
+
+} // End llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Chrono.h b/contrib/libs/llvm16/include/llvm/Support/Chrono.h
new file mode 100644
index 00000000000..3ec37ad884b
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Chrono.h
@@ -0,0 +1,183 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CHRONO_H
+#define LLVM_SUPPORT_CHRONO_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/FormatProviders.h"
+
+#include <chrono>
+#include <ctime>
+#include <ratio>
+
+namespace llvm {
+
+class raw_ostream;
+
+namespace sys {
+
+/// A time point on the system clock. This is provided for two reasons:
+/// - to insulate us against subtle differences in behavior to differences in
+/// system clock precision (which is implementation-defined and differs
+/// between platforms).
+/// - to shorten the type name
+/// The default precision is nanoseconds. If you need a specific precision
+/// specify it explicitly. If unsure, use the default. If you need a time point
+/// on a clock other than the system_clock, use std::chrono directly.
+template <typename D = std::chrono::nanoseconds>
+using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
+
+/// Convert a TimePoint to std::time_t
+inline std::time_t toTimeT(TimePoint<> TP) {
+ using namespace std::chrono;
+ return system_clock::to_time_t(
+ time_point_cast<system_clock::time_point::duration>(TP));
+}
+
+/// Convert a std::time_t to a TimePoint
+inline TimePoint<std::chrono::seconds>
+toTimePoint(std::time_t T) {
+ using namespace std::chrono;
+ return time_point_cast<seconds>(system_clock::from_time_t(T));
+}
+
+/// Convert a std::time_t + nanoseconds to a TimePoint
+inline TimePoint<>
+toTimePoint(std::time_t T, uint32_t nsec) {
+ using namespace std::chrono;
+ return time_point_cast<nanoseconds>(system_clock::from_time_t(T))
+ + nanoseconds(nsec);
+}
+
+} // namespace sys
+
+raw_ostream &operator<<(raw_ostream &OS, sys::TimePoint<> TP);
+
+/// Format provider for TimePoint<>
+///
+/// The options string is a strftime format string, with extensions:
+/// - %L is millis: 000-999
+/// - %f is micros: 000000-999999
+/// - %N is nanos: 000000000 - 999999999
+///
+/// If no options are given, the default format is "%Y-%m-%d %H:%M:%S.%N".
+template <>
+struct format_provider<sys::TimePoint<>> {
+ static void format(const sys::TimePoint<> &TP, llvm::raw_ostream &OS,
+ StringRef Style);
+};
+
+namespace detail {
+template <typename Period> struct unit { static const char value[]; };
+template <typename Period> const char unit<Period>::value[] = "";
+
+template <> struct unit<std::ratio<3600>> { static const char value[]; };
+template <> struct unit<std::ratio<60>> { static const char value[]; };
+template <> struct unit<std::ratio<1>> { static const char value[]; };
+template <> struct unit<std::milli> { static const char value[]; };
+template <> struct unit<std::micro> { static const char value[]; };
+template <> struct unit<std::nano> { static const char value[]; };
+} // namespace detail
+
+/// Implementation of format_provider<T> for duration types.
+///
+/// The options string of a duration type has the grammar:
+///
+/// duration_options ::= [unit][show_unit [number_options]]
+/// unit ::= `h`|`m`|`s`|`ms|`us`|`ns`
+/// show_unit ::= `+` | `-`
+/// number_options ::= options string for a integral or floating point type
+///
+/// Examples
+/// =================================
+/// | options | Input | Output |
+/// =================================
+/// | "" | 1s | 1 s |
+/// | "ms" | 1s | 1000 ms |
+/// | "ms-" | 1s | 1000 |
+/// | "ms-n" | 1s | 1,000 |
+/// | "" | 1.0s | 1.00 s |
+/// =================================
+///
+/// If the unit of the duration type is not one of the units specified above,
+/// it is still possible to format it, provided you explicitly request a
+/// display unit or you request that the unit is not displayed.
+
+template <typename Rep, typename Period>
+struct format_provider<std::chrono::duration<Rep, Period>> {
+private:
+ typedef std::chrono::duration<Rep, Period> Dur;
+ typedef std::conditional_t<std::chrono::treat_as_floating_point<Rep>::value,
+ double, intmax_t>
+ InternalRep;
+
+ template <typename AsPeriod> static InternalRep getAs(const Dur &D) {
+ using namespace std::chrono;
+ return duration_cast<duration<InternalRep, AsPeriod>>(D).count();
+ }
+
+ static std::pair<InternalRep, StringRef> consumeUnit(StringRef &Style,
+ const Dur &D) {
+ using namespace std::chrono;
+ if (Style.consume_front("ns"))
+ return {getAs<std::nano>(D), "ns"};
+ if (Style.consume_front("us"))
+ return {getAs<std::micro>(D), "us"};
+ if (Style.consume_front("ms"))
+ return {getAs<std::milli>(D), "ms"};
+ if (Style.consume_front("s"))
+ return {getAs<std::ratio<1>>(D), "s"};
+ if (Style.consume_front("m"))
+ return {getAs<std::ratio<60>>(D), "m"};
+ if (Style.consume_front("h"))
+ return {getAs<std::ratio<3600>>(D), "h"};
+ return {D.count(), detail::unit<Period>::value};
+ }
+
+ static bool consumeShowUnit(StringRef &Style) {
+ if (Style.empty())
+ return true;
+ if (Style.consume_front("-"))
+ return false;
+ if (Style.consume_front("+"))
+ return true;
+ assert(0 && "Unrecognised duration format");
+ return true;
+ }
+
+public:
+ static void format(const Dur &D, llvm::raw_ostream &Stream, StringRef Style) {
+ InternalRep count;
+ StringRef unit;
+ std::tie(count, unit) = consumeUnit(Style, D);
+ bool show_unit = consumeShowUnit(Style);
+
+ format_provider<InternalRep>::format(count, Stream, Style);
+
+ if (show_unit) {
+ assert(!unit.empty());
+ Stream << " " << unit;
+ }
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_CHRONO_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CodeGen.h b/contrib/libs/llvm16/include/llvm/Support/CodeGen.h
new file mode 100644
index 00000000000..7f8b0200df3
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CodeGen.h
@@ -0,0 +1,147 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/CodeGen.h - CodeGen Concepts ---------------*- 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 define some types which define code generation concepts. For
+// example, relocation model.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CODEGEN_H
+#define LLVM_SUPPORT_CODEGEN_H
+
+#include <cstdint>
+#include <optional>
+
+namespace llvm {
+
+ // Relocation model types.
+ namespace Reloc {
+ // Cannot be named PIC due to collision with -DPIC
+ enum Model { Static, PIC_, DynamicNoPIC, ROPI, RWPI, ROPI_RWPI };
+ }
+
+ // Code model types.
+ namespace CodeModel {
+ // Sync changes with CodeGenCWrappers.h.
+ enum Model { Tiny, Small, Kernel, Medium, Large };
+ }
+
+ namespace PICLevel {
+ // This is used to map -fpic/-fPIC.
+ enum Level { NotPIC=0, SmallPIC=1, BigPIC=2 };
+ }
+
+ namespace PIELevel {
+ enum Level { Default=0, Small=1, Large=2 };
+ }
+
+ // TLS models.
+ namespace TLSModel {
+ enum Model {
+ GeneralDynamic,
+ LocalDynamic,
+ InitialExec,
+ LocalExec
+ };
+ }
+
+ namespace CodeGenOpt {
+ /// Type for the unique integer IDs of code generation optimization levels.
+ using IDType = int;
+ /// Code generation optimization level.
+ enum Level : IDType {
+ None = 0, ///< -O0
+ Less = 1, ///< -O1
+ Default = 2, ///< -O2, -Os
+ Aggressive = 3 ///< -O3
+ };
+ /// Get the \c Level identified by the integer \p ID.
+ ///
+ /// Returns std::nullopt if \p ID is invalid.
+ inline std::optional<Level> getLevel(IDType ID) {
+ if (ID < 0 || ID > 3)
+ return std::nullopt;
+ return static_cast<Level>(ID);
+ }
+ /// Parse \p C as a single digit integer ID and get matching \c Level.
+ ///
+ /// Returns std::nullopt if the input is not a valid digit or not a valid ID.
+ inline std::optional<Level> parseLevel(char C) {
+ if (C < '0')
+ return std::nullopt;
+ return getLevel(static_cast<IDType>(C - '0'));
+ }
+ } // namespace CodeGenOpt
+
+ /// These enums are meant to be passed into addPassesToEmitFile to indicate
+ /// what type of file to emit, and returned by it to indicate what type of
+ /// file could actually be made.
+ enum CodeGenFileType {
+ CGFT_AssemblyFile,
+ CGFT_ObjectFile,
+ CGFT_Null // Do not emit any output.
+ };
+
+ // Specify what functions should keep the frame pointer.
+ enum class FramePointerKind { None, NonLeaf, All };
+
+ // Specify what type of zeroing callee-used registers.
+ namespace ZeroCallUsedRegs {
+ const unsigned ONLY_USED = 1U << 1;
+ const unsigned ONLY_GPR = 1U << 2;
+ const unsigned ONLY_ARG = 1U << 3;
+
+ enum class ZeroCallUsedRegsKind : unsigned int {
+ // Don't zero any call-used regs.
+ Skip = 1U << 0,
+ // Only zeros call-used GPRs used in the fn and pass args.
+ UsedGPRArg = ONLY_USED | ONLY_GPR | ONLY_ARG,
+ // Only zeros call-used GPRs used in the fn.
+ UsedGPR = ONLY_USED | ONLY_GPR,
+ // Only zeros call-used regs used in the fn and pass args.
+ UsedArg = ONLY_USED | ONLY_ARG,
+ // Only zeros call-used regs used in the fn.
+ Used = ONLY_USED,
+ // Zeros all call-used GPRs that pass args.
+ AllGPRArg = ONLY_GPR | ONLY_ARG,
+ // Zeros all call-used GPRs.
+ AllGPR = ONLY_GPR,
+ // Zeros all call-used regs that pass args.
+ AllArg = ONLY_ARG,
+ // Zeros all call-used regs.
+ All = 0,
+ };
+ } // namespace ZeroCallUsedRegs
+
+ enum class UWTableKind {
+ None = 0, ///< No unwind table requested
+ Sync = 1, ///< "Synchronous" unwind tables
+ Async = 2, ///< "Asynchronous" unwind tables (instr precise)
+ Default = 2,
+ };
+
+ enum class FunctionReturnThunksKind : unsigned int {
+ Keep = 0, ///< No function return thunk.
+ Extern = 1, ///< Replace returns with jump to thunk, don't emit thunk.
+ Invalid = 2, ///< Not used.
+ };
+
+ } // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CodeGenCoverage.h b/contrib/libs/llvm16/include/llvm/Support/CodeGenCoverage.h
new file mode 100644
index 00000000000..51173d3edb9
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CodeGenCoverage.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//== llvm/Support/CodeGenCoverage.h ------------------------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file This file provides rule coverage tracking for tablegen-erated CodeGen.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CODEGENCOVERAGE_H
+#define LLVM_SUPPORT_CODEGENCOVERAGE_H
+
+#include "llvm/ADT/BitVector.h"
+
+namespace llvm {
+class MemoryBuffer;
+
+class CodeGenCoverage {
+protected:
+ BitVector RuleCoverage;
+
+public:
+ using const_covered_iterator = BitVector::const_set_bits_iterator;
+
+ CodeGenCoverage();
+
+ void setCovered(uint64_t RuleID);
+ bool isCovered(uint64_t RuleID) const;
+ iterator_range<const_covered_iterator> covered() const;
+
+ bool parse(MemoryBuffer &Buffer, StringRef BackendName);
+ bool emit(StringRef FilePrefix, StringRef BackendName) const;
+ void reset();
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_CODEGENCOVERAGE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CommandLine.h b/contrib/libs/llvm16/include/llvm/Support/CommandLine.h
new file mode 100644
index 00000000000..03ff0a5235e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CommandLine.h
@@ -0,0 +1,2282 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/CommandLine.h - Command line handler --------*- 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 class implements a command line argument processor that is useful when
+// creating a tool. It provides a simple, minimalistic interface that is easily
+// extensible and supports nonlocal (library) command line options.
+//
+// Note that rather than trying to figure out what this code does, you should
+// read the library documentation located in docs/CommandLine.html or looks at
+// the many example usages in tools/*/*.cpp
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_COMMANDLINE_H
+#define LLVM_SUPPORT_COMMANDLINE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <climits>
+#include <cstddef>
+#include <functional>
+#include <initializer_list>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+
+namespace vfs {
+class FileSystem;
+}
+
+class StringSaver;
+
+/// This namespace contains all of the command line option processing machinery.
+/// It is intentionally a short name to make qualified usage concise.
+namespace cl {
+
+//===----------------------------------------------------------------------===//
+// Command line option processing entry point.
+//
+// Returns true on success. Otherwise, this will print the error message to
+// stderr and exit if \p Errs is not set (nullptr by default), or print the
+// error message to \p Errs and return false if \p Errs is provided.
+//
+// If EnvVar is not nullptr, command-line options are also parsed from the
+// environment variable named by EnvVar. Precedence is given to occurrences
+// from argv. This precedence is currently implemented by parsing argv after
+// the environment variable, so it is only implemented correctly for options
+// that give precedence to later occurrences. If your program supports options
+// that give precedence to earlier occurrences, you will need to extend this
+// function to support it correctly.
+bool ParseCommandLineOptions(int argc, const char *const *argv,
+ StringRef Overview = "",
+ raw_ostream *Errs = nullptr,
+ const char *EnvVar = nullptr,
+ bool LongOptionsUseDoubleDash = false);
+
+// Function pointer type for printing version information.
+using VersionPrinterTy = std::function<void(raw_ostream &)>;
+
+///===---------------------------------------------------------------------===//
+/// Override the default (LLVM specific) version printer used to print out the
+/// version when --version is given on the command line. This allows other
+/// systems using the CommandLine utilities to print their own version string.
+void SetVersionPrinter(VersionPrinterTy func);
+
+///===---------------------------------------------------------------------===//
+/// Add an extra printer to use in addition to the default one. This can be
+/// called multiple times, and each time it adds a new function to the list
+/// which will be called after the basic LLVM version printing is complete.
+/// Each can then add additional information specific to the tool.
+void AddExtraVersionPrinter(VersionPrinterTy func);
+
+// Print option values.
+// With -print-options print the difference between option values and defaults.
+// With -print-all-options print all option values.
+// (Currently not perfect, but best-effort.)
+void PrintOptionValues();
+
+// Forward declaration - AddLiteralOption needs to be up here to make gcc happy.
+class Option;
+
+/// Adds a new option for parsing and provides the option it refers to.
+///
+/// \param O pointer to the option
+/// \param Name the string name for the option to handle during parsing
+///
+/// Literal options are used by some parsers to register special option values.
+/// This is how the PassNameParser registers pass names for opt.
+void AddLiteralOption(Option &O, StringRef Name);
+
+//===----------------------------------------------------------------------===//
+// Flags permitted to be passed to command line arguments
+//
+
+enum NumOccurrencesFlag { // Flags for the number of occurrences allowed
+ Optional = 0x00, // Zero or One occurrence
+ ZeroOrMore = 0x01, // Zero or more occurrences allowed
+ Required = 0x02, // One occurrence required
+ OneOrMore = 0x03, // One or more occurrences required
+
+ // Indicates that this option is fed anything that follows the last positional
+ // argument required by the application (it is an error if there are zero
+ // positional arguments, and a ConsumeAfter option is used).
+ // Thus, for example, all arguments to LLI are processed until a filename is
+ // found. Once a filename is found, all of the succeeding arguments are
+ // passed, unprocessed, to the ConsumeAfter option.
+ //
+ ConsumeAfter = 0x04
+};
+
+enum ValueExpected { // Is a value required for the option?
+ // zero reserved for the unspecified value
+ ValueOptional = 0x01, // The value can appear... or not
+ ValueRequired = 0x02, // The value is required to appear!
+ ValueDisallowed = 0x03 // A value may not be specified (for flags)
+};
+
+enum OptionHidden { // Control whether -help shows this option
+ NotHidden = 0x00, // Option included in -help & -help-hidden
+ Hidden = 0x01, // -help doesn't, but -help-hidden does
+ ReallyHidden = 0x02 // Neither -help nor -help-hidden show this arg
+};
+
+// This controls special features that the option might have that cause it to be
+// parsed differently...
+//
+// Prefix - This option allows arguments that are otherwise unrecognized to be
+// matched by options that are a prefix of the actual value. This is useful for
+// cases like a linker, where options are typically of the form '-lfoo' or
+// '-L../../include' where -l or -L are the actual flags. When prefix is
+// enabled, and used, the value for the flag comes from the suffix of the
+// argument.
+//
+// AlwaysPrefix - Only allow the behavior enabled by the Prefix flag and reject
+// the Option=Value form.
+//
+
+enum FormattingFlags {
+ NormalFormatting = 0x00, // Nothing special
+ Positional = 0x01, // Is a positional argument, no '-' required
+ Prefix = 0x02, // Can this option directly prefix its value?
+ AlwaysPrefix = 0x03 // Can this option only directly prefix its value?
+};
+
+enum MiscFlags { // Miscellaneous flags to adjust argument
+ CommaSeparated = 0x01, // Should this cl::list split between commas?
+ PositionalEatsArgs = 0x02, // Should this positional cl::list eat -args?
+ Sink = 0x04, // Should this cl::list eat all unknown options?
+
+ // Can this option group with other options?
+ // If this is enabled, multiple letter options are allowed to bunch together
+ // with only a single hyphen for the whole group. This allows emulation
+ // of the behavior that ls uses for example: ls -la === ls -l -a
+ Grouping = 0x08,
+
+ // Default option
+ DefaultOption = 0x10
+};
+
+//===----------------------------------------------------------------------===//
+//
+class OptionCategory {
+private:
+ StringRef const Name;
+ StringRef const Description;
+
+ void registerCategory();
+
+public:
+ OptionCategory(StringRef const Name,
+ StringRef const Description = "")
+ : Name(Name), Description(Description) {
+ registerCategory();
+ }
+
+ StringRef getName() const { return Name; }
+ StringRef getDescription() const { return Description; }
+};
+
+// The general Option Category (used as default category).
+OptionCategory &getGeneralCategory();
+
+//===----------------------------------------------------------------------===//
+//
+class SubCommand {
+private:
+ StringRef Name;
+ StringRef Description;
+
+protected:
+ void registerSubCommand();
+ void unregisterSubCommand();
+
+public:
+ SubCommand(StringRef Name, StringRef Description = "")
+ : Name(Name), Description(Description) {
+ registerSubCommand();
+ }
+ SubCommand() = default;
+
+ // Get the special subcommand representing no subcommand.
+ static SubCommand &getTopLevel();
+
+ // Get the special subcommand that can be used to put an option into all
+ // subcomands.
+ static SubCommand &getAll();
+
+ void reset();
+
+ explicit operator bool() const;
+
+ StringRef getName() const { return Name; }
+ StringRef getDescription() const { return Description; }
+
+ SmallVector<Option *, 4> PositionalOpts;
+ SmallVector<Option *, 4> SinkOpts;
+ StringMap<Option *> OptionsMap;
+
+ Option *ConsumeAfterOpt = nullptr; // The ConsumeAfter option if it exists.
+};
+
+// A special subcommand representing no subcommand
+extern ManagedStatic<SubCommand> TopLevelSubCommand;
+
+// A special subcommand that can be used to put an option into all subcommands.
+extern ManagedStatic<SubCommand> AllSubCommands;
+
+//===----------------------------------------------------------------------===//
+//
+class Option {
+ friend class alias;
+
+ // Overriden by subclasses to handle the value passed into an argument. Should
+ // return true if there was an error processing the argument and the program
+ // should exit.
+ //
+ virtual bool handleOccurrence(unsigned pos, StringRef ArgName,
+ StringRef Arg) = 0;
+
+ virtual enum ValueExpected getValueExpectedFlagDefault() const {
+ return ValueOptional;
+ }
+
+ // Out of line virtual function to provide home for the class.
+ virtual void anchor();
+
+ uint16_t NumOccurrences; // The number of times specified
+ // Occurrences, HiddenFlag, and Formatting are all enum types but to avoid
+ // problems with signed enums in bitfields.
+ uint16_t Occurrences : 3; // enum NumOccurrencesFlag
+ // not using the enum type for 'Value' because zero is an implementation
+ // detail representing the non-value
+ uint16_t Value : 2;
+ uint16_t HiddenFlag : 2; // enum OptionHidden
+ uint16_t Formatting : 2; // enum FormattingFlags
+ uint16_t Misc : 5;
+ uint16_t FullyInitialized : 1; // Has addArgument been called?
+ uint16_t Position; // Position of last occurrence of the option
+ uint16_t AdditionalVals; // Greater than 0 for multi-valued option.
+
+public:
+ StringRef ArgStr; // The argument string itself (ex: "help", "o")
+ StringRef HelpStr; // The descriptive text message for -help
+ StringRef ValueStr; // String describing what the value of this option is
+ SmallVector<OptionCategory *, 1>
+ Categories; // The Categories this option belongs to
+ SmallPtrSet<SubCommand *, 1> Subs; // The subcommands this option belongs to.
+
+ inline enum NumOccurrencesFlag getNumOccurrencesFlag() const {
+ return (enum NumOccurrencesFlag)Occurrences;
+ }
+
+ inline enum ValueExpected getValueExpectedFlag() const {
+ return Value ? ((enum ValueExpected)Value) : getValueExpectedFlagDefault();
+ }
+
+ inline enum OptionHidden getOptionHiddenFlag() const {
+ return (enum OptionHidden)HiddenFlag;
+ }
+
+ inline enum FormattingFlags getFormattingFlag() const {
+ return (enum FormattingFlags)Formatting;
+ }
+
+ inline unsigned getMiscFlags() const { return Misc; }
+ inline unsigned getPosition() const { return Position; }
+ inline unsigned getNumAdditionalVals() const { return AdditionalVals; }
+
+ // Return true if the argstr != ""
+ bool hasArgStr() const { return !ArgStr.empty(); }
+ bool isPositional() const { return getFormattingFlag() == cl::Positional; }
+ bool isSink() const { return getMiscFlags() & cl::Sink; }
+ bool isDefaultOption() const { return getMiscFlags() & cl::DefaultOption; }
+
+ bool isConsumeAfter() const {
+ return getNumOccurrencesFlag() == cl::ConsumeAfter;
+ }
+
+ bool isInAllSubCommands() const {
+ return llvm::is_contained(Subs, &SubCommand::getAll());
+ }
+
+ //-------------------------------------------------------------------------===
+ // Accessor functions set by OptionModifiers
+ //
+ void setArgStr(StringRef S);
+ void setDescription(StringRef S) { HelpStr = S; }
+ void setValueStr(StringRef S) { ValueStr = S; }
+ void setNumOccurrencesFlag(enum NumOccurrencesFlag Val) { Occurrences = Val; }
+ void setValueExpectedFlag(enum ValueExpected Val) { Value = Val; }
+ void setHiddenFlag(enum OptionHidden Val) { HiddenFlag = Val; }
+ void setFormattingFlag(enum FormattingFlags V) { Formatting = V; }
+ void setMiscFlag(enum MiscFlags M) { Misc |= M; }
+ void setPosition(unsigned pos) { Position = pos; }
+ void addCategory(OptionCategory &C);
+ void addSubCommand(SubCommand &S) { Subs.insert(&S); }
+
+protected:
+ explicit Option(enum NumOccurrencesFlag OccurrencesFlag,
+ enum OptionHidden Hidden)
+ : NumOccurrences(0), Occurrences(OccurrencesFlag), Value(0),
+ HiddenFlag(Hidden), Formatting(NormalFormatting), Misc(0),
+ FullyInitialized(false), Position(0), AdditionalVals(0) {
+ Categories.push_back(&getGeneralCategory());
+ }
+
+ inline void setNumAdditionalVals(unsigned n) { AdditionalVals = n; }
+
+public:
+ virtual ~Option() = default;
+
+ // Register this argument with the commandline system.
+ //
+ void addArgument();
+
+ /// Unregisters this option from the CommandLine system.
+ ///
+ /// This option must have been the last option registered.
+ /// For testing purposes only.
+ void removeArgument();
+
+ // Return the width of the option tag for printing...
+ virtual size_t getOptionWidth() const = 0;
+
+ // Print out information about this option. The to-be-maintained width is
+ // specified.
+ //
+ virtual void printOptionInfo(size_t GlobalWidth) const = 0;
+
+ virtual void printOptionValue(size_t GlobalWidth, bool Force) const = 0;
+
+ virtual void setDefault() = 0;
+
+ // Prints the help string for an option.
+ //
+ // This maintains the Indent for multi-line descriptions.
+ // FirstLineIndentedBy is the count of chars of the first line
+ // i.e. the one containing the --<option name>.
+ static void printHelpStr(StringRef HelpStr, size_t Indent,
+ size_t FirstLineIndentedBy);
+
+ // Prints the help string for an enum value.
+ //
+ // This maintains the Indent for multi-line descriptions.
+ // FirstLineIndentedBy is the count of chars of the first line
+ // i.e. the one containing the =<value>.
+ static void printEnumValHelpStr(StringRef HelpStr, size_t Indent,
+ size_t FirstLineIndentedBy);
+
+ virtual void getExtraOptionNames(SmallVectorImpl<StringRef> &) {}
+
+ // Wrapper around handleOccurrence that enforces Flags.
+ //
+ virtual bool addOccurrence(unsigned pos, StringRef ArgName, StringRef Value,
+ bool MultiArg = false);
+
+ // Prints option name followed by message. Always returns true.
+ bool error(const Twine &Message, StringRef ArgName = StringRef(), raw_ostream &Errs = llvm::errs());
+ bool error(const Twine &Message, raw_ostream &Errs) {
+ return error(Message, StringRef(), Errs);
+ }
+
+ inline int getNumOccurrences() const { return NumOccurrences; }
+ void reset();
+};
+
+//===----------------------------------------------------------------------===//
+// Command line option modifiers that can be used to modify the behavior of
+// command line option parsers...
+//
+
+// Modifier to set the description shown in the -help output...
+struct desc {
+ StringRef Desc;
+
+ desc(StringRef Str) : Desc(Str) {}
+
+ void apply(Option &O) const { O.setDescription(Desc); }
+};
+
+// Modifier to set the value description shown in the -help output...
+struct value_desc {
+ StringRef Desc;
+
+ value_desc(StringRef Str) : Desc(Str) {}
+
+ void apply(Option &O) const { O.setValueStr(Desc); }
+};
+
+// Specify a default (initial) value for the command line argument, if the
+// default constructor for the argument type does not give you what you want.
+// This is only valid on "opt" arguments, not on "list" arguments.
+template <class Ty> struct initializer {
+ const Ty &Init;
+ initializer(const Ty &Val) : Init(Val) {}
+
+ template <class Opt> void apply(Opt &O) const { O.setInitialValue(Init); }
+};
+
+template <class Ty> struct list_initializer {
+ ArrayRef<Ty> Inits;
+ list_initializer(ArrayRef<Ty> Vals) : Inits(Vals) {}
+
+ template <class Opt> void apply(Opt &O) const { O.setInitialValues(Inits); }
+};
+
+template <class Ty> initializer<Ty> init(const Ty &Val) {
+ return initializer<Ty>(Val);
+}
+
+template <class Ty>
+list_initializer<Ty> list_init(ArrayRef<Ty> Vals) {
+ return list_initializer<Ty>(Vals);
+}
+
+// Allow the user to specify which external variable they want to store the
+// results of the command line argument processing into, if they don't want to
+// store it in the option itself.
+template <class Ty> struct LocationClass {
+ Ty &Loc;
+
+ LocationClass(Ty &L) : Loc(L) {}
+
+ template <class Opt> void apply(Opt &O) const { O.setLocation(O, Loc); }
+};
+
+template <class Ty> LocationClass<Ty> location(Ty &L) {
+ return LocationClass<Ty>(L);
+}
+
+// Specify the Option category for the command line argument to belong to.
+struct cat {
+ OptionCategory &Category;
+
+ cat(OptionCategory &c) : Category(c) {}
+
+ template <class Opt> void apply(Opt &O) const { O.addCategory(Category); }
+};
+
+// Specify the subcommand that this option belongs to.
+struct sub {
+ SubCommand &Sub;
+
+ sub(SubCommand &S) : Sub(S) {}
+
+ template <class Opt> void apply(Opt &O) const { O.addSubCommand(Sub); }
+};
+
+// Specify a callback function to be called when an option is seen.
+// Can be used to set other options automatically.
+template <typename R, typename Ty> struct cb {
+ std::function<R(Ty)> CB;
+
+ cb(std::function<R(Ty)> CB) : CB(CB) {}
+
+ template <typename Opt> void apply(Opt &O) const { O.setCallback(CB); }
+};
+
+namespace detail {
+template <typename F>
+struct callback_traits : public callback_traits<decltype(&F::operator())> {};
+
+template <typename R, typename C, typename... Args>
+struct callback_traits<R (C::*)(Args...) const> {
+ using result_type = R;
+ using arg_type = std::tuple_element_t<0, std::tuple<Args...>>;
+ static_assert(sizeof...(Args) == 1, "callback function must have one and only one parameter");
+ static_assert(std::is_same<result_type, void>::value,
+ "callback return type must be void");
+ static_assert(std::is_lvalue_reference<arg_type>::value &&
+ std::is_const<std::remove_reference_t<arg_type>>::value,
+ "callback arg_type must be a const lvalue reference");
+};
+} // namespace detail
+
+template <typename F>
+cb<typename detail::callback_traits<F>::result_type,
+ typename detail::callback_traits<F>::arg_type>
+callback(F CB) {
+ using result_type = typename detail::callback_traits<F>::result_type;
+ using arg_type = typename detail::callback_traits<F>::arg_type;
+ return cb<result_type, arg_type>(CB);
+}
+
+//===----------------------------------------------------------------------===//
+
+// Support value comparison outside the template.
+struct GenericOptionValue {
+ virtual bool compare(const GenericOptionValue &V) const = 0;
+
+protected:
+ GenericOptionValue() = default;
+ GenericOptionValue(const GenericOptionValue&) = default;
+ GenericOptionValue &operator=(const GenericOptionValue &) = default;
+ ~GenericOptionValue() = default;
+
+private:
+ virtual void anchor();
+};
+
+template <class DataType> struct OptionValue;
+
+// The default value safely does nothing. Option value printing is only
+// best-effort.
+template <class DataType, bool isClass>
+struct OptionValueBase : public GenericOptionValue {
+ // Temporary storage for argument passing.
+ using WrapperType = OptionValue<DataType>;
+
+ bool hasValue() const { return false; }
+
+ const DataType &getValue() const { llvm_unreachable("no default value"); }
+
+ // Some options may take their value from a different data type.
+ template <class DT> void setValue(const DT & /*V*/) {}
+
+ bool compare(const DataType & /*V*/) const { return false; }
+
+ bool compare(const GenericOptionValue & /*V*/) const override {
+ return false;
+ }
+
+protected:
+ ~OptionValueBase() = default;
+};
+
+// Simple copy of the option value.
+template <class DataType> class OptionValueCopy : public GenericOptionValue {
+ DataType Value;
+ bool Valid = false;
+
+protected:
+ OptionValueCopy(const OptionValueCopy&) = default;
+ OptionValueCopy &operator=(const OptionValueCopy &) = default;
+ ~OptionValueCopy() = default;
+
+public:
+ OptionValueCopy() = default;
+
+ bool hasValue() const { return Valid; }
+
+ const DataType &getValue() const {
+ assert(Valid && "invalid option value");
+ return Value;
+ }
+
+ void setValue(const DataType &V) {
+ Valid = true;
+ Value = V;
+ }
+
+ bool compare(const DataType &V) const { return Valid && (Value != V); }
+
+ bool compare(const GenericOptionValue &V) const override {
+ const OptionValueCopy<DataType> &VC =
+ static_cast<const OptionValueCopy<DataType> &>(V);
+ if (!VC.hasValue())
+ return false;
+ return compare(VC.getValue());
+ }
+};
+
+// Non-class option values.
+template <class DataType>
+struct OptionValueBase<DataType, false> : OptionValueCopy<DataType> {
+ using WrapperType = DataType;
+
+protected:
+ OptionValueBase() = default;
+ OptionValueBase(const OptionValueBase&) = default;
+ OptionValueBase &operator=(const OptionValueBase &) = default;
+ ~OptionValueBase() = default;
+};
+
+// Top-level option class.
+template <class DataType>
+struct OptionValue final
+ : OptionValueBase<DataType, std::is_class<DataType>::value> {
+ OptionValue() = default;
+
+ OptionValue(const DataType &V) { this->setValue(V); }
+
+ // Some options may take their value from a different data type.
+ template <class DT> OptionValue<DataType> &operator=(const DT &V) {
+ this->setValue(V);
+ return *this;
+ }
+};
+
+// Other safe-to-copy-by-value common option types.
+enum boolOrDefault { BOU_UNSET, BOU_TRUE, BOU_FALSE };
+template <>
+struct OptionValue<cl::boolOrDefault> final
+ : OptionValueCopy<cl::boolOrDefault> {
+ using WrapperType = cl::boolOrDefault;
+
+ OptionValue() = default;
+
+ OptionValue(const cl::boolOrDefault &V) { this->setValue(V); }
+
+ OptionValue<cl::boolOrDefault> &operator=(const cl::boolOrDefault &V) {
+ setValue(V);
+ return *this;
+ }
+
+private:
+ void anchor() override;
+};
+
+template <>
+struct OptionValue<std::string> final : OptionValueCopy<std::string> {
+ using WrapperType = StringRef;
+
+ OptionValue() = default;
+
+ OptionValue(const std::string &V) { this->setValue(V); }
+
+ OptionValue<std::string> &operator=(const std::string &V) {
+ setValue(V);
+ return *this;
+ }
+
+private:
+ void anchor() override;
+};
+
+//===----------------------------------------------------------------------===//
+// Enum valued command line option
+//
+
+// This represents a single enum value, using "int" as the underlying type.
+struct OptionEnumValue {
+ StringRef Name;
+ int Value;
+ StringRef Description;
+};
+
+#define clEnumVal(ENUMVAL, DESC) \
+ llvm::cl::OptionEnumValue { #ENUMVAL, int(ENUMVAL), DESC }
+#define clEnumValN(ENUMVAL, FLAGNAME, DESC) \
+ llvm::cl::OptionEnumValue { FLAGNAME, int(ENUMVAL), DESC }
+
+// For custom data types, allow specifying a group of values together as the
+// values that go into the mapping that the option handler uses.
+//
+class ValuesClass {
+ // Use a vector instead of a map, because the lists should be short,
+ // the overhead is less, and most importantly, it keeps them in the order
+ // inserted so we can print our option out nicely.
+ SmallVector<OptionEnumValue, 4> Values;
+
+public:
+ ValuesClass(std::initializer_list<OptionEnumValue> Options)
+ : Values(Options) {}
+
+ template <class Opt> void apply(Opt &O) const {
+ for (const auto &Value : Values)
+ O.getParser().addLiteralOption(Value.Name, Value.Value,
+ Value.Description);
+ }
+};
+
+/// Helper to build a ValuesClass by forwarding a variable number of arguments
+/// as an initializer list to the ValuesClass constructor.
+template <typename... OptsTy> ValuesClass values(OptsTy... Options) {
+ return ValuesClass({Options...});
+}
+
+//===----------------------------------------------------------------------===//
+// Parameterizable parser for different data types. By default, known data types
+// (string, int, bool) have specialized parsers, that do what you would expect.
+// The default parser, used for data types that are not built-in, uses a mapping
+// table to map specific options to values, which is used, among other things,
+// to handle enum types.
+
+//--------------------------------------------------
+// This class holds all the non-generic code that we do not need replicated for
+// every instance of the generic parser. This also allows us to put stuff into
+// CommandLine.cpp
+//
+class generic_parser_base {
+protected:
+ class GenericOptionInfo {
+ public:
+ GenericOptionInfo(StringRef name, StringRef helpStr)
+ : Name(name), HelpStr(helpStr) {}
+ StringRef Name;
+ StringRef HelpStr;
+ };
+
+public:
+ generic_parser_base(Option &O) : Owner(O) {}
+
+ virtual ~generic_parser_base() = default;
+ // Base class should have virtual-destructor
+
+ // Virtual function implemented by generic subclass to indicate how many
+ // entries are in Values.
+ //
+ virtual unsigned getNumOptions() const = 0;
+
+ // Return option name N.
+ virtual StringRef getOption(unsigned N) const = 0;
+
+ // Return description N
+ virtual StringRef getDescription(unsigned N) const = 0;
+
+ // Return the width of the option tag for printing...
+ virtual size_t getOptionWidth(const Option &O) const;
+
+ virtual const GenericOptionValue &getOptionValue(unsigned N) const = 0;
+
+ // Print out information about this option. The to-be-maintained width is
+ // specified.
+ //
+ virtual void printOptionInfo(const Option &O, size_t GlobalWidth) const;
+
+ void printGenericOptionDiff(const Option &O, const GenericOptionValue &V,
+ const GenericOptionValue &Default,
+ size_t GlobalWidth) const;
+
+ // Print the value of an option and it's default.
+ //
+ // Template definition ensures that the option and default have the same
+ // DataType (via the same AnyOptionValue).
+ template <class AnyOptionValue>
+ void printOptionDiff(const Option &O, const AnyOptionValue &V,
+ const AnyOptionValue &Default,
+ size_t GlobalWidth) const {
+ printGenericOptionDiff(O, V, Default, GlobalWidth);
+ }
+
+ void initialize() {}
+
+ void getExtraOptionNames(SmallVectorImpl<StringRef> &OptionNames) {
+ // If there has been no argstr specified, that means that we need to add an
+ // argument for every possible option. This ensures that our options are
+ // vectored to us.
+ if (!Owner.hasArgStr())
+ for (unsigned i = 0, e = getNumOptions(); i != e; ++i)
+ OptionNames.push_back(getOption(i));
+ }
+
+ enum ValueExpected getValueExpectedFlagDefault() const {
+ // If there is an ArgStr specified, then we are of the form:
+ //
+ // -opt=O2 or -opt O2 or -optO2
+ //
+ // In which case, the value is required. Otherwise if an arg str has not
+ // been specified, we are of the form:
+ //
+ // -O2 or O2 or -la (where -l and -a are separate options)
+ //
+ // If this is the case, we cannot allow a value.
+ //
+ if (Owner.hasArgStr())
+ return ValueRequired;
+ else
+ return ValueDisallowed;
+ }
+
+ // Return the option number corresponding to the specified
+ // argument string. If the option is not found, getNumOptions() is returned.
+ //
+ unsigned findOption(StringRef Name);
+
+protected:
+ Option &Owner;
+};
+
+// Default parser implementation - This implementation depends on having a
+// mapping of recognized options to values of some sort. In addition to this,
+// each entry in the mapping also tracks a help message that is printed with the
+// command line option for -help. Because this is a simple mapping parser, the
+// data type can be any unsupported type.
+//
+template <class DataType> class parser : public generic_parser_base {
+protected:
+ class OptionInfo : public GenericOptionInfo {
+ public:
+ OptionInfo(StringRef name, DataType v, StringRef helpStr)
+ : GenericOptionInfo(name, helpStr), V(v) {}
+
+ OptionValue<DataType> V;
+ };
+ SmallVector<OptionInfo, 8> Values;
+
+public:
+ parser(Option &O) : generic_parser_base(O) {}
+
+ using parser_data_type = DataType;
+
+ // Implement virtual functions needed by generic_parser_base
+ unsigned getNumOptions() const override { return unsigned(Values.size()); }
+ StringRef getOption(unsigned N) const override { return Values[N].Name; }
+ StringRef getDescription(unsigned N) const override {
+ return Values[N].HelpStr;
+ }
+
+ // Return the value of option name N.
+ const GenericOptionValue &getOptionValue(unsigned N) const override {
+ return Values[N].V;
+ }
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, DataType &V) {
+ StringRef ArgVal;
+ if (Owner.hasArgStr())
+ ArgVal = Arg;
+ else
+ ArgVal = ArgName;
+
+ for (size_t i = 0, e = Values.size(); i != e; ++i)
+ if (Values[i].Name == ArgVal) {
+ V = Values[i].V.getValue();
+ return false;
+ }
+
+ return O.error("Cannot find option named '" + ArgVal + "'!");
+ }
+
+ /// Add an entry to the mapping table.
+ ///
+ template <class DT>
+ void addLiteralOption(StringRef Name, const DT &V, StringRef HelpStr) {
+ assert(findOption(Name) == Values.size() && "Option already exists!");
+ OptionInfo X(Name, static_cast<DataType>(V), HelpStr);
+ Values.push_back(X);
+ AddLiteralOption(Owner, Name);
+ }
+
+ /// Remove the specified option.
+ ///
+ void removeLiteralOption(StringRef Name) {
+ unsigned N = findOption(Name);
+ assert(N != Values.size() && "Option not found!");
+ Values.erase(Values.begin() + N);
+ }
+};
+
+//--------------------------------------------------
+// Super class of parsers to provide boilerplate code
+//
+class basic_parser_impl { // non-template implementation of basic_parser<t>
+public:
+ basic_parser_impl(Option &) {}
+
+ virtual ~basic_parser_impl() = default;
+
+ enum ValueExpected getValueExpectedFlagDefault() const {
+ return ValueRequired;
+ }
+
+ void getExtraOptionNames(SmallVectorImpl<StringRef> &) {}
+
+ void initialize() {}
+
+ // Return the width of the option tag for printing...
+ size_t getOptionWidth(const Option &O) const;
+
+ // Print out information about this option. The to-be-maintained width is
+ // specified.
+ //
+ void printOptionInfo(const Option &O, size_t GlobalWidth) const;
+
+ // Print a placeholder for options that don't yet support printOptionDiff().
+ void printOptionNoValue(const Option &O, size_t GlobalWidth) const;
+
+ // Overload in subclass to provide a better default value.
+ virtual StringRef getValueName() const { return "value"; }
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ virtual void anchor();
+
+protected:
+ // A helper for basic_parser::printOptionDiff.
+ void printOptionName(const Option &O, size_t GlobalWidth) const;
+};
+
+// The real basic parser is just a template wrapper that provides a typedef for
+// the provided data type.
+//
+template <class DataType> class basic_parser : public basic_parser_impl {
+public:
+ using parser_data_type = DataType;
+ using OptVal = OptionValue<DataType>;
+
+ basic_parser(Option &O) : basic_parser_impl(O) {}
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<bool>;
+
+template <> class parser<bool> : public basic_parser<bool> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, bool &Val);
+
+ void initialize() {}
+
+ enum ValueExpected getValueExpectedFlagDefault() const {
+ return ValueOptional;
+ }
+
+ // Do not print =<value> at all.
+ StringRef getValueName() const override { return StringRef(); }
+
+ void printOptionDiff(const Option &O, bool V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<boolOrDefault>;
+
+template <> class parser<boolOrDefault> : public basic_parser<boolOrDefault> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, boolOrDefault &Val);
+
+ enum ValueExpected getValueExpectedFlagDefault() const {
+ return ValueOptional;
+ }
+
+ // Do not print =<value> at all.
+ StringRef getValueName() const override { return StringRef(); }
+
+ void printOptionDiff(const Option &O, boolOrDefault V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<int>;
+
+template <> class parser<int> : public basic_parser<int> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, int &Val);
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "int"; }
+
+ void printOptionDiff(const Option &O, int V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<long>;
+
+template <> class parser<long> final : public basic_parser<long> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, long &Val);
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "long"; }
+
+ void printOptionDiff(const Option &O, long V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<long long>;
+
+template <> class parser<long long> : public basic_parser<long long> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, long long &Val);
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "long"; }
+
+ void printOptionDiff(const Option &O, long long V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<unsigned>;
+
+template <> class parser<unsigned> : public basic_parser<unsigned> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, unsigned &Val);
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "uint"; }
+
+ void printOptionDiff(const Option &O, unsigned V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<unsigned long>;
+
+template <>
+class parser<unsigned long> final : public basic_parser<unsigned long> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, unsigned long &Val);
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "ulong"; }
+
+ void printOptionDiff(const Option &O, unsigned long V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<unsigned long long>;
+
+template <>
+class parser<unsigned long long> : public basic_parser<unsigned long long> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg,
+ unsigned long long &Val);
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "ulong"; }
+
+ void printOptionDiff(const Option &O, unsigned long long V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<double>;
+
+template <> class parser<double> : public basic_parser<double> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, double &Val);
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "number"; }
+
+ void printOptionDiff(const Option &O, double V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<float>;
+
+template <> class parser<float> : public basic_parser<float> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &O, StringRef ArgName, StringRef Arg, float &Val);
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "number"; }
+
+ void printOptionDiff(const Option &O, float V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<std::string>;
+
+template <> class parser<std::string> : public basic_parser<std::string> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &, StringRef, StringRef Arg, std::string &Value) {
+ Value = Arg.str();
+ return false;
+ }
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "string"; }
+
+ void printOptionDiff(const Option &O, StringRef V, const OptVal &Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+
+extern template class basic_parser<char>;
+
+template <> class parser<char> : public basic_parser<char> {
+public:
+ parser(Option &O) : basic_parser(O) {}
+
+ // Return true on error.
+ bool parse(Option &, StringRef, StringRef Arg, char &Value) {
+ Value = Arg[0];
+ return false;
+ }
+
+ // Overload in subclass to provide a better default value.
+ StringRef getValueName() const override { return "char"; }
+
+ void printOptionDiff(const Option &O, char V, OptVal Default,
+ size_t GlobalWidth) const;
+
+ // An out-of-line virtual method to provide a 'home' for this class.
+ void anchor() override;
+};
+
+//--------------------------------------------------
+// This collection of wrappers is the intermediary between class opt and class
+// parser to handle all the template nastiness.
+
+// This overloaded function is selected by the generic parser.
+template <class ParserClass, class DT>
+void printOptionDiff(const Option &O, const generic_parser_base &P, const DT &V,
+ const OptionValue<DT> &Default, size_t GlobalWidth) {
+ OptionValue<DT> OV = V;
+ P.printOptionDiff(O, OV, Default, GlobalWidth);
+}
+
+// This is instantiated for basic parsers when the parsed value has a different
+// type than the option value. e.g. HelpPrinter.
+template <class ParserDT, class ValDT> struct OptionDiffPrinter {
+ void print(const Option &O, const parser<ParserDT> &P, const ValDT & /*V*/,
+ const OptionValue<ValDT> & /*Default*/, size_t GlobalWidth) {
+ P.printOptionNoValue(O, GlobalWidth);
+ }
+};
+
+// This is instantiated for basic parsers when the parsed value has the same
+// type as the option value.
+template <class DT> struct OptionDiffPrinter<DT, DT> {
+ void print(const Option &O, const parser<DT> &P, const DT &V,
+ const OptionValue<DT> &Default, size_t GlobalWidth) {
+ P.printOptionDiff(O, V, Default, GlobalWidth);
+ }
+};
+
+// This overloaded function is selected by the basic parser, which may parse a
+// different type than the option type.
+template <class ParserClass, class ValDT>
+void printOptionDiff(
+ const Option &O,
+ const basic_parser<typename ParserClass::parser_data_type> &P,
+ const ValDT &V, const OptionValue<ValDT> &Default, size_t GlobalWidth) {
+
+ OptionDiffPrinter<typename ParserClass::parser_data_type, ValDT> printer;
+ printer.print(O, static_cast<const ParserClass &>(P), V, Default,
+ GlobalWidth);
+}
+
+//===----------------------------------------------------------------------===//
+// This class is used because we must use partial specialization to handle
+// literal string arguments specially (const char* does not correctly respond to
+// the apply method). Because the syntax to use this is a pain, we have the
+// 'apply' method below to handle the nastiness...
+//
+template <class Mod> struct applicator {
+ template <class Opt> static void opt(const Mod &M, Opt &O) { M.apply(O); }
+};
+
+// Handle const char* as a special case...
+template <unsigned n> struct applicator<char[n]> {
+ template <class Opt> static void opt(StringRef Str, Opt &O) {
+ O.setArgStr(Str);
+ }
+};
+template <unsigned n> struct applicator<const char[n]> {
+ template <class Opt> static void opt(StringRef Str, Opt &O) {
+ O.setArgStr(Str);
+ }
+};
+template <> struct applicator<StringRef > {
+ template <class Opt> static void opt(StringRef Str, Opt &O) {
+ O.setArgStr(Str);
+ }
+};
+
+template <> struct applicator<NumOccurrencesFlag> {
+ static void opt(NumOccurrencesFlag N, Option &O) {
+ O.setNumOccurrencesFlag(N);
+ }
+};
+
+template <> struct applicator<ValueExpected> {
+ static void opt(ValueExpected VE, Option &O) { O.setValueExpectedFlag(VE); }
+};
+
+template <> struct applicator<OptionHidden> {
+ static void opt(OptionHidden OH, Option &O) { O.setHiddenFlag(OH); }
+};
+
+template <> struct applicator<FormattingFlags> {
+ static void opt(FormattingFlags FF, Option &O) { O.setFormattingFlag(FF); }
+};
+
+template <> struct applicator<MiscFlags> {
+ static void opt(MiscFlags MF, Option &O) {
+ assert((MF != Grouping || O.ArgStr.size() == 1) &&
+ "cl::Grouping can only apply to single character Options.");
+ O.setMiscFlag(MF);
+ }
+};
+
+// Apply modifiers to an option in a type safe way.
+template <class Opt, class Mod, class... Mods>
+void apply(Opt *O, const Mod &M, const Mods &... Ms) {
+ applicator<Mod>::opt(M, *O);
+ apply(O, Ms...);
+}
+
+template <class Opt, class Mod> void apply(Opt *O, const Mod &M) {
+ applicator<Mod>::opt(M, *O);
+}
+
+//===----------------------------------------------------------------------===//
+// Default storage class definition: external storage. This implementation
+// assumes the user will specify a variable to store the data into with the
+// cl::location(x) modifier.
+//
+template <class DataType, bool ExternalStorage, bool isClass>
+class opt_storage {
+ DataType *Location = nullptr; // Where to store the object...
+ OptionValue<DataType> Default;
+
+ void check_location() const {
+ assert(Location && "cl::location(...) not specified for a command "
+ "line option with external storage, "
+ "or cl::init specified before cl::location()!!");
+ }
+
+public:
+ opt_storage() = default;
+
+ bool setLocation(Option &O, DataType &L) {
+ if (Location)
+ return O.error("cl::location(x) specified more than once!");
+ Location = &L;
+ Default = L;
+ return false;
+ }
+
+ template <class T> void setValue(const T &V, bool initial = false) {
+ check_location();
+ *Location = V;
+ if (initial)
+ Default = V;
+ }
+
+ DataType &getValue() {
+ check_location();
+ return *Location;
+ }
+ const DataType &getValue() const {
+ check_location();
+ return *Location;
+ }
+
+ operator DataType() const { return this->getValue(); }
+
+ const OptionValue<DataType> &getDefault() const { return Default; }
+};
+
+// Define how to hold a class type object, such as a string. Since we can
+// inherit from a class, we do so. This makes us exactly compatible with the
+// object in all cases that it is used.
+//
+template <class DataType>
+class opt_storage<DataType, false, true> : public DataType {
+public:
+ OptionValue<DataType> Default;
+
+ template <class T> void setValue(const T &V, bool initial = false) {
+ DataType::operator=(V);
+ if (initial)
+ Default = V;
+ }
+
+ DataType &getValue() { return *this; }
+ const DataType &getValue() const { return *this; }
+
+ const OptionValue<DataType> &getDefault() const { return Default; }
+};
+
+// Define a partial specialization to handle things we cannot inherit from. In
+// this case, we store an instance through containment, and overload operators
+// to get at the value.
+//
+template <class DataType> class opt_storage<DataType, false, false> {
+public:
+ DataType Value;
+ OptionValue<DataType> Default;
+
+ // Make sure we initialize the value with the default constructor for the
+ // type.
+ opt_storage() : Value(DataType()), Default() {}
+
+ template <class T> void setValue(const T &V, bool initial = false) {
+ Value = V;
+ if (initial)
+ Default = V;
+ }
+ DataType &getValue() { return Value; }
+ DataType getValue() const { return Value; }
+
+ const OptionValue<DataType> &getDefault() const { return Default; }
+
+ operator DataType() const { return getValue(); }
+
+ // If the datatype is a pointer, support -> on it.
+ DataType operator->() const { return Value; }
+};
+
+//===----------------------------------------------------------------------===//
+// A scalar command line option.
+//
+template <class DataType, bool ExternalStorage = false,
+ class ParserClass = parser<DataType>>
+class opt : public Option,
+ public opt_storage<DataType, ExternalStorage,
+ std::is_class<DataType>::value> {
+ ParserClass Parser;
+
+ bool handleOccurrence(unsigned pos, StringRef ArgName,
+ StringRef Arg) override {
+ typename ParserClass::parser_data_type Val =
+ typename ParserClass::parser_data_type();
+ if (Parser.parse(*this, ArgName, Arg, Val))
+ return true; // Parse error!
+ this->setValue(Val);
+ this->setPosition(pos);
+ Callback(Val);
+ return false;
+ }
+
+ enum ValueExpected getValueExpectedFlagDefault() const override {
+ return Parser.getValueExpectedFlagDefault();
+ }
+
+ void getExtraOptionNames(SmallVectorImpl<StringRef> &OptionNames) override {
+ return Parser.getExtraOptionNames(OptionNames);
+ }
+
+ // Forward printing stuff to the parser...
+ size_t getOptionWidth() const override {
+ return Parser.getOptionWidth(*this);
+ }
+
+ void printOptionInfo(size_t GlobalWidth) const override {
+ Parser.printOptionInfo(*this, GlobalWidth);
+ }
+
+ void printOptionValue(size_t GlobalWidth, bool Force) const override {
+ if (Force || this->getDefault().compare(this->getValue())) {
+ cl::printOptionDiff<ParserClass>(*this, Parser, this->getValue(),
+ this->getDefault(), GlobalWidth);
+ }
+ }
+
+ template <class T,
+ class = std::enable_if_t<std::is_assignable<T &, T>::value>>
+ void setDefaultImpl() {
+ const OptionValue<DataType> &V = this->getDefault();
+ if (V.hasValue())
+ this->setValue(V.getValue());
+ else
+ this->setValue(T());
+ }
+
+ template <class T,
+ class = std::enable_if_t<!std::is_assignable<T &, T>::value>>
+ void setDefaultImpl(...) {}
+
+ void setDefault() override { setDefaultImpl<DataType>(); }
+
+ void done() {
+ addArgument();
+ Parser.initialize();
+ }
+
+public:
+ // Command line options should not be copyable
+ opt(const opt &) = delete;
+ opt &operator=(const opt &) = delete;
+
+ // setInitialValue - Used by the cl::init modifier...
+ void setInitialValue(const DataType &V) { this->setValue(V, true); }
+
+ ParserClass &getParser() { return Parser; }
+
+ template <class T> DataType &operator=(const T &Val) {
+ this->setValue(Val);
+ Callback(Val);
+ return this->getValue();
+ }
+
+ template <class... Mods>
+ explicit opt(const Mods &... Ms)
+ : Option(llvm::cl::Optional, NotHidden), Parser(*this) {
+ apply(this, Ms...);
+ done();
+ }
+
+ void setCallback(
+ std::function<void(const typename ParserClass::parser_data_type &)> CB) {
+ Callback = CB;
+ }
+
+ std::function<void(const typename ParserClass::parser_data_type &)> Callback =
+ [](const typename ParserClass::parser_data_type &) {};
+};
+
+extern template class opt<unsigned>;
+extern template class opt<int>;
+extern template class opt<std::string>;
+extern template class opt<char>;
+extern template class opt<bool>;
+
+//===----------------------------------------------------------------------===//
+// Default storage class definition: external storage. This implementation
+// assumes the user will specify a variable to store the data into with the
+// cl::location(x) modifier.
+//
+template <class DataType, class StorageClass> class list_storage {
+ StorageClass *Location = nullptr; // Where to store the object...
+ std::vector<OptionValue<DataType>> Default =
+ std::vector<OptionValue<DataType>>();
+ bool DefaultAssigned = false;
+
+public:
+ list_storage() = default;
+
+ void clear() {}
+
+ bool setLocation(Option &O, StorageClass &L) {
+ if (Location)
+ return O.error("cl::location(x) specified more than once!");
+ Location = &L;
+ return false;
+ }
+
+ template <class T> void addValue(const T &V, bool initial = false) {
+ assert(Location != nullptr &&
+ "cl::location(...) not specified for a command "
+ "line option with external storage!");
+ Location->push_back(V);
+ if (initial)
+ Default.push_back(V);
+ }
+
+ const std::vector<OptionValue<DataType>> &getDefault() const {
+ return Default;
+ }
+
+ void assignDefault() { DefaultAssigned = true; }
+ void overwriteDefault() { DefaultAssigned = false; }
+ bool isDefaultAssigned() { return DefaultAssigned; }
+};
+
+// Define how to hold a class type object, such as a string.
+// Originally this code inherited from std::vector. In transitioning to a new
+// API for command line options we should change this. The new implementation
+// of this list_storage specialization implements the minimum subset of the
+// std::vector API required for all the current clients.
+//
+// FIXME: Reduce this API to a more narrow subset of std::vector
+//
+template <class DataType> class list_storage<DataType, bool> {
+ std::vector<DataType> Storage;
+ std::vector<OptionValue<DataType>> Default;
+ bool DefaultAssigned = false;
+
+public:
+ using iterator = typename std::vector<DataType>::iterator;
+
+ iterator begin() { return Storage.begin(); }
+ iterator end() { return Storage.end(); }
+
+ using const_iterator = typename std::vector<DataType>::const_iterator;
+
+ const_iterator begin() const { return Storage.begin(); }
+ const_iterator end() const { return Storage.end(); }
+
+ using size_type = typename std::vector<DataType>::size_type;
+
+ size_type size() const { return Storage.size(); }
+
+ bool empty() const { return Storage.empty(); }
+
+ void push_back(const DataType &value) { Storage.push_back(value); }
+ void push_back(DataType &&value) { Storage.push_back(value); }
+
+ using reference = typename std::vector<DataType>::reference;
+ using const_reference = typename std::vector<DataType>::const_reference;
+
+ reference operator[](size_type pos) { return Storage[pos]; }
+ const_reference operator[](size_type pos) const { return Storage[pos]; }
+
+ void clear() {
+ Storage.clear();
+ }
+
+ iterator erase(const_iterator pos) { return Storage.erase(pos); }
+ iterator erase(const_iterator first, const_iterator last) {
+ return Storage.erase(first, last);
+ }
+
+ iterator erase(iterator pos) { return Storage.erase(pos); }
+ iterator erase(iterator first, iterator last) {
+ return Storage.erase(first, last);
+ }
+
+ iterator insert(const_iterator pos, const DataType &value) {
+ return Storage.insert(pos, value);
+ }
+ iterator insert(const_iterator pos, DataType &&value) {
+ return Storage.insert(pos, value);
+ }
+
+ iterator insert(iterator pos, const DataType &value) {
+ return Storage.insert(pos, value);
+ }
+ iterator insert(iterator pos, DataType &&value) {
+ return Storage.insert(pos, value);
+ }
+
+ reference front() { return Storage.front(); }
+ const_reference front() const { return Storage.front(); }
+
+ operator std::vector<DataType> &() { return Storage; }
+ operator ArrayRef<DataType>() const { return Storage; }
+ std::vector<DataType> *operator&() { return &Storage; }
+ const std::vector<DataType> *operator&() const { return &Storage; }
+
+ template <class T> void addValue(const T &V, bool initial = false) {
+ Storage.push_back(V);
+ if (initial)
+ Default.push_back(OptionValue<DataType>(V));
+ }
+
+ const std::vector<OptionValue<DataType>> &getDefault() const {
+ return Default;
+ }
+
+ void assignDefault() { DefaultAssigned = true; }
+ void overwriteDefault() { DefaultAssigned = false; }
+ bool isDefaultAssigned() { return DefaultAssigned; }
+};
+
+//===----------------------------------------------------------------------===//
+// A list of command line options.
+//
+template <class DataType, class StorageClass = bool,
+ class ParserClass = parser<DataType>>
+class list : public Option, public list_storage<DataType, StorageClass> {
+ std::vector<unsigned> Positions;
+ ParserClass Parser;
+
+ enum ValueExpected getValueExpectedFlagDefault() const override {
+ return Parser.getValueExpectedFlagDefault();
+ }
+
+ void getExtraOptionNames(SmallVectorImpl<StringRef> &OptionNames) override {
+ return Parser.getExtraOptionNames(OptionNames);
+ }
+
+ bool handleOccurrence(unsigned pos, StringRef ArgName,
+ StringRef Arg) override {
+ typename ParserClass::parser_data_type Val =
+ typename ParserClass::parser_data_type();
+ if (list_storage<DataType, StorageClass>::isDefaultAssigned()) {
+ clear();
+ list_storage<DataType, StorageClass>::overwriteDefault();
+ }
+ if (Parser.parse(*this, ArgName, Arg, Val))
+ return true; // Parse Error!
+ list_storage<DataType, StorageClass>::addValue(Val);
+ setPosition(pos);
+ Positions.push_back(pos);
+ Callback(Val);
+ return false;
+ }
+
+ // Forward printing stuff to the parser...
+ size_t getOptionWidth() const override {
+ return Parser.getOptionWidth(*this);
+ }
+
+ void printOptionInfo(size_t GlobalWidth) const override {
+ Parser.printOptionInfo(*this, GlobalWidth);
+ }
+
+ // Unimplemented: list options don't currently store their default value.
+ void printOptionValue(size_t /*GlobalWidth*/, bool /*Force*/) const override {
+ }
+
+ void setDefault() override {
+ Positions.clear();
+ list_storage<DataType, StorageClass>::clear();
+ for (auto &Val : list_storage<DataType, StorageClass>::getDefault())
+ list_storage<DataType, StorageClass>::addValue(Val.getValue());
+ }
+
+ void done() {
+ addArgument();
+ Parser.initialize();
+ }
+
+public:
+ // Command line options should not be copyable
+ list(const list &) = delete;
+ list &operator=(const list &) = delete;
+
+ ParserClass &getParser() { return Parser; }
+
+ unsigned getPosition(unsigned optnum) const {
+ assert(optnum < this->size() && "Invalid option index");
+ return Positions[optnum];
+ }
+
+ void clear() {
+ Positions.clear();
+ list_storage<DataType, StorageClass>::clear();
+ }
+
+ // setInitialValues - Used by the cl::list_init modifier...
+ void setInitialValues(ArrayRef<DataType> Vs) {
+ assert(!(list_storage<DataType, StorageClass>::isDefaultAssigned()) &&
+ "Cannot have two default values");
+ list_storage<DataType, StorageClass>::assignDefault();
+ for (auto &Val : Vs)
+ list_storage<DataType, StorageClass>::addValue(Val, true);
+ }
+
+ void setNumAdditionalVals(unsigned n) { Option::setNumAdditionalVals(n); }
+
+ template <class... Mods>
+ explicit list(const Mods &... Ms)
+ : Option(ZeroOrMore, NotHidden), Parser(*this) {
+ apply(this, Ms...);
+ done();
+ }
+
+ void setCallback(
+ std::function<void(const typename ParserClass::parser_data_type &)> CB) {
+ Callback = CB;
+ }
+
+ std::function<void(const typename ParserClass::parser_data_type &)> Callback =
+ [](const typename ParserClass::parser_data_type &) {};
+};
+
+// Modifier to set the number of additional values.
+struct multi_val {
+ unsigned AdditionalVals;
+ explicit multi_val(unsigned N) : AdditionalVals(N) {}
+
+ template <typename D, typename S, typename P>
+ void apply(list<D, S, P> &L) const {
+ L.setNumAdditionalVals(AdditionalVals);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Default storage class definition: external storage. This implementation
+// assumes the user will specify a variable to store the data into with the
+// cl::location(x) modifier.
+//
+template <class DataType, class StorageClass> class bits_storage {
+ unsigned *Location = nullptr; // Where to store the bits...
+
+ template <class T> static unsigned Bit(const T &V) {
+ unsigned BitPos = static_cast<unsigned>(V);
+ assert(BitPos < sizeof(unsigned) * CHAR_BIT &&
+ "enum exceeds width of bit vector!");
+ return 1 << BitPos;
+ }
+
+public:
+ bits_storage() = default;
+
+ bool setLocation(Option &O, unsigned &L) {
+ if (Location)
+ return O.error("cl::location(x) specified more than once!");
+ Location = &L;
+ return false;
+ }
+
+ template <class T> void addValue(const T &V) {
+ assert(Location != nullptr &&
+ "cl::location(...) not specified for a command "
+ "line option with external storage!");
+ *Location |= Bit(V);
+ }
+
+ unsigned getBits() { return *Location; }
+
+ void clear() {
+ if (Location)
+ *Location = 0;
+ }
+
+ template <class T> bool isSet(const T &V) {
+ return (*Location & Bit(V)) != 0;
+ }
+};
+
+// Define how to hold bits. Since we can inherit from a class, we do so.
+// This makes us exactly compatible with the bits in all cases that it is used.
+//
+template <class DataType> class bits_storage<DataType, bool> {
+ unsigned Bits{0}; // Where to store the bits...
+
+ template <class T> static unsigned Bit(const T &V) {
+ unsigned BitPos = static_cast<unsigned>(V);
+ assert(BitPos < sizeof(unsigned) * CHAR_BIT &&
+ "enum exceeds width of bit vector!");
+ return 1 << BitPos;
+ }
+
+public:
+ template <class T> void addValue(const T &V) { Bits |= Bit(V); }
+
+ unsigned getBits() { return Bits; }
+
+ void clear() { Bits = 0; }
+
+ template <class T> bool isSet(const T &V) { return (Bits & Bit(V)) != 0; }
+};
+
+//===----------------------------------------------------------------------===//
+// A bit vector of command options.
+//
+template <class DataType, class Storage = bool,
+ class ParserClass = parser<DataType>>
+class bits : public Option, public bits_storage<DataType, Storage> {
+ std::vector<unsigned> Positions;
+ ParserClass Parser;
+
+ enum ValueExpected getValueExpectedFlagDefault() const override {
+ return Parser.getValueExpectedFlagDefault();
+ }
+
+ void getExtraOptionNames(SmallVectorImpl<StringRef> &OptionNames) override {
+ return Parser.getExtraOptionNames(OptionNames);
+ }
+
+ bool handleOccurrence(unsigned pos, StringRef ArgName,
+ StringRef Arg) override {
+ typename ParserClass::parser_data_type Val =
+ typename ParserClass::parser_data_type();
+ if (Parser.parse(*this, ArgName, Arg, Val))
+ return true; // Parse Error!
+ this->addValue(Val);
+ setPosition(pos);
+ Positions.push_back(pos);
+ Callback(Val);
+ return false;
+ }
+
+ // Forward printing stuff to the parser...
+ size_t getOptionWidth() const override {
+ return Parser.getOptionWidth(*this);
+ }
+
+ void printOptionInfo(size_t GlobalWidth) const override {
+ Parser.printOptionInfo(*this, GlobalWidth);
+ }
+
+ // Unimplemented: bits options don't currently store their default values.
+ void printOptionValue(size_t /*GlobalWidth*/, bool /*Force*/) const override {
+ }
+
+ void setDefault() override { bits_storage<DataType, Storage>::clear(); }
+
+ void done() {
+ addArgument();
+ Parser.initialize();
+ }
+
+public:
+ // Command line options should not be copyable
+ bits(const bits &) = delete;
+ bits &operator=(const bits &) = delete;
+
+ ParserClass &getParser() { return Parser; }
+
+ unsigned getPosition(unsigned optnum) const {
+ assert(optnum < this->size() && "Invalid option index");
+ return Positions[optnum];
+ }
+
+ template <class... Mods>
+ explicit bits(const Mods &... Ms)
+ : Option(ZeroOrMore, NotHidden), Parser(*this) {
+ apply(this, Ms...);
+ done();
+ }
+
+ void setCallback(
+ std::function<void(const typename ParserClass::parser_data_type &)> CB) {
+ Callback = CB;
+ }
+
+ std::function<void(const typename ParserClass::parser_data_type &)> Callback =
+ [](const typename ParserClass::parser_data_type &) {};
+};
+
+//===----------------------------------------------------------------------===//
+// Aliased command line option (alias this name to a preexisting name)
+//
+
+class alias : public Option {
+ Option *AliasFor;
+
+ bool handleOccurrence(unsigned pos, StringRef /*ArgName*/,
+ StringRef Arg) override {
+ return AliasFor->handleOccurrence(pos, AliasFor->ArgStr, Arg);
+ }
+
+ bool addOccurrence(unsigned pos, StringRef /*ArgName*/, StringRef Value,
+ bool MultiArg = false) override {
+ return AliasFor->addOccurrence(pos, AliasFor->ArgStr, Value, MultiArg);
+ }
+
+ // Handle printing stuff...
+ size_t getOptionWidth() const override;
+ void printOptionInfo(size_t GlobalWidth) const override;
+
+ // Aliases do not need to print their values.
+ void printOptionValue(size_t /*GlobalWidth*/, bool /*Force*/) const override {
+ }
+
+ void setDefault() override { AliasFor->setDefault(); }
+
+ ValueExpected getValueExpectedFlagDefault() const override {
+ return AliasFor->getValueExpectedFlag();
+ }
+
+ void done() {
+ if (!hasArgStr())
+ error("cl::alias must have argument name specified!");
+ if (!AliasFor)
+ error("cl::alias must have an cl::aliasopt(option) specified!");
+ if (!Subs.empty())
+ error("cl::alias must not have cl::sub(), aliased option's cl::sub() will be used!");
+ Subs = AliasFor->Subs;
+ Categories = AliasFor->Categories;
+ addArgument();
+ }
+
+public:
+ // Command line options should not be copyable
+ alias(const alias &) = delete;
+ alias &operator=(const alias &) = delete;
+
+ void setAliasFor(Option &O) {
+ if (AliasFor)
+ error("cl::alias must only have one cl::aliasopt(...) specified!");
+ AliasFor = &O;
+ }
+
+ template <class... Mods>
+ explicit alias(const Mods &... Ms)
+ : Option(Optional, Hidden), AliasFor(nullptr) {
+ apply(this, Ms...);
+ done();
+ }
+};
+
+// Modifier to set the option an alias aliases.
+struct aliasopt {
+ Option &Opt;
+
+ explicit aliasopt(Option &O) : Opt(O) {}
+
+ void apply(alias &A) const { A.setAliasFor(Opt); }
+};
+
+// Provide additional help at the end of the normal help output. All occurrences
+// of cl::extrahelp will be accumulated and printed to stderr at the end of the
+// regular help, just before exit is called.
+struct extrahelp {
+ StringRef morehelp;
+
+ explicit extrahelp(StringRef help);
+};
+
+void PrintVersionMessage();
+
+/// This function just prints the help message, exactly the same way as if the
+/// -help or -help-hidden option had been given on the command line.
+///
+/// \param Hidden if true will print hidden options
+/// \param Categorized if true print options in categories
+void PrintHelpMessage(bool Hidden = false, bool Categorized = false);
+
+//===----------------------------------------------------------------------===//
+// Public interface for accessing registered options.
+//
+
+/// Use this to get a StringMap to all registered named options
+/// (e.g. -help).
+///
+/// \return A reference to the StringMap used by the cl APIs to parse options.
+///
+/// Access to unnamed arguments (i.e. positional) are not provided because
+/// it is expected that the client already has access to these.
+///
+/// Typical usage:
+/// \code
+/// main(int argc,char* argv[]) {
+/// StringMap<llvm::cl::Option*> &opts = llvm::cl::getRegisteredOptions();
+/// assert(opts.count("help") == 1)
+/// opts["help"]->setDescription("Show alphabetical help information")
+/// // More code
+/// llvm::cl::ParseCommandLineOptions(argc,argv);
+/// //More code
+/// }
+/// \endcode
+///
+/// This interface is useful for modifying options in libraries that are out of
+/// the control of the client. The options should be modified before calling
+/// llvm::cl::ParseCommandLineOptions().
+///
+/// Hopefully this API can be deprecated soon. Any situation where options need
+/// to be modified by tools or libraries should be handled by sane APIs rather
+/// than just handing around a global list.
+StringMap<Option *> &
+getRegisteredOptions(SubCommand &Sub = SubCommand::getTopLevel());
+
+/// Use this to get all registered SubCommands from the provided parser.
+///
+/// \return A range of all SubCommand pointers registered with the parser.
+///
+/// Typical usage:
+/// \code
+/// main(int argc, char* argv[]) {
+/// llvm::cl::ParseCommandLineOptions(argc, argv);
+/// for (auto* S : llvm::cl::getRegisteredSubcommands()) {
+/// if (*S) {
+/// std::cout << "Executing subcommand: " << S->getName() << std::endl;
+/// // Execute some function based on the name...
+/// }
+/// }
+/// }
+/// \endcode
+///
+/// This interface is useful for defining subcommands in libraries and
+/// the dispatch from a single point (like in the main function).
+iterator_range<typename SmallPtrSet<SubCommand *, 4>::iterator>
+getRegisteredSubcommands();
+
+//===----------------------------------------------------------------------===//
+// Standalone command line processing utilities.
+//
+
+/// Tokenizes a command line that can contain escapes and quotes.
+//
+/// The quoting rules match those used by GCC and other tools that use
+/// libiberty's buildargv() or expandargv() utilities, and do not match bash.
+/// They differ from buildargv() on treatment of backslashes that do not escape
+/// a special character to make it possible to accept most Windows file paths.
+///
+/// \param [in] Source The string to be split on whitespace with quotes.
+/// \param [in] Saver Delegates back to the caller for saving parsed strings.
+/// \param [in] MarkEOLs true if tokenizing a response file and you want end of
+/// lines and end of the response file to be marked with a nullptr string.
+/// \param [out] NewArgv All parsed strings are appended to NewArgv.
+void TokenizeGNUCommandLine(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs = false);
+
+/// Tokenizes a string of Windows command line arguments, which may contain
+/// quotes and escaped quotes.
+///
+/// See MSDN docs for CommandLineToArgvW for information on the quoting rules.
+/// http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft(v=vs.85).aspx
+///
+/// For handling a full Windows command line including the executable name at
+/// the start, see TokenizeWindowsCommandLineFull below.
+///
+/// \param [in] Source The string to be split on whitespace with quotes.
+/// \param [in] Saver Delegates back to the caller for saving parsed strings.
+/// \param [in] MarkEOLs true if tokenizing a response file and you want end of
+/// lines and end of the response file to be marked with a nullptr string.
+/// \param [out] NewArgv All parsed strings are appended to NewArgv.
+void TokenizeWindowsCommandLine(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs = false);
+
+/// Tokenizes a Windows command line while attempting to avoid copies. If no
+/// quoting or escaping was used, this produces substrings of the original
+/// string. If a token requires unquoting, it will be allocated with the
+/// StringSaver.
+void TokenizeWindowsCommandLineNoCopy(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<StringRef> &NewArgv);
+
+/// Tokenizes a Windows full command line, including command name at the start.
+///
+/// This uses the same syntax rules as TokenizeWindowsCommandLine for all but
+/// the first token. But the first token is expected to be parsed as the
+/// executable file name in the way CreateProcess would do it, rather than the
+/// way the C library startup code would do it: CreateProcess does not consider
+/// that \ is ever an escape character (because " is not a valid filename char,
+/// hence there's never a need to escape it to be used literally).
+///
+/// Parameters are the same as for TokenizeWindowsCommandLine. In particular,
+/// if you set MarkEOLs = true, then the first word of every line will be
+/// parsed using the special rules for command names, making this function
+/// suitable for parsing a file full of commands to execute.
+void TokenizeWindowsCommandLineFull(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs = false);
+
+/// String tokenization function type. Should be compatible with either
+/// Windows or Unix command line tokenizers.
+using TokenizerCallback = void (*)(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs);
+
+/// Tokenizes content of configuration file.
+///
+/// \param [in] Source The string representing content of config file.
+/// \param [in] Saver Delegates back to the caller for saving parsed strings.
+/// \param [out] NewArgv All parsed strings are appended to NewArgv.
+/// \param [in] MarkEOLs Added for compatibility with TokenizerCallback.
+///
+/// It works like TokenizeGNUCommandLine with ability to skip comment lines.
+///
+void tokenizeConfigFile(StringRef Source, StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv,
+ bool MarkEOLs = false);
+
+/// Contains options that control response file expansion.
+class ExpansionContext {
+ /// Provides persistent storage for parsed strings.
+ StringSaver Saver;
+
+ /// Tokenization strategy. Typically Unix or Windows.
+ TokenizerCallback Tokenizer;
+
+ /// File system used for all file access when running the expansion.
+ vfs::FileSystem *FS;
+
+ /// Path used to resolve relative rsp files. If empty, the file system
+ /// current directory is used instead.
+ StringRef CurrentDir;
+
+ /// Directories used for search of config files.
+ ArrayRef<StringRef> SearchDirs;
+
+ /// True if names of nested response files must be resolved relative to
+ /// including file.
+ bool RelativeNames = false;
+
+ /// If true, mark end of lines and the end of the response file with nullptrs
+ /// in the Argv vector.
+ bool MarkEOLs = false;
+
+ /// If true, body of config file is expanded.
+ bool InConfigFile = false;
+
+ llvm::Error expandResponseFile(StringRef FName,
+ SmallVectorImpl<const char *> &NewArgv);
+
+public:
+ ExpansionContext(BumpPtrAllocator &A, TokenizerCallback T);
+
+ ExpansionContext &setMarkEOLs(bool X) {
+ MarkEOLs = X;
+ return *this;
+ }
+
+ ExpansionContext &setRelativeNames(bool X) {
+ RelativeNames = X;
+ return *this;
+ }
+
+ ExpansionContext &setCurrentDir(StringRef X) {
+ CurrentDir = X;
+ return *this;
+ }
+
+ ExpansionContext &setSearchDirs(ArrayRef<StringRef> X) {
+ SearchDirs = X;
+ return *this;
+ }
+
+ ExpansionContext &setVFS(vfs::FileSystem *X) {
+ FS = X;
+ return *this;
+ }
+
+ /// Looks for the specified configuration file.
+ ///
+ /// \param[in] FileName Name of the file to search for.
+ /// \param[out] FilePath File absolute path, if it was found.
+ /// \return True if file was found.
+ ///
+ /// If the specified file name contains a directory separator, it is searched
+ /// for by its absolute path. Otherwise looks for file sequentially in
+ /// directories specified by SearchDirs field.
+ bool findConfigFile(StringRef FileName, SmallVectorImpl<char> &FilePath);
+
+ /// Reads command line options from the given configuration file.
+ ///
+ /// \param [in] CfgFile Path to configuration file.
+ /// \param [out] Argv Array to which the read options are added.
+ /// \return true if the file was successfully read.
+ ///
+ /// It reads content of the specified file, tokenizes it and expands "@file"
+ /// commands resolving file names in them relative to the directory where
+ /// CfgFilename resides. It also expands "<CFGDIR>" to the base path of the
+ /// current config file.
+ Error readConfigFile(StringRef CfgFile, SmallVectorImpl<const char *> &Argv);
+
+ /// Expands constructs "@file" in the provided array of arguments recursively.
+ Error expandResponseFiles(SmallVectorImpl<const char *> &Argv);
+};
+
+/// A convenience helper which concatenates the options specified by the
+/// environment variable EnvVar and command line options, then expands
+/// response files recursively.
+/// \return true if all @files were expanded successfully or there were none.
+bool expandResponseFiles(int Argc, const char *const *Argv, const char *EnvVar,
+ SmallVectorImpl<const char *> &NewArgv);
+
+/// A convenience helper which supports the typical use case of expansion
+/// function call.
+bool ExpandResponseFiles(StringSaver &Saver, TokenizerCallback Tokenizer,
+ SmallVectorImpl<const char *> &Argv);
+
+/// A convenience helper which concatenates the options specified by the
+/// environment variable EnvVar and command line options, then expands response
+/// files recursively. The tokenizer is a predefined GNU or Windows one.
+/// \return true if all @files were expanded successfully or there were none.
+bool expandResponseFiles(int Argc, const char *const *Argv, const char *EnvVar,
+ StringSaver &Saver,
+ SmallVectorImpl<const char *> &NewArgv);
+
+/// Mark all options not part of this category as cl::ReallyHidden.
+///
+/// \param Category the category of options to keep displaying
+///
+/// Some tools (like clang-format) like to be able to hide all options that are
+/// not specific to the tool. This function allows a tool to specify a single
+/// option category to display in the -help output.
+void HideUnrelatedOptions(cl::OptionCategory &Category,
+ SubCommand &Sub = SubCommand::getTopLevel());
+
+/// Mark all options not part of the categories as cl::ReallyHidden.
+///
+/// \param Categories the categories of options to keep displaying.
+///
+/// Some tools (like clang-format) like to be able to hide all options that are
+/// not specific to the tool. This function allows a tool to specify a single
+/// option category to display in the -help output.
+void HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *> Categories,
+ SubCommand &Sub = SubCommand::getTopLevel());
+
+/// Reset all command line options to a state that looks as if they have
+/// never appeared on the command line. This is useful for being able to parse
+/// a command line multiple times (especially useful for writing tests).
+void ResetAllOptionOccurrences();
+
+/// Reset the command line parser back to its initial state. This
+/// removes
+/// all options, categories, and subcommands and returns the parser to a state
+/// where no options are supported.
+void ResetCommandLineParser();
+
+/// Parses `Arg` into the option handler `Handler`.
+bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i);
+
+} // end namespace cl
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_COMMANDLINE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Compiler.h b/contrib/libs/llvm16/include/llvm/Support/Compiler.h
new file mode 100644
index 00000000000..ccae94b064f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Compiler.h
@@ -0,0 +1,565 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- 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 defines several macros, based on the current compiler. This allows
+// use of compiler-specific features in a way that remains portable. This header
+// can be included from either C or C++.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_COMPILER_H
+#define LLVM_SUPPORT_COMPILER_H
+
+#include "llvm/Config/llvm-config.h"
+
+#include <stddef.h>
+
+#if defined(_MSC_VER)
+#include <sal.h>
+#endif
+
+#ifndef __has_feature
+# define __has_feature(x) 0
+#endif
+
+#ifndef __has_extension
+# define __has_extension(x) 0
+#endif
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+#ifndef __has_include
+# define __has_include(x) 0
+#endif
+
+// Only use __has_cpp_attribute in C++ mode. GCC defines __has_cpp_attribute in
+// C mode, but the :: in __has_cpp_attribute(scoped::attribute) is invalid.
+#ifndef LLVM_HAS_CPP_ATTRIBUTE
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+# define LLVM_HAS_CPP_ATTRIBUTE(x) 0
+#endif
+#endif
+
+/// \macro LLVM_GNUC_PREREQ
+/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
+/// available.
+#ifndef LLVM_GNUC_PREREQ
+# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+# define LLVM_GNUC_PREREQ(maj, min, patch) \
+ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
+ ((maj) << 20) + ((min) << 10) + (patch))
+# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define LLVM_GNUC_PREREQ(maj, min, patch) \
+ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
+# else
+# define LLVM_GNUC_PREREQ(maj, min, patch) 0
+# endif
+#endif
+
+/// \macro LLVM_MSC_PREREQ
+/// Is the compiler MSVC of at least the specified version?
+/// The common \param version values to check for are:
+/// * 1910: VS2017, version 15.1 & 15.2
+/// * 1911: VS2017, version 15.3 & 15.4
+/// * 1912: VS2017, version 15.5
+/// * 1913: VS2017, version 15.6
+/// * 1914: VS2017, version 15.7
+/// * 1915: VS2017, version 15.8
+/// * 1916: VS2017, version 15.9
+/// * 1920: VS2019, version 16.0
+/// * 1921: VS2019, version 16.1
+/// * 1922: VS2019, version 16.2
+/// * 1923: VS2019, version 16.3
+/// * 1924: VS2019, version 16.4
+/// * 1925: VS2019, version 16.5
+/// * 1926: VS2019, version 16.6
+/// * 1927: VS2019, version 16.7
+/// * 1928: VS2019, version 16.8 + 16.9
+/// * 1929: VS2019, version 16.10 + 16.11
+/// * 1930: VS2022, version 17.0
+#ifdef _MSC_VER
+#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
+
+// We require at least VS 2019.
+#if !defined(LLVM_FORCE_USE_OLD_TOOLCHAIN)
+#if !LLVM_MSC_PREREQ(1920)
+#error LLVM requires at least VS 2019.
+#endif
+#endif
+
+#else
+#define LLVM_MSC_PREREQ(version) 0
+#endif
+
+/// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked
+/// into a shared library, then the class should be private to the library and
+/// not accessible from outside it. Can also be used to mark variables and
+/// functions, making them private to any shared library they are linked into.
+/// On PE/COFF targets, library visibility is the default, so this isn't needed.
+///
+/// LLVM_EXTERNAL_VISIBILITY - classes, functions, and variables marked with
+/// this attribute will be made public and visible outside of any shared library
+/// they are linked in to.
+#if __has_attribute(visibility) && \
+ (!(defined(_WIN32) || defined(__CYGWIN__)) || \
+ (defined(__MINGW32__) && defined(__clang__)))
+#define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden")))
+#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
+#define LLVM_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
+#else
+#define LLVM_EXTERNAL_VISIBILITY
+#endif
+#else
+#define LLVM_LIBRARY_VISIBILITY
+#define LLVM_EXTERNAL_VISIBILITY
+#endif
+
+#if defined(__GNUC__)
+#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
+#else
+#define LLVM_PREFETCH(addr, rw, locality)
+#endif
+
+#if __has_attribute(used)
+#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
+#else
+#define LLVM_ATTRIBUTE_USED
+#endif
+
+#if defined(__clang__)
+#define LLVM_DEPRECATED(MSG, FIX) __attribute__((deprecated(MSG, FIX)))
+#else
+#define LLVM_DEPRECATED(MSG, FIX) [[deprecated(MSG)]]
+#endif
+
+// Indicate that a non-static, non-const C++ member function reinitializes
+// the entire object to a known state, independent of the previous state of
+// the object.
+//
+// The clang-tidy check bugprone-use-after-move recognizes this attribute as a
+// marker that a moved-from object has left the indeterminate state and can be
+// reused.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes)
+#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#else
+#define LLVM_ATTRIBUTE_REINITIALIZES
+#endif
+
+// Some compilers warn about unused functions. When a function is sometimes
+// used or not depending on build settings (e.g. a function only called from
+// within "assert"), this attribute can be used to suppress such warnings.
+//
+// However, it shouldn't be used for unused *variables*, as those have a much
+// more portable solution:
+// (void)unused_var_name;
+// Prefer cast-to-void wherever it is sufficient.
+#if __has_attribute(unused)
+#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
+#else
+#define LLVM_ATTRIBUTE_UNUSED
+#endif
+
+// FIXME: Provide this for PE/COFF targets.
+#if __has_attribute(weak) && !defined(__MINGW32__) && !defined(__CYGWIN__) && \
+ !defined(_WIN32)
+#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__))
+#else
+#define LLVM_ATTRIBUTE_WEAK
+#endif
+
+// Prior to clang 3.2, clang did not accept any spelling of
+// __has_attribute(const), so assume it is supported.
+#if defined(__clang__) || defined(__GNUC__)
+// aka 'CONST' but following LLVM Conventions.
+#define LLVM_READNONE __attribute__((__const__))
+#else
+#define LLVM_READNONE
+#endif
+
+#if __has_attribute(pure) || defined(__GNUC__)
+// aka 'PURE' but following LLVM Conventions.
+#define LLVM_READONLY __attribute__((__pure__))
+#else
+#define LLVM_READONLY
+#endif
+
+#if __has_attribute(minsize)
+#define LLVM_ATTRIBUTE_MINSIZE __attribute__((minsize))
+#else
+#define LLVM_ATTRIBUTE_MINSIZE
+#endif
+
+#if __has_builtin(__builtin_expect) || defined(__GNUC__)
+#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
+#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
+#else
+#define LLVM_LIKELY(EXPR) (EXPR)
+#define LLVM_UNLIKELY(EXPR) (EXPR)
+#endif
+
+/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
+/// mark a method "not for inlining".
+#if __has_attribute(noinline)
+#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
+#else
+#define LLVM_ATTRIBUTE_NOINLINE
+#endif
+
+/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
+/// so, mark a method "always inline" because it is performance sensitive.
+#if __has_attribute(always_inline)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
+#else
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
+#endif
+
+/// LLVM_ATTRIBUTE_NO_DEBUG - On compilers where we have a directive to do
+/// so, mark a method "no debug" because debug info makes the debugger
+/// experience worse.
+#if __has_attribute(nodebug)
+#define LLVM_ATTRIBUTE_NODEBUG __attribute__((nodebug))
+#else
+#define LLVM_ATTRIBUTE_NODEBUG
+#endif
+
+#if __has_attribute(returns_nonnull)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL
+#endif
+
+/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
+/// pointer that does not alias any other valid pointer.
+#ifdef __GNUC__
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
+#endif
+
+/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
+#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
+#define LLVM_FALLTHROUGH [[fallthrough]]
+#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
+#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
+#elif __has_attribute(fallthrough)
+#define LLVM_FALLTHROUGH __attribute__((fallthrough))
+#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough)
+#define LLVM_FALLTHROUGH [[clang::fallthrough]]
+#else
+#define LLVM_FALLTHROUGH
+#endif
+
+/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
+/// they are constant initialized.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \
+ [[clang::require_constant_initialization]]
+#else
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION
+#endif
+
+/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable
+/// lifetime warnings.
+#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner)
+#define LLVM_GSL_OWNER [[gsl::Owner]]
+#else
+#define LLVM_GSL_OWNER
+#endif
+
+/// LLVM_GSL_POINTER - Apply this to non-owning classes like
+/// StringRef to enable lifetime warnings.
+#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer)
+#define LLVM_GSL_POINTER [[gsl::Pointer]]
+#else
+#define LLVM_GSL_POINTER
+#endif
+
+/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
+/// pedantic diagnostics.
+#ifdef __GNUC__
+#define LLVM_EXTENSION __extension__
+#else
+#define LLVM_EXTENSION
+#endif
+
+/// LLVM_BUILTIN_UNREACHABLE - On compilers which support it, expands
+/// to an expression which states that it is undefined behavior for the
+/// compiler to reach this point. Otherwise is not defined.
+///
+/// '#else' is intentionally left out so that other macro logic (e.g.,
+/// LLVM_ASSUME_ALIGNED and llvm_unreachable()) can detect whether
+/// LLVM_BUILTIN_UNREACHABLE has a definition.
+#if __has_builtin(__builtin_unreachable) || defined(__GNUC__)
+# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
+#elif defined(_MSC_VER)
+# define LLVM_BUILTIN_UNREACHABLE __assume(false)
+#endif
+
+/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
+/// which causes the program to exit abnormally.
+#if __has_builtin(__builtin_trap) || defined(__GNUC__)
+# define LLVM_BUILTIN_TRAP __builtin_trap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC, does not require forward
+// declarations involving platform-specific typedefs (unlike RaiseException),
+// results in a call to vectored exception handlers, and encodes to a short
+// instruction that still causes the trapping behavior we want.
+# define LLVM_BUILTIN_TRAP __debugbreak()
+#else
+# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
+#endif
+
+/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
+/// an expression which causes the program to break while running
+/// under a debugger.
+#if __has_builtin(__builtin_debugtrap)
+# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC and breaks while
+// running under the debugger, and also supports invoking a debugger
+// when the OS is configured appropriately.
+# define LLVM_BUILTIN_DEBUGTRAP __debugbreak()
+#else
+// Just continue execution when built with compilers that have no
+// support. This is a debugging aid and not intended to force the
+// program to abort if encountered.
+# define LLVM_BUILTIN_DEBUGTRAP
+#endif
+
+/// \macro LLVM_ASSUME_ALIGNED
+/// Returns a pointer with an assumed alignment.
+#if __has_builtin(__builtin_assume_aligned) || defined(__GNUC__)
+# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
+#elif defined(LLVM_BUILTIN_UNREACHABLE)
+# define LLVM_ASSUME_ALIGNED(p, a) \
+ (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
+#else
+# define LLVM_ASSUME_ALIGNED(p, a) (p)
+#endif
+
+/// \macro LLVM_PACKED
+/// Used to specify a packed structure.
+/// LLVM_PACKED(
+/// struct A {
+/// int i;
+/// int j;
+/// int k;
+/// long long l;
+/// });
+///
+/// LLVM_PACKED_START
+/// struct B {
+/// int i;
+/// int j;
+/// int k;
+/// long long l;
+/// };
+/// LLVM_PACKED_END
+#ifdef _MSC_VER
+# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
+# define LLVM_PACKED_START __pragma(pack(push, 1))
+# define LLVM_PACKED_END __pragma(pack(pop))
+#else
+# define LLVM_PACKED(d) d __attribute__((packed))
+# define LLVM_PACKED_START _Pragma("pack(push, 1)")
+# define LLVM_PACKED_END _Pragma("pack(pop)")
+#endif
+
+/// \macro LLVM_MEMORY_SANITIZER_BUILD
+/// Whether LLVM itself is built with MemorySanitizer instrumentation.
+#if __has_feature(memory_sanitizer)
+# define LLVM_MEMORY_SANITIZER_BUILD 1
+# include <sanitizer/msan_interface.h>
+# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory))
+#else
+# define LLVM_MEMORY_SANITIZER_BUILD 0
+# define __msan_allocated_memory(p, size)
+# define __msan_unpoison(p, size)
+# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
+#endif
+
+/// \macro LLVM_ADDRESS_SANITIZER_BUILD
+/// Whether LLVM itself is built with AddressSanitizer instrumentation.
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define LLVM_ADDRESS_SANITIZER_BUILD 1
+#if __has_include(<sanitizer/asan_interface.h>)
+# include <sanitizer/asan_interface.h>
+#else
+// These declarations exist to support ASan with MSVC. If MSVC eventually ships
+// asan_interface.h in their headers, then we can remove this.
+#ifdef __cplusplus
+extern "C" {
+#endif
+void __asan_poison_memory_region(void const volatile *addr, size_t size);
+void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#endif
+#else
+# define LLVM_ADDRESS_SANITIZER_BUILD 0
+# define __asan_poison_memory_region(p, size)
+# define __asan_unpoison_memory_region(p, size)
+#endif
+
+/// \macro LLVM_HWADDRESS_SANITIZER_BUILD
+/// Whether LLVM itself is built with HWAddressSanitizer instrumentation.
+#if __has_feature(hwaddress_sanitizer)
+#define LLVM_HWADDRESS_SANITIZER_BUILD 1
+#else
+#define LLVM_HWADDRESS_SANITIZER_BUILD 0
+#endif
+
+/// \macro LLVM_THREAD_SANITIZER_BUILD
+/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
+#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
+# define LLVM_THREAD_SANITIZER_BUILD 1
+#else
+# define LLVM_THREAD_SANITIZER_BUILD 0
+#endif
+
+#if LLVM_THREAD_SANITIZER_BUILD
+// Thread Sanitizer is a tool that finds races in code.
+// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
+// tsan detects these exact functions by name.
+#ifdef __cplusplus
+extern "C" {
+#endif
+void AnnotateHappensAfter(const char *file, int line, const volatile void *cv);
+void AnnotateHappensBefore(const char *file, int line, const volatile void *cv);
+void AnnotateIgnoreWritesBegin(const char *file, int line);
+void AnnotateIgnoreWritesEnd(const char *file, int line);
+#ifdef __cplusplus
+}
+#endif
+
+// This marker is used to define a happens-before arc. The race detector will
+// infer an arc from the begin to the end when they share the same pointer
+// argument.
+# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
+
+// This marker defines the destination of a happens-before arc.
+# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
+
+// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
+# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+// Resume checking for racy writes.
+# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+#else
+# define TsanHappensBefore(cv)
+# define TsanHappensAfter(cv)
+# define TsanIgnoreWritesBegin()
+# define TsanIgnoreWritesEnd()
+#endif
+
+/// \macro LLVM_NO_SANITIZE
+/// Disable a particular sanitizer for a function.
+#if __has_attribute(no_sanitize)
+#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
+#else
+#define LLVM_NO_SANITIZE(KIND)
+#endif
+
+/// Mark debug helper function definitions like dump() that should not be
+/// stripped from debug builds.
+/// Note that you should also surround dump() functions with
+/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
+/// get stripped in release builds.
+// FIXME: Move this to a private config.h as it's not usable in public headers.
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
+#else
+#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
+#endif
+
+/// \macro LLVM_PRETTY_FUNCTION
+/// Gets a user-friendly looking function signature for the current scope
+/// using the best available method on each platform. The exact format of the
+/// resulting string is implementation specific and non-portable, so this should
+/// only be used, for example, for logging or diagnostics.
+#if defined(_MSC_VER)
+#define LLVM_PRETTY_FUNCTION __FUNCSIG__
+#elif defined(__GNUC__) || defined(__clang__)
+#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#define LLVM_PRETTY_FUNCTION __func__
+#endif
+
+/// \macro LLVM_THREAD_LOCAL
+/// A thread-local storage specifier which can be used with globals,
+/// extern globals, and static globals.
+///
+/// This is essentially an extremely restricted analog to C++11's thread_local
+/// support. It uses thread_local if available, falling back on gcc __thread
+/// if not. __thread doesn't support many of the C++11 thread_local's
+/// features. You should only use this for PODs that you can statically
+/// initialize to some constant value. In almost all circumstances this is most
+/// appropriate for use with a pointer, integer, or small aggregation of
+/// pointers and integers.
+#if LLVM_ENABLE_THREADS
+#if __has_feature(cxx_thread_local) || defined(_MSC_VER)
+#define LLVM_THREAD_LOCAL thread_local
+#else
+// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
+// we only need the restricted functionality that provides.
+#define LLVM_THREAD_LOCAL __thread
+#endif
+#else // !LLVM_ENABLE_THREADS
+// If threading is disabled entirely, this compiles to nothing and you get
+// a normal global variable.
+#define LLVM_THREAD_LOCAL
+#endif
+
+/// \macro LLVM_ENABLE_EXCEPTIONS
+/// Whether LLVM is built with exception support.
+#if __has_feature(cxx_exceptions)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#elif defined(__GNUC__) && defined(__EXCEPTIONS)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#elif defined(_MSC_VER) && defined(_CPPUNWIND)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#endif
+
+/// \macro LLVM_NO_PROFILE_INSTRUMENT_FUNCTION
+/// Disable the profile instrument for a function.
+#if __has_attribute(no_profile_instrument_function)
+#define LLVM_NO_PROFILE_INSTRUMENT_FUNCTION \
+ __attribute__((no_profile_instrument_function))
+#else
+#define LLVM_NO_PROFILE_INSTRUMENT_FUNCTION
+#endif
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Compression.h b/contrib/libs/llvm16/include/llvm/Support/Compression.h
new file mode 100644
index 00000000000..e4c677ab988
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Compression.h
@@ -0,0 +1,139 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/Compression.h ---Compression----------------*- 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 basic functions for compression/decompression.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_COMPRESSION_H
+#define LLVM_SUPPORT_COMPRESSION_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/DataTypes.h"
+
+namespace llvm {
+template <typename T> class SmallVectorImpl;
+class Error;
+
+// None indicates no compression. The other members are a subset of
+// compression::Format, which is used for compressed debug sections in some
+// object file formats (e.g. ELF). This is a separate class as we may add new
+// compression::Format members for non-debugging purposes.
+enum class DebugCompressionType {
+ None, ///< No compression
+ Zlib, ///< zlib
+ Zstd, ///< Zstandard
+};
+
+namespace compression {
+namespace zlib {
+
+constexpr int NoCompression = 0;
+constexpr int BestSpeedCompression = 1;
+constexpr int DefaultCompression = 6;
+constexpr int BestSizeCompression = 9;
+
+bool isAvailable();
+
+void compress(ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &CompressedBuffer,
+ int Level = DefaultCompression);
+
+Error decompress(ArrayRef<uint8_t> Input, uint8_t *Output,
+ size_t &UncompressedSize);
+
+Error decompress(ArrayRef<uint8_t> Input, SmallVectorImpl<uint8_t> &Output,
+ size_t UncompressedSize);
+
+} // End of namespace zlib
+
+namespace zstd {
+
+constexpr int NoCompression = -5;
+constexpr int BestSpeedCompression = 1;
+constexpr int DefaultCompression = 5;
+constexpr int BestSizeCompression = 12;
+
+bool isAvailable();
+
+void compress(ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &CompressedBuffer,
+ int Level = DefaultCompression);
+
+Error decompress(ArrayRef<uint8_t> Input, uint8_t *Output,
+ size_t &UncompressedSize);
+
+Error decompress(ArrayRef<uint8_t> Input, SmallVectorImpl<uint8_t> &Output,
+ size_t UncompressedSize);
+
+} // End of namespace zstd
+
+enum class Format {
+ Zlib,
+ Zstd,
+};
+
+inline Format formatFor(DebugCompressionType Type) {
+ switch (Type) {
+ case DebugCompressionType::None:
+ llvm_unreachable("not a compression type");
+ case DebugCompressionType::Zlib:
+ return Format::Zlib;
+ case DebugCompressionType::Zstd:
+ return Format::Zstd;
+ }
+ llvm_unreachable("");
+}
+
+struct Params {
+ constexpr Params(Format F)
+ : format(F), level(F == Format::Zlib ? zlib::DefaultCompression
+ : zstd::DefaultCompression) {}
+ Params(DebugCompressionType Type) : Params(formatFor(Type)) {}
+
+ Format format;
+ int level;
+ // This may support multi-threading for zstd in the future. Note that
+ // different threads may produce different output, so be careful if certain
+ // output determinism is desired.
+};
+
+// Return nullptr if LLVM was built with support (LLVM_ENABLE_ZLIB,
+// LLVM_ENABLE_ZSTD) for the specified compression format; otherwise
+// return a string literal describing the reason.
+const char *getReasonIfUnsupported(Format F);
+
+// Compress Input with the specified format P.Format. If Level is -1, use
+// *::DefaultCompression for the format.
+void compress(Params P, ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &Output);
+
+// Decompress Input. The uncompressed size must be available.
+Error decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,
+ uint8_t *Output, size_t UncompressedSize);
+Error decompress(Format F, ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &Output, size_t UncompressedSize);
+Error decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,
+ SmallVectorImpl<uint8_t> &Output, size_t UncompressedSize);
+
+} // End of namespace compression
+
+} // End of namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ConvertUTF.h b/contrib/libs/llvm16/include/llvm/Support/ConvertUTF.h
new file mode 100644
index 00000000000..d67aa50ed4d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ConvertUTF.h
@@ -0,0 +1,359 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
+ *
+ * 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
+ *
+ *==------------------------------------------------------------------------==*/
+/*
+ * Copyright © 1991-2015 Unicode, Inc. All rights reserved.
+ * Distributed under the Terms of Use in
+ * http://www.unicode.org/copyright.html.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of the Unicode data files and any associated documentation
+ * (the "Data Files") or Unicode software and any associated documentation
+ * (the "Software") to deal in the Data Files or Software
+ * without restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, and/or sell copies of
+ * the Data Files or Software, and to permit persons to whom the Data Files
+ * or Software are furnished to do so, provided that
+ * (a) this copyright and permission notice appear with all copies
+ * of the Data Files or Software,
+ * (b) this copyright and permission notice appear in associated
+ * documentation, and
+ * (c) there is clear notice in each modified Data File or in the Software
+ * as well as in the documentation associated with the Data File(s) or
+ * Software that the data or software has been modified.
+ *
+ * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+ * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+ * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder
+ * shall not be used in advertising or otherwise to promote the sale,
+ * use or other dealings in these Data Files or Software without prior
+ * written authorization of the copyright holder.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Header file.
+
+ Several funtions are included here, forming a complete set of
+ conversions between the three formats. UTF-7 is not included
+ here, but is handled in a separate source file.
+
+ Each of these routines takes pointers to input buffers and output
+ buffers. The input buffers are const.
+
+ Each routine converts the text between *sourceStart and sourceEnd,
+ putting the result into the buffer between *targetStart and
+ targetEnd. Note: the end pointers are *after* the last item: e.g.
+ *(sourceEnd - 1) is the last item.
+
+ The return result indicates whether the conversion was successful,
+ and if not, whether the problem was in the source or target buffers.
+ (Only the first encountered problem is indicated.)
+
+ After the conversion, *sourceStart and *targetStart are both
+ updated to point to the end of last text successfully converted in
+ the respective buffers.
+
+ Input parameters:
+ sourceStart - pointer to a pointer to the source buffer.
+ The contents of this are modified on return so that
+ it points at the next thing to be converted.
+ targetStart - similarly, pointer to pointer to the target buffer.
+ sourceEnd, targetEnd - respectively pointers to the ends of the
+ two buffers, for overflow checking only.
+
+ These conversion functions take a ConversionFlags argument. When this
+ flag is set to strict, both irregular sequences and isolated surrogates
+ will cause an error. When the flag is set to lenient, both irregular
+ sequences and isolated surrogates are converted.
+
+ Whether the flag is strict or lenient, all illegal sequences will cause
+ an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+ or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+ must check for illegal sequences.
+
+ When the flag is set to lenient, characters over 0x10FFFF are converted
+ to the replacement character; otherwise (when the flag is set to strict)
+ they constitute an error.
+
+ Output parameters:
+ The value "sourceIllegal" is returned from some routines if the input
+ sequence is malformed. When "sourceIllegal" is returned, the source
+ value will point to the illegal value that caused the problem. E.g.,
+ in UTF-8 when a sequence is malformed, it points to the start of the
+ malformed sequence.
+
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+#ifndef LLVM_SUPPORT_CONVERTUTF_H
+#define LLVM_SUPPORT_CONVERTUTF_H
+
+#include <cstddef>
+#include <string>
+
+#if defined(_WIN32)
+#include <system_error>
+#endif
+
+// Wrap everything in namespace llvm so that programs can link with llvm and
+// their own version of the unicode libraries.
+
+namespace llvm {
+
+/* ---------------------------------------------------------------------
+ The following 4 definitions are compiler-specific.
+ The C standard does not guarantee that wchar_t has at least
+ 16 bits, so wchar_t is no less portable than unsigned short!
+ All should be unsigned values to avoid sign extension during
+ bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef unsigned int UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8; /* typically 8 bits */
+typedef unsigned char Boolean; /* 0 or 1 */
+
+/* Some fundamental constants */
+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
+#define UNI_MAX_BMP (UTF32)0x0000FFFF
+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
+
+#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4
+
+#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE 0xFEFF
+#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE
+
+#define UNI_UTF32_BYTE_ORDER_MARK_NATIVE 0x0000FEFF
+#define UNI_UTF32_BYTE_ORDER_MARK_SWAPPED 0xFFFE0000
+
+typedef enum {
+ conversionOK, /* conversion successful */
+ sourceExhausted, /* partial character in source, but hit end */
+ targetExhausted, /* insuff. room in target for conversion */
+ sourceIllegal /* source sequence is illegal/malformed */
+} ConversionResult;
+
+typedef enum {
+ strictConversion = 0,
+ lenientConversion
+} ConversionFlags;
+
+ConversionResult ConvertUTF8toUTF16 (
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+/**
+ * Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
+ * incomplete code unit sequence, returns \c sourceExhausted.
+ */
+ConversionResult ConvertUTF8toUTF32Partial(
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+/**
+ * Convert a partial UTF8 sequence to UTF32. If the sequence ends in an
+ * incomplete code unit sequence, returns \c sourceIllegal.
+ */
+ConversionResult ConvertUTF8toUTF32(
+ const UTF8** sourceStart, const UTF8* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF8 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF8 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF16toUTF32 (
+ const UTF16** sourceStart, const UTF16* sourceEnd,
+ UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
+
+ConversionResult ConvertUTF32toUTF16 (
+ const UTF32** sourceStart, const UTF32* sourceEnd,
+ UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
+
+Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+
+Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd);
+
+unsigned getUTF8SequenceSize(const UTF8 *source, const UTF8 *sourceEnd);
+
+unsigned getNumBytesForUTF8(UTF8 firstByte);
+
+/*************************************************************************/
+/* Below are LLVM-specific wrappers of the functions above. */
+
+template <typename T> class ArrayRef;
+template <typename T> class SmallVectorImpl;
+class StringRef;
+
+/**
+ * Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on
+ * WideCharWidth. The converted data is written to ResultPtr, which needs to
+ * point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
+ * ResultPtr will point one after the end of the copied string. On failure,
+ * ResultPtr will not be changed, and ErrorPtr will be set to the location of
+ * the first character which could not be converted.
+ * \return true on success.
+ */
+bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source,
+ char *&ResultPtr, const UTF8 *&ErrorPtr);
+
+/**
+* Converts a UTF-8 StringRef to a std::wstring.
+* \return true on success.
+*/
+bool ConvertUTF8toWide(llvm::StringRef Source, std::wstring &Result);
+
+/**
+* Converts a UTF-8 C-string to a std::wstring.
+* \return true on success.
+*/
+bool ConvertUTF8toWide(const char *Source, std::wstring &Result);
+
+/**
+* Converts a std::wstring to a UTF-8 encoded std::string.
+* \return true on success.
+*/
+bool convertWideToUTF8(const std::wstring &Source, std::string &Result);
+
+
+/**
+ * Convert an Unicode code point to UTF8 sequence.
+ *
+ * \param Source a Unicode code point.
+ * \param [in,out] ResultPtr pointer to the output buffer, needs to be at least
+ * \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes. On success \c ResultPtr is
+ * updated one past end of the converted sequence.
+ *
+ * \returns true on success.
+ */
+bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr);
+
+/**
+ * Convert the first UTF8 sequence in the given source buffer to a UTF32
+ * code point.
+ *
+ * \param [in,out] source A pointer to the source buffer. If the conversion
+ * succeeds, this pointer will be updated to point to the byte just past the
+ * end of the converted sequence.
+ * \param sourceEnd A pointer just past the end of the source buffer.
+ * \param [out] target The converted code
+ * \param flags Whether the conversion is strict or lenient.
+ *
+ * \returns conversionOK on success
+ *
+ * \sa ConvertUTF8toUTF32
+ */
+inline ConversionResult convertUTF8Sequence(const UTF8 **source,
+ const UTF8 *sourceEnd,
+ UTF32 *target,
+ ConversionFlags flags) {
+ if (*source == sourceEnd)
+ return sourceExhausted;
+ unsigned size = getNumBytesForUTF8(**source);
+ if ((ptrdiff_t)size > sourceEnd - *source)
+ return sourceExhausted;
+ return ConvertUTF8toUTF32(source, *source + size, &target, target + 1, flags);
+}
+
+/**
+ * Returns true if a blob of text starts with a UTF-16 big or little endian byte
+ * order mark.
+ */
+bool hasUTF16ByteOrderMark(ArrayRef<char> SrcBytes);
+
+/**
+ * Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
+ *
+ * \param [in] SrcBytes A buffer of what is assumed to be UTF-16 encoded text.
+ * \param [out] Out Converted UTF-8 is stored here on success.
+ * \returns true on success
+ */
+bool convertUTF16ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out);
+
+/**
+* Converts a UTF16 string into a UTF8 std::string.
+*
+* \param [in] Src A buffer of UTF-16 encoded text.
+* \param [out] Out Converted UTF-8 is stored here on success.
+* \returns true on success
+*/
+bool convertUTF16ToUTF8String(ArrayRef<UTF16> Src, std::string &Out);
+
+/**
+ * Converts a stream of raw bytes assumed to be UTF32 into a UTF8 std::string.
+ *
+ * \param [in] SrcBytes A buffer of what is assumed to be UTF-32 encoded text.
+ * \param [out] Out Converted UTF-8 is stored here on success.
+ * \returns true on success
+ */
+bool convertUTF32ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out);
+
+/**
+ * Converts a UTF32 string into a UTF8 std::string.
+ *
+ * \param [in] Src A buffer of UTF-32 encoded text.
+ * \param [out] Out Converted UTF-8 is stored here on success.
+ * \returns true on success
+ */
+bool convertUTF32ToUTF8String(ArrayRef<UTF32> Src, std::string &Out);
+
+/**
+ * Converts a UTF-8 string into a UTF-16 string with native endianness.
+ *
+ * \returns true on success
+ */
+bool convertUTF8ToUTF16String(StringRef SrcUTF8,
+ SmallVectorImpl<UTF16> &DstUTF16);
+
+#if defined(_WIN32)
+namespace sys {
+namespace windows {
+std::error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
+/// Convert to UTF16 from the current code page used in the system
+std::error_code CurCPToUTF16(StringRef utf8, SmallVectorImpl<wchar_t> &utf16);
+std::error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len,
+ SmallVectorImpl<char> &utf8);
+/// Convert from UTF16 to the current code page used in the system
+std::error_code UTF16ToCurCP(const wchar_t *utf16, size_t utf16_len,
+ SmallVectorImpl<char> &utf8);
+} // namespace windows
+} // namespace sys
+#endif
+
+} /* end namespace llvm */
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/CrashRecoveryContext.h b/contrib/libs/llvm16/include/llvm/Support/CrashRecoveryContext.h
new file mode 100644
index 00000000000..80c1d1d96ee
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/CrashRecoveryContext.h
@@ -0,0 +1,283 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- CrashRecoveryContext.h - Crash Recovery ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
+#define LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
+
+#include "llvm/ADT/STLFunctionalExtras.h"
+
+namespace llvm {
+class CrashRecoveryContextCleanup;
+
+/// Crash recovery helper object.
+///
+/// This class implements support for running operations in a safe context so
+/// that crashes (memory errors, stack overflow, assertion violations) can be
+/// detected and control restored to the crashing thread. Crash detection is
+/// purely "best effort", the exact set of failures which can be recovered from
+/// is platform dependent.
+///
+/// Clients make use of this code by first calling
+/// CrashRecoveryContext::Enable(), and then executing unsafe operations via a
+/// CrashRecoveryContext object. For example:
+///
+/// \code
+/// void actual_work(void *);
+///
+/// void foo() {
+/// CrashRecoveryContext CRC;
+///
+/// if (!CRC.RunSafely(actual_work, 0)) {
+/// ... a crash was detected, report error to user ...
+/// }
+///
+/// ... no crash was detected ...
+/// }
+/// \endcode
+///
+/// To assist recovery the class allows specifying set of actions that will be
+/// executed in any case, whether crash occurs or not. These actions may be used
+/// to reclaim resources in the case of crash.
+class CrashRecoveryContext {
+ void *Impl = nullptr;
+ CrashRecoveryContextCleanup *head = nullptr;
+
+public:
+ CrashRecoveryContext();
+ ~CrashRecoveryContext();
+
+ /// Register cleanup handler, which is used when the recovery context is
+ /// finished.
+ /// The recovery context owns the handler.
+ void registerCleanup(CrashRecoveryContextCleanup *cleanup);
+
+ void unregisterCleanup(CrashRecoveryContextCleanup *cleanup);
+
+ /// Enable crash recovery.
+ static void Enable();
+
+ /// Disable crash recovery.
+ static void Disable();
+
+ /// Return the active context, if the code is currently executing in a
+ /// thread which is in a protected context.
+ static CrashRecoveryContext *GetCurrent();
+
+ /// Return true if the current thread is recovering from a crash.
+ static bool isRecoveringFromCrash();
+
+ /// Execute the provided callback function (with the given arguments) in
+ /// a protected context.
+ ///
+ /// \return True if the function completed successfully, and false if the
+ /// function crashed (or HandleCrash was called explicitly). Clients should
+ /// make as little assumptions as possible about the program state when
+ /// RunSafely has returned false.
+ bool RunSafely(function_ref<void()> Fn);
+ bool RunSafely(void (*Fn)(void*), void *UserData) {
+ return RunSafely([&]() { Fn(UserData); });
+ }
+
+ /// Execute the provide callback function (with the given arguments) in
+ /// a protected context which is run in another thread (optionally with a
+ /// requested stack size).
+ ///
+ /// See RunSafely().
+ ///
+ /// On Darwin, if PRIO_DARWIN_BG is set on the calling thread, it will be
+ /// propagated to the new thread as well.
+ bool RunSafelyOnThread(function_ref<void()>, unsigned RequestedStackSize = 0);
+ bool RunSafelyOnThread(void (*Fn)(void*), void *UserData,
+ unsigned RequestedStackSize = 0) {
+ return RunSafelyOnThread([&]() { Fn(UserData); }, RequestedStackSize);
+ }
+
+ /// Explicitly trigger a crash recovery in the current process, and
+ /// return failure from RunSafely(). This function does not return.
+ [[noreturn]] void HandleExit(int RetCode);
+
+ /// Return true if RetCode indicates that a signal or an exception occurred.
+ static bool isCrash(int RetCode);
+
+ /// Throw again a signal or an exception, after it was catched once by a
+ /// CrashRecoveryContext.
+ static bool throwIfCrash(int RetCode);
+
+ /// In case of a crash, this is the crash identifier.
+ int RetCode = 0;
+
+ /// Selects whether handling of failures should be done in the same way as
+ /// for regular crashes. When this is active, a crash would print the
+ /// callstack, clean-up any temporary files and create a coredump/minidump.
+ bool DumpStackAndCleanupOnFailure = false;
+};
+
+/// Abstract base class of cleanup handlers.
+///
+/// Derived classes override method recoverResources, which makes actual work on
+/// resource recovery.
+///
+/// Cleanup handlers are stored in a double list, which is owned and managed by
+/// a crash recovery context.
+class CrashRecoveryContextCleanup {
+protected:
+ CrashRecoveryContext *context = nullptr;
+ CrashRecoveryContextCleanup(CrashRecoveryContext *context)
+ : context(context) {}
+
+public:
+ bool cleanupFired = false;
+
+ virtual ~CrashRecoveryContextCleanup();
+ virtual void recoverResources() = 0;
+
+ CrashRecoveryContext *getContext() const {
+ return context;
+ }
+
+private:
+ friend class CrashRecoveryContext;
+ CrashRecoveryContextCleanup *prev = nullptr, *next = nullptr;
+};
+
+/// Base class of cleanup handler that controls recovery of resources of the
+/// given type.
+///
+/// \tparam Derived Class that uses this class as a base.
+/// \tparam T Type of controlled resource.
+///
+/// This class serves as a base for its template parameter as implied by
+/// Curiously Recurring Template Pattern.
+///
+/// This class factors out creation of a cleanup handler. The latter requires
+/// knowledge of the current recovery context, which is provided by this class.
+template<typename Derived, typename T>
+class CrashRecoveryContextCleanupBase : public CrashRecoveryContextCleanup {
+protected:
+ T *resource;
+ CrashRecoveryContextCleanupBase(CrashRecoveryContext *context, T *resource)
+ : CrashRecoveryContextCleanup(context), resource(resource) {}
+
+public:
+ /// Creates cleanup handler.
+ /// \param x Pointer to the resource recovered by this handler.
+ /// \return New handler or null if the method was called outside a recovery
+ /// context.
+ static Derived *create(T *x) {
+ if (x) {
+ if (CrashRecoveryContext *context = CrashRecoveryContext::GetCurrent())
+ return new Derived(context, x);
+ }
+ return nullptr;
+ }
+};
+
+/// Cleanup handler that reclaims resource by calling destructor on it.
+template <typename T>
+class CrashRecoveryContextDestructorCleanup : public
+ CrashRecoveryContextCleanupBase<CrashRecoveryContextDestructorCleanup<T>, T> {
+public:
+ CrashRecoveryContextDestructorCleanup(CrashRecoveryContext *context,
+ T *resource)
+ : CrashRecoveryContextCleanupBase<
+ CrashRecoveryContextDestructorCleanup<T>, T>(context, resource) {}
+
+ void recoverResources() override {
+ this->resource->~T();
+ }
+};
+
+/// Cleanup handler that reclaims resource by calling 'delete' on it.
+template <typename T>
+class CrashRecoveryContextDeleteCleanup : public
+ CrashRecoveryContextCleanupBase<CrashRecoveryContextDeleteCleanup<T>, T> {
+public:
+ CrashRecoveryContextDeleteCleanup(CrashRecoveryContext *context, T *resource)
+ : CrashRecoveryContextCleanupBase<
+ CrashRecoveryContextDeleteCleanup<T>, T>(context, resource) {}
+
+ void recoverResources() override { delete this->resource; }
+};
+
+/// Cleanup handler that reclaims resource by calling its method 'Release'.
+template <typename T>
+class CrashRecoveryContextReleaseRefCleanup : public
+ CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>, T> {
+public:
+ CrashRecoveryContextReleaseRefCleanup(CrashRecoveryContext *context,
+ T *resource)
+ : CrashRecoveryContextCleanupBase<CrashRecoveryContextReleaseRefCleanup<T>,
+ T>(context, resource) {}
+
+ void recoverResources() override { this->resource->Release(); }
+};
+
+/// Helper class for managing resource cleanups.
+///
+/// \tparam T Type of resource been reclaimed.
+/// \tparam Cleanup Class that defines how the resource is reclaimed.
+///
+/// Clients create objects of this type in the code executed in a crash recovery
+/// context to ensure that the resource will be reclaimed even in the case of
+/// crash. For example:
+///
+/// \code
+/// void actual_work(void *) {
+/// ...
+/// std::unique_ptr<Resource> R(new Resource());
+/// CrashRecoveryContextCleanupRegistrar D(R.get());
+/// ...
+/// }
+///
+/// void foo() {
+/// CrashRecoveryContext CRC;
+///
+/// if (!CRC.RunSafely(actual_work, 0)) {
+/// ... a crash was detected, report error to user ...
+/// }
+/// \endcode
+///
+/// If the code of `actual_work` in the example above does not crash, the
+/// destructor of CrashRecoveryContextCleanupRegistrar removes cleanup code from
+/// the current CrashRecoveryContext and the resource is reclaimed by the
+/// destructor of std::unique_ptr. If crash happens, destructors are not called
+/// and the resource is reclaimed by cleanup object registered in the recovery
+/// context by the constructor of CrashRecoveryContextCleanupRegistrar.
+template <typename T, typename Cleanup = CrashRecoveryContextDeleteCleanup<T> >
+class CrashRecoveryContextCleanupRegistrar {
+ CrashRecoveryContextCleanup *cleanup;
+
+public:
+ CrashRecoveryContextCleanupRegistrar(T *x)
+ : cleanup(Cleanup::create(x)) {
+ if (cleanup)
+ cleanup->getContext()->registerCleanup(cleanup);
+ }
+
+ ~CrashRecoveryContextCleanupRegistrar() { unregister(); }
+
+ void unregister() {
+ if (cleanup && !cleanup->cleanupFired)
+ cleanup->getContext()->unregisterCleanup(cleanup);
+ cleanup = nullptr;
+ }
+};
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_CRASHRECOVERYCONTEXT_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/DJB.h b/contrib/libs/llvm16/include/llvm/Support/DJB.h
new file mode 100644
index 00000000000..ec0ad6214f3
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/DJB.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- 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 support for the DJ Bernstein hash function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DJB_H
+#define LLVM_SUPPORT_DJB_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+/// The Bernstein hash function used by the DWARF accelerator tables.
+inline uint32_t djbHash(StringRef Buffer, uint32_t H = 5381) {
+ for (unsigned char C : Buffer.bytes())
+ H = (H << 5) + H + C;
+ return H;
+}
+
+/// Computes the Bernstein hash after folding the input according to the Dwarf 5
+/// standard case folding rules.
+uint32_t caseFoldingDjbHash(StringRef Buffer, uint32_t H = 5381);
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_DJB_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/DOTGraphTraits.h b/contrib/libs/llvm16/include/llvm/Support/DOTGraphTraits.h
new file mode 100644
index 00000000000..f893fc9d2b1
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/DOTGraphTraits.h
@@ -0,0 +1,183 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/DOTGraphTraits.h - Customize .dot output ---*- 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 defines a template class that can be used to customize dot output
+// graphs generated by the GraphWriter.h file. The default implementation of
+// this file will produce a simple, but not very polished graph. By
+// specializing this template, lots of customization opportunities are possible.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DOTGRAPHTRAITS_H
+#define LLVM_SUPPORT_DOTGRAPHTRAITS_H
+
+#include <string>
+
+namespace llvm {
+
+/// DefaultDOTGraphTraits - This class provides the default implementations of
+/// all of the DOTGraphTraits methods. If a specialization does not need to
+/// override all methods here it should inherit so that it can get the default
+/// implementations.
+///
+struct DefaultDOTGraphTraits {
+private:
+ bool IsSimple;
+
+protected:
+ bool isSimple() {
+ return IsSimple;
+ }
+
+public:
+ explicit DefaultDOTGraphTraits(bool simple=false) : IsSimple (simple) {}
+
+ /// getGraphName - Return the label for the graph as a whole. Printed at the
+ /// top of the graph.
+ ///
+ template<typename GraphType>
+ static std::string getGraphName(const GraphType &) { return ""; }
+
+ /// getGraphProperties - Return any custom properties that should be included
+ /// in the top level graph structure for dot.
+ ///
+ template<typename GraphType>
+ static std::string getGraphProperties(const GraphType &) {
+ return "";
+ }
+
+ /// renderGraphFromBottomUp - If this function returns true, the graph is
+ /// emitted bottom-up instead of top-down. This requires graphviz 2.0 to work
+ /// though.
+ static bool renderGraphFromBottomUp() {
+ return false;
+ }
+
+ /// isNodeHidden - If the function returns true, the given node is not
+ /// displayed in the graph.
+ template <typename GraphType>
+ static bool isNodeHidden(const void *, const GraphType &) {
+ return false;
+ }
+
+ // renderNodesUsingHTML - If the function returns true, nodes will be
+ // rendered using HTML-like labels which allows colors, etc in the nodes
+ // and the edge source labels.
+ static bool renderNodesUsingHTML() { return false; }
+
+ /// getNodeLabel - Given a node and a pointer to the top level graph, return
+ /// the label to print in the node.
+ template<typename GraphType>
+ std::string getNodeLabel(const void *, const GraphType &) {
+ return "";
+ }
+
+ // getNodeIdentifierLabel - Returns a string representing the
+ // address or other unique identifier of the node. (Only used if
+ // non-empty.)
+ template <typename GraphType>
+ static std::string getNodeIdentifierLabel(const void *, const GraphType &) {
+ return "";
+ }
+
+ template<typename GraphType>
+ static std::string getNodeDescription(const void *, const GraphType &) {
+ return "";
+ }
+
+ /// If you want to specify custom node attributes, this is the place to do so
+ ///
+ template<typename GraphType>
+ static std::string getNodeAttributes(const void *,
+ const GraphType &) {
+ return "";
+ }
+
+ /// If you want to override the dot attributes printed for a particular edge,
+ /// override this method.
+ template<typename EdgeIter, typename GraphType>
+ static std::string getEdgeAttributes(const void *, EdgeIter,
+ const GraphType &) {
+ return "";
+ }
+
+ /// getEdgeSourceLabel - If you want to label the edge source itself,
+ /// implement this method.
+ template<typename EdgeIter>
+ static std::string getEdgeSourceLabel(const void *, EdgeIter) {
+ return "";
+ }
+
+ /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
+ /// should actually target another edge source, not a node. If this method is
+ /// implemented, getEdgeTarget should be implemented.
+ template<typename EdgeIter>
+ static bool edgeTargetsEdgeSource(const void *, EdgeIter) {
+ return false;
+ }
+
+ /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
+ /// called to determine which outgoing edge of Node is the target of this
+ /// edge.
+ template<typename EdgeIter>
+ static EdgeIter getEdgeTarget(const void *, EdgeIter I) {
+ return I;
+ }
+
+ /// hasEdgeDestLabels - If this function returns true, the graph is able
+ /// to provide labels for edge destinations.
+ static bool hasEdgeDestLabels() {
+ return false;
+ }
+
+ /// numEdgeDestLabels - If hasEdgeDestLabels, this function returns the
+ /// number of incoming edge labels the given node has.
+ static unsigned numEdgeDestLabels(const void *) {
+ return 0;
+ }
+
+ /// getEdgeDestLabel - If hasEdgeDestLabels, this function returns the
+ /// incoming edge label with the given index in the given node.
+ static std::string getEdgeDestLabel(const void *, unsigned) {
+ return "";
+ }
+
+ /// addCustomGraphFeatures - If a graph is made up of more than just
+ /// straight-forward nodes and edges, this is the place to put all of the
+ /// custom stuff necessary. The GraphWriter object, instantiated with your
+ /// GraphType is passed in as an argument. You may call arbitrary methods on
+ /// it to add things to the output graph.
+ ///
+ template<typename GraphType, typename GraphWriter>
+ static void addCustomGraphFeatures(const GraphType &, GraphWriter &) {}
+};
+
+
+/// DOTGraphTraits - Template class that can be specialized to customize how
+/// graphs are converted to 'dot' graphs. When specializing, you may inherit
+/// from DefaultDOTGraphTraits if you don't need to override everything.
+///
+template <typename Ty>
+struct DOTGraphTraits : public DefaultDOTGraphTraits {
+ DOTGraphTraits (bool simple=false) : DefaultDOTGraphTraits (simple) {}
+};
+
+} // End llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/DXILOperationCommon.h b/contrib/libs/llvm16/include/llvm/Support/DXILOperationCommon.h
new file mode 100644
index 00000000000..094124e2e2d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/DXILOperationCommon.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- DXILOperationCommon.h - DXIL Operation ------------------*- 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 is created to share common definitions used by both the
+// DXILOpBuilder and the table
+// generator.
+// Documentation for DXIL can be found in
+// https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DXILOPERATIONCOMMON_H
+#define LLVM_SUPPORT_DXILOPERATIONCOMMON_H
+
+#include "llvm/ADT/StringSwitch.h"
+
+namespace llvm {
+namespace dxil {
+
+enum class ParameterKind : uint8_t {
+ INVALID = 0,
+ VOID,
+ HALF,
+ FLOAT,
+ DOUBLE,
+ I1,
+ I8,
+ I16,
+ I32,
+ I64,
+ OVERLOAD,
+ CBUFFER_RET,
+ RESOURCE_RET,
+ DXIL_HANDLE,
+};
+
+inline ParameterKind parameterTypeNameToKind(StringRef Name) {
+ return StringSwitch<ParameterKind>(Name)
+ .Case("void", ParameterKind::VOID)
+ .Case("half", ParameterKind::HALF)
+ .Case("float", ParameterKind::FLOAT)
+ .Case("double", ParameterKind::DOUBLE)
+ .Case("i1", ParameterKind::I1)
+ .Case("i8", ParameterKind::I8)
+ .Case("i16", ParameterKind::I16)
+ .Case("i32", ParameterKind::I32)
+ .Case("i64", ParameterKind::I64)
+ .Case("$o", ParameterKind::OVERLOAD)
+ .Case("dx.types.Handle", ParameterKind::DXIL_HANDLE)
+ .Case("dx.types.CBufRet", ParameterKind::CBUFFER_RET)
+ .Case("dx.types.ResRet", ParameterKind::RESOURCE_RET)
+ .Default(ParameterKind::INVALID);
+}
+
+} // namespace dxil
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/DataExtractor.h b/contrib/libs/llvm16/include/llvm/Support/DataExtractor.h
new file mode 100644
index 00000000000..db88ce0be8f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/DataExtractor.h
@@ -0,0 +1,720 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- DataExtractor.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DATAEXTRACTOR_H
+#define LLVM_SUPPORT_DATAEXTRACTOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+/// An auxiliary type to facilitate extraction of 3-byte entities.
+struct Uint24 {
+ uint8_t Bytes[3];
+ Uint24(uint8_t U) {
+ Bytes[0] = Bytes[1] = Bytes[2] = U;
+ }
+ Uint24(uint8_t U0, uint8_t U1, uint8_t U2) {
+ Bytes[0] = U0; Bytes[1] = U1; Bytes[2] = U2;
+ }
+ uint32_t getAsUint32(bool IsLittleEndian) const {
+ int LoIx = IsLittleEndian ? 0 : 2;
+ return Bytes[LoIx] + (Bytes[1] << 8) + (Bytes[2-LoIx] << 16);
+ }
+};
+
+using uint24_t = Uint24;
+static_assert(sizeof(uint24_t) == 3, "sizeof(uint24_t) != 3");
+
+/// Needed by swapByteOrder().
+inline uint24_t getSwappedBytes(uint24_t C) {
+ return uint24_t(C.Bytes[2], C.Bytes[1], C.Bytes[0]);
+}
+
+class DataExtractor {
+ StringRef Data;
+ uint8_t IsLittleEndian;
+ uint8_t AddressSize;
+public:
+ /// A class representing a position in a DataExtractor, as well as any error
+ /// encountered during extraction. It enables one to extract a sequence of
+ /// values without error-checking and then checking for errors in bulk at the
+ /// end. The class holds an Error object, so failing to check the result of
+ /// the parse will result in a runtime error. The error flag is sticky and
+ /// will cause all subsequent extraction functions to fail without even
+ /// attempting to parse and without updating the Cursor offset. After clearing
+ /// the error flag, one can again use the Cursor object for parsing.
+ class Cursor {
+ uint64_t Offset;
+ Error Err;
+
+ friend class DataExtractor;
+
+ public:
+ /// Construct a cursor for extraction from the given offset.
+ explicit Cursor(uint64_t Offset) : Offset(Offset), Err(Error::success()) {}
+
+ /// Checks whether the cursor is valid (i.e. no errors were encountered). In
+ /// case of errors, this does not clear the error flag -- one must call
+ /// takeError() instead.
+ explicit operator bool() { return !Err; }
+
+ /// Return the current position of this Cursor. In the error state this is
+ /// the position of the Cursor before the first error was encountered.
+ uint64_t tell() const { return Offset; }
+
+ /// Set the cursor to the new offset. This does not impact the error state.
+ void seek(uint64_t NewOffSet) { Offset = NewOffSet; }
+
+ /// Return error contained inside this Cursor, if any. Clears the internal
+ /// Cursor state.
+ Error takeError() { return std::move(Err); }
+ };
+
+ /// Construct with a buffer that is owned by the caller.
+ ///
+ /// This constructor allows us to use data that is owned by the
+ /// caller. The data must stay around as long as this object is
+ /// valid.
+ DataExtractor(StringRef Data, bool IsLittleEndian, uint8_t AddressSize)
+ : Data(Data), IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {}
+ DataExtractor(ArrayRef<uint8_t> Data, bool IsLittleEndian,
+ uint8_t AddressSize)
+ : Data(StringRef(reinterpret_cast<const char *>(Data.data()),
+ Data.size())),
+ IsLittleEndian(IsLittleEndian), AddressSize(AddressSize) {}
+
+ /// Get the data pointed to by this extractor.
+ StringRef getData() const { return Data; }
+ /// Get the endianness for this extractor.
+ bool isLittleEndian() const { return IsLittleEndian; }
+ /// Get the address size for this extractor.
+ uint8_t getAddressSize() const { return AddressSize; }
+ /// Set the address size for this extractor.
+ void setAddressSize(uint8_t Size) { AddressSize = Size; }
+
+ /// Extract a C string from \a *offset_ptr.
+ ///
+ /// Returns a pointer to a C String from the data at the offset
+ /// pointed to by \a offset_ptr. A variable length NULL terminated C
+ /// string will be extracted and the \a offset_ptr will be
+ /// updated with the offset of the byte that follows the NULL
+ /// terminator byte.
+ ///
+ /// @param[in,out] OffsetPtr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// A pointer to the C string value in the data. If the offset
+ /// pointed to by \a offset_ptr is out of bounds, or if the
+ /// offset plus the length of the C string is out of bounds,
+ /// NULL will be returned.
+ const char *getCStr(uint64_t *OffsetPtr, Error *Err = nullptr) const {
+ return getCStrRef(OffsetPtr, Err).data();
+ }
+
+ /// Extract a C string from the location given by the cursor. In case of an
+ /// extraction error, or if the cursor is already in an error state, a
+ /// nullptr is returned.
+ const char *getCStr(Cursor &C) const { return getCStrRef(C).data(); }
+
+ /// Extract a C string from \a *offset_ptr.
+ ///
+ /// Returns a StringRef for the C String from the data at the offset
+ /// pointed to by \a offset_ptr. A variable length NULL terminated C
+ /// string will be extracted and the \a offset_ptr will be
+ /// updated with the offset of the byte that follows the NULL
+ /// terminator byte.
+ ///
+ /// \param[in,out] OffsetPtr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// \return
+ /// A StringRef for the C string value in the data. If the offset
+ /// pointed to by \a offset_ptr is out of bounds, or if the
+ /// offset plus the length of the C string is out of bounds,
+ /// a default-initialized StringRef will be returned.
+ StringRef getCStrRef(uint64_t *OffsetPtr, Error *Err = nullptr) const;
+
+ /// Extract a C string (as a StringRef) from the location given by the cursor.
+ /// In case of an extraction error, or if the cursor is already in an error
+ /// state, a default-initialized StringRef is returned.
+ StringRef getCStrRef(Cursor &C) const {
+ return getCStrRef(&C.Offset, &C.Err);
+ }
+
+ /// Extract a fixed length string from \a *OffsetPtr and consume \a Length
+ /// bytes.
+ ///
+ /// Returns a StringRef for the string from the data at the offset
+ /// pointed to by \a OffsetPtr. A fixed length C string will be extracted
+ /// and the \a OffsetPtr will be advanced by \a Length bytes.
+ ///
+ /// \param[in,out] OffsetPtr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// \param[in] Length
+ /// The length of the fixed length string to extract. If there are not
+ /// enough bytes in the data to extract the full string, the offset will
+ /// be left unmodified.
+ ///
+ /// \param[in] TrimChars
+ /// A set of characters to trim from the end of the string. Fixed length
+ /// strings are commonly either NULL terminated by one or more zero
+ /// bytes. Some clients have one or more spaces at the end of the string,
+ /// but a good default is to trim the NULL characters.
+ ///
+ /// \return
+ /// A StringRef for the C string value in the data. If the offset
+ /// pointed to by \a OffsetPtr is out of bounds, or if the
+ /// offset plus the length of the C string is out of bounds,
+ /// a default-initialized StringRef will be returned.
+ StringRef getFixedLengthString(uint64_t *OffsetPtr,
+ uint64_t Length, StringRef TrimChars = {"\0", 1}) const;
+
+ /// Extract a fixed number of bytes from the specified offset.
+ ///
+ /// Returns a StringRef for the bytes from the data at the offset
+ /// pointed to by \a OffsetPtr. A fixed length C string will be extracted
+ /// and the \a OffsetPtr will be advanced by \a Length bytes.
+ ///
+ /// \param[in,out] OffsetPtr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// \param[in] Length
+ /// The number of bytes to extract. If there are not enough bytes in the
+ /// data to extract all of the bytes, the offset will be left unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// \return
+ /// A StringRef for the extracted bytes. If the offset pointed to by
+ /// \a OffsetPtr is out of bounds, or if the offset plus the length
+ /// is out of bounds, a default-initialized StringRef will be returned.
+ StringRef getBytes(uint64_t *OffsetPtr, uint64_t Length,
+ Error *Err = nullptr) const;
+
+ /// Extract a fixed number of bytes from the location given by the cursor. In
+ /// case of an extraction error, or if the cursor is already in an error
+ /// state, a default-initialized StringRef is returned.
+ StringRef getBytes(Cursor &C, uint64_t Length) {
+ return getBytes(&C.Offset, Length, &C.Err);
+ }
+
+ /// Extract an unsigned integer of size \a byte_size from \a
+ /// *offset_ptr.
+ ///
+ /// Extract a single unsigned integer value and update the offset
+ /// pointed to by \a offset_ptr. The size of the extracted integer
+ /// is specified by the \a byte_size argument. \a byte_size should
+ /// have a value greater than or equal to one and less than or equal
+ /// to eight since the return value is 64 bits wide. Any
+ /// \a byte_size values less than 1 or greater than 8 will result in
+ /// nothing being extracted, and zero being returned.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] byte_size
+ /// The size in byte of the integer to extract.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// The unsigned integer value that was extracted, or zero on
+ /// failure.
+ uint64_t getUnsigned(uint64_t *offset_ptr, uint32_t byte_size,
+ Error *Err = nullptr) const;
+
+ /// Extract an unsigned integer of the given size from the location given by
+ /// the cursor. In case of an extraction error, or if the cursor is already in
+ /// an error state, zero is returned.
+ uint64_t getUnsigned(Cursor &C, uint32_t Size) const {
+ return getUnsigned(&C.Offset, Size, &C.Err);
+ }
+
+ /// Extract an signed integer of size \a byte_size from \a *offset_ptr.
+ ///
+ /// Extract a single signed integer value (sign extending if required)
+ /// and update the offset pointed to by \a offset_ptr. The size of
+ /// the extracted integer is specified by the \a byte_size argument.
+ /// \a byte_size should have a value greater than or equal to one
+ /// and less than or equal to eight since the return value is 64
+ /// bits wide. Any \a byte_size values less than 1 or greater than
+ /// 8 will result in nothing being extracted, and zero being returned.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] size
+ /// The size in bytes of the integer to extract.
+ ///
+ /// @return
+ /// The sign extended signed integer value that was extracted,
+ /// or zero on failure.
+ int64_t getSigned(uint64_t *offset_ptr, uint32_t size) const;
+
+ //------------------------------------------------------------------
+ /// Extract an pointer from \a *offset_ptr.
+ ///
+ /// Extract a single pointer from the data and update the offset
+ /// pointed to by \a offset_ptr. The size of the extracted pointer
+ /// is \a getAddressSize(), so the address size has to be
+ /// set correctly prior to extracting any pointer values.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted pointer value as a 64 integer.
+ uint64_t getAddress(uint64_t *offset_ptr) const {
+ return getUnsigned(offset_ptr, AddressSize);
+ }
+
+ /// Extract a pointer-sized unsigned integer from the location given by the
+ /// cursor. In case of an extraction error, or if the cursor is already in
+ /// an error state, zero is returned.
+ uint64_t getAddress(Cursor &C) const { return getUnsigned(C, AddressSize); }
+
+ /// Extract a uint8_t value from \a *offset_ptr.
+ ///
+ /// Extract a single uint8_t from the binary data at the offset
+ /// pointed to by \a offset_ptr, and advance the offset on success.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// The extracted uint8_t value.
+ uint8_t getU8(uint64_t *offset_ptr, Error *Err = nullptr) const;
+
+ /// Extract a single uint8_t value from the location given by the cursor. In
+ /// case of an extraction error, or if the cursor is already in an error
+ /// state, zero is returned.
+ uint8_t getU8(Cursor &C) const { return getU8(&C.Offset, &C.Err); }
+
+ /// Extract \a count uint8_t values from \a *offset_ptr.
+ ///
+ /// Extract \a count uint8_t values from the binary data at the
+ /// offset pointed to by \a offset_ptr, and advance the offset on
+ /// success. The extracted values are copied into \a dst.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[out] dst
+ /// A buffer to copy \a count uint8_t values into. \a dst must
+ /// be large enough to hold all requested data.
+ ///
+ /// @param[in] count
+ /// The number of uint8_t values to extract.
+ ///
+ /// @return
+ /// \a dst if all values were properly extracted and copied,
+ /// NULL otherise.
+ uint8_t *getU8(uint64_t *offset_ptr, uint8_t *dst, uint32_t count) const;
+
+ /// Extract \a Count uint8_t values from the location given by the cursor and
+ /// store them into the destination buffer. In case of an extraction error, or
+ /// if the cursor is already in an error state, a nullptr is returned and the
+ /// destination buffer is left unchanged.
+ uint8_t *getU8(Cursor &C, uint8_t *Dst, uint32_t Count) const;
+
+ /// Extract \a Count uint8_t values from the location given by the cursor and
+ /// store them into the destination vector. The vector is resized to fit the
+ /// extracted data. In case of an extraction error, or if the cursor is
+ /// already in an error state, the destination vector is left unchanged and
+ /// cursor is placed into an error state.
+ void getU8(Cursor &C, SmallVectorImpl<uint8_t> &Dst, uint32_t Count) const {
+ if (isValidOffsetForDataOfSize(C.Offset, Count))
+ Dst.resize(Count);
+
+ // This relies on the fact that getU8 will not attempt to write to the
+ // buffer if isValidOffsetForDataOfSize(C.Offset, Count) is false.
+ getU8(C, Dst.data(), Count);
+ }
+
+ //------------------------------------------------------------------
+ /// Extract a uint16_t value from \a *offset_ptr.
+ ///
+ /// Extract a single uint16_t from the binary data at the offset
+ /// pointed to by \a offset_ptr, and update the offset on success.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// The extracted uint16_t value.
+ //------------------------------------------------------------------
+ uint16_t getU16(uint64_t *offset_ptr, Error *Err = nullptr) const;
+
+ /// Extract a single uint16_t value from the location given by the cursor. In
+ /// case of an extraction error, or if the cursor is already in an error
+ /// state, zero is returned.
+ uint16_t getU16(Cursor &C) const { return getU16(&C.Offset, &C.Err); }
+
+ /// Extract \a count uint16_t values from \a *offset_ptr.
+ ///
+ /// Extract \a count uint16_t values from the binary data at the
+ /// offset pointed to by \a offset_ptr, and advance the offset on
+ /// success. The extracted values are copied into \a dst.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[out] dst
+ /// A buffer to copy \a count uint16_t values into. \a dst must
+ /// be large enough to hold all requested data.
+ ///
+ /// @param[in] count
+ /// The number of uint16_t values to extract.
+ ///
+ /// @return
+ /// \a dst if all values were properly extracted and copied,
+ /// NULL otherise.
+ uint16_t *getU16(uint64_t *offset_ptr, uint16_t *dst, uint32_t count) const;
+
+ /// Extract a 24-bit unsigned value from \a *offset_ptr and return it
+ /// in a uint32_t.
+ ///
+ /// Extract 3 bytes from the binary data at the offset pointed to by
+ /// \a offset_ptr, construct a uint32_t from them and update the offset
+ /// on success.
+ ///
+ /// @param[in,out] OffsetPtr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the 3 bytes if the value is extracted correctly. If the offset
+ /// is out of bounds or there are not enough bytes to extract this value,
+ /// the offset will be left unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// The extracted 24-bit value represented in a uint32_t.
+ uint32_t getU24(uint64_t *OffsetPtr, Error *Err = nullptr) const;
+
+ /// Extract a single 24-bit unsigned value from the location given by the
+ /// cursor. In case of an extraction error, or if the cursor is already in an
+ /// error state, zero is returned.
+ uint32_t getU24(Cursor &C) const { return getU24(&C.Offset, &C.Err); }
+
+ /// Extract a uint32_t value from \a *offset_ptr.
+ ///
+ /// Extract a single uint32_t from the binary data at the offset
+ /// pointed to by \a offset_ptr, and update the offset on success.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// The extracted uint32_t value.
+ uint32_t getU32(uint64_t *offset_ptr, Error *Err = nullptr) const;
+
+ /// Extract a single uint32_t value from the location given by the cursor. In
+ /// case of an extraction error, or if the cursor is already in an error
+ /// state, zero is returned.
+ uint32_t getU32(Cursor &C) const { return getU32(&C.Offset, &C.Err); }
+
+ /// Extract \a count uint32_t values from \a *offset_ptr.
+ ///
+ /// Extract \a count uint32_t values from the binary data at the
+ /// offset pointed to by \a offset_ptr, and advance the offset on
+ /// success. The extracted values are copied into \a dst.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[out] dst
+ /// A buffer to copy \a count uint32_t values into. \a dst must
+ /// be large enough to hold all requested data.
+ ///
+ /// @param[in] count
+ /// The number of uint32_t values to extract.
+ ///
+ /// @return
+ /// \a dst if all values were properly extracted and copied,
+ /// NULL otherise.
+ uint32_t *getU32(uint64_t *offset_ptr, uint32_t *dst, uint32_t count) const;
+
+ /// Extract a uint64_t value from \a *offset_ptr.
+ ///
+ /// Extract a single uint64_t from the binary data at the offset
+ /// pointed to by \a offset_ptr, and update the offset on success.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// The extracted uint64_t value.
+ uint64_t getU64(uint64_t *offset_ptr, Error *Err = nullptr) const;
+
+ /// Extract a single uint64_t value from the location given by the cursor. In
+ /// case of an extraction error, or if the cursor is already in an error
+ /// state, zero is returned.
+ uint64_t getU64(Cursor &C) const { return getU64(&C.Offset, &C.Err); }
+
+ /// Extract \a count uint64_t values from \a *offset_ptr.
+ ///
+ /// Extract \a count uint64_t values from the binary data at the
+ /// offset pointed to by \a offset_ptr, and advance the offset on
+ /// success. The extracted values are copied into \a dst.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[out] dst
+ /// A buffer to copy \a count uint64_t values into. \a dst must
+ /// be large enough to hold all requested data.
+ ///
+ /// @param[in] count
+ /// The number of uint64_t values to extract.
+ ///
+ /// @return
+ /// \a dst if all values were properly extracted and copied,
+ /// NULL otherise.
+ uint64_t *getU64(uint64_t *offset_ptr, uint64_t *dst, uint32_t count) const;
+
+ /// Extract a signed LEB128 value from \a *offset_ptr.
+ ///
+ /// Extracts an signed LEB128 number from this object's data
+ /// starting at the offset pointed to by \a offset_ptr. The offset
+ /// pointed to by \a offset_ptr will be updated with the offset of
+ /// the byte following the last extracted byte.
+ ///
+ /// @param[in,out] OffsetPtr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// The extracted signed integer value.
+ int64_t getSLEB128(uint64_t *OffsetPtr, Error *Err = nullptr) const;
+
+ /// Extract an signed LEB128 value from the location given by the cursor.
+ /// In case of an extraction error, or if the cursor is already in an error
+ /// state, zero is returned.
+ int64_t getSLEB128(Cursor &C) const { return getSLEB128(&C.Offset, &C.Err); }
+
+ /// Extract a unsigned LEB128 value from \a *offset_ptr.
+ ///
+ /// Extracts an unsigned LEB128 number from this object's data
+ /// starting at the offset pointed to by \a offset_ptr. The offset
+ /// pointed to by \a offset_ptr will be updated with the offset of
+ /// the byte following the last extracted byte.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in,out] Err
+ /// A pointer to an Error object. Upon return the Error object is set to
+ /// indicate the result (success/failure) of the function. If the Error
+ /// object is already set when calling this function, no extraction is
+ /// performed.
+ ///
+ /// @return
+ /// The extracted unsigned integer value.
+ uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err = nullptr) const;
+
+ /// Extract an unsigned LEB128 value from the location given by the cursor.
+ /// In case of an extraction error, or if the cursor is already in an error
+ /// state, zero is returned.
+ uint64_t getULEB128(Cursor &C) const { return getULEB128(&C.Offset, &C.Err); }
+
+ /// Advance the Cursor position by the given number of bytes. No-op if the
+ /// cursor is in an error state.
+ void skip(Cursor &C, uint64_t Length) const;
+
+ /// Return true iff the cursor is at the end of the buffer, regardless of the
+ /// error state of the cursor. The only way both eof and error states can be
+ /// true is if one attempts a read while the cursor is at the very end of the
+ /// data buffer.
+ bool eof(const Cursor &C) const { return size() == C.Offset; }
+
+ /// Test the validity of \a offset.
+ ///
+ /// @return
+ /// \b true if \a offset is a valid offset into the data in this
+ /// object, \b false otherwise.
+ bool isValidOffset(uint64_t offset) const { return size() > offset; }
+
+ /// Test the availability of \a length bytes of data from \a offset.
+ ///
+ /// @return
+ /// \b true if \a offset is a valid offset and there are \a
+ /// length bytes available at that offset, \b false otherwise.
+ bool isValidOffsetForDataOfSize(uint64_t offset, uint64_t length) const {
+ return offset + length >= offset && isValidOffset(offset + length - 1);
+ }
+
+ /// Test the availability of enough bytes of data for a pointer from
+ /// \a offset. The size of a pointer is \a getAddressSize().
+ ///
+ /// @return
+ /// \b true if \a offset is a valid offset and there are enough
+ /// bytes for a pointer available at that offset, \b false
+ /// otherwise.
+ bool isValidOffsetForAddress(uint64_t offset) const {
+ return isValidOffsetForDataOfSize(offset, AddressSize);
+ }
+
+ /// Return the number of bytes in the underlying buffer.
+ size_t size() const { return Data.size(); }
+
+protected:
+ // Make it possible for subclasses to access these fields without making them
+ // public.
+ static uint64_t &getOffset(Cursor &C) { return C.Offset; }
+ static Error &getError(Cursor &C) { return C.Err; }
+
+private:
+ /// If it is possible to read \a Size bytes at offset \a Offset, returns \b
+ /// true. Otherwise, returns \b false. If \a E is not nullptr, also sets the
+ /// error object to indicate an error.
+ bool prepareRead(uint64_t Offset, uint64_t Size, Error *E) const;
+
+ template <typename T> T getU(uint64_t *OffsetPtr, Error *Err) const;
+ template <typename T>
+ T *getUs(uint64_t *OffsetPtr, T *Dst, uint32_t Count, Error *Err) const;
+};
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/DataTypes.h b/contrib/libs/llvm16/include/llvm/Support/DataTypes.h
new file mode 100644
index 00000000000..a825219bb70
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/DataTypes.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/DataTypes.h - Define fixed size types ------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Due to layering constraints (Support depends on llvm-c) this is a thin
+// wrapper around the implementation that lives in llvm-c, though most clients
+// can/should think of this as being provided by Support for simplicity (not
+// many clients are aware of their dependency on llvm-c).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DATATYPES_H
+#define LLVM_SUPPORT_DATATYPES_H
+
+#include "llvm-c/DataTypes.h"
+
+#endif // LLVM_SUPPORT_DATATYPES_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Debug.h b/contrib/libs/llvm16/include/llvm/Support/Debug.h
new file mode 100644
index 00000000000..7c2a2139e6f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Debug.h
@@ -0,0 +1,116 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Debug.h - Easy way to add debug output ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a handy way of adding debugging information to your
+// code, without it being enabled all of the time, and without having to add
+// command line options to enable it.
+//
+// In particular, just wrap your code with the LLVM_DEBUG() macro, and it will
+// be enabled automatically if you specify '-debug' on the command-line.
+// LLVM_DEBUG() requires the DEBUG_TYPE macro to be defined. Set it to "foo"
+// specify that your debug code belongs to class "foo". Be careful that you only
+// do this after including Debug.h and not around any #include of headers.
+// Headers should define and undef the macro acround the code that needs to use
+// the LLVM_DEBUG() macro. Then, on the command line, you can specify
+// '-debug-only=foo' to enable JUST the debug information for the foo class.
+//
+// When compiling without assertions, the -debug-* options and all code in
+// LLVM_DEBUG() statements disappears, so it does not affect the runtime of the
+// code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DEBUG_H
+#define LLVM_SUPPORT_DEBUG_H
+
+namespace llvm {
+
+class raw_ostream;
+
+#ifndef NDEBUG
+
+/// isCurrentDebugType - Return true if the specified string is the debug type
+/// specified on the command line, or if none was specified on the command line
+/// with the -debug-only=X option.
+///
+bool isCurrentDebugType(const char *Type);
+
+/// setCurrentDebugType - Set the current debug type, as if the -debug-only=X
+/// option were specified. Note that DebugFlag also needs to be set to true for
+/// debug output to be produced.
+///
+void setCurrentDebugType(const char *Type);
+
+/// setCurrentDebugTypes - Set the current debug type, as if the
+/// -debug-only=X,Y,Z option were specified. Note that DebugFlag
+/// also needs to be set to true for debug output to be produced.
+///
+void setCurrentDebugTypes(const char **Types, unsigned Count);
+
+/// DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug
+/// information. In the '-debug' option is specified on the commandline, and if
+/// this is a debug build, then the code specified as the option to the macro
+/// will be executed. Otherwise it will not be. Example:
+///
+/// DEBUG_WITH_TYPE("bitset", dbgs() << "Bitset contains: " << Bitset << "\n");
+///
+/// This will emit the debug information if -debug is present, and -debug-only
+/// is not specified, or is specified as "bitset".
+#define DEBUG_WITH_TYPE(TYPE, X) \
+ do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType(TYPE)) { X; } \
+ } while (false)
+
+#else
+#define isCurrentDebugType(X) (false)
+#define setCurrentDebugType(X) do { (void)(X); } while (false)
+#define setCurrentDebugTypes(X, N) do { (void)(X); (void)(N); } while (false)
+#define DEBUG_WITH_TYPE(TYPE, X) do { } while (false)
+#endif
+
+/// This boolean is set to true if the '-debug' command line option
+/// is specified. This should probably not be referenced directly, instead, use
+/// the DEBUG macro below.
+///
+extern bool DebugFlag;
+
+/// EnableDebugBuffering - This defaults to false. If true, the debug
+/// stream will install signal handlers to dump any buffered debug
+/// output. It allows clients to selectively allow the debug stream
+/// to install signal handlers if they are certain there will be no
+/// conflict.
+///
+extern bool EnableDebugBuffering;
+
+/// dbgs() - This returns a reference to a raw_ostream for debugging
+/// messages. If debugging is disabled it returns errs(). Use it
+/// like: dbgs() << "foo" << "bar";
+raw_ostream &dbgs();
+
+// DEBUG macro - This macro should be used by passes to emit debug information.
+// In the '-debug' option is specified on the commandline, and if this is a
+// debug build, then the code specified as the option to the macro will be
+// executed. Otherwise it will not be. Example:
+//
+// LLVM_DEBUG(dbgs() << "Bitset contains: " << Bitset << "\n");
+//
+#define LLVM_DEBUG(X) DEBUG_WITH_TYPE(DEBUG_TYPE, X)
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_DEBUG_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/DebugCounter.h b/contrib/libs/llvm16/include/llvm/Support/DebugCounter.h
new file mode 100644
index 00000000000..f37163af050
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/DebugCounter.h
@@ -0,0 +1,198 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/DebugCounter.h - Debug counter support ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file provides an implementation of debug counters. Debug
+/// counters are a tool that let you narrow down a miscompilation to a specific
+/// thing happening.
+///
+/// To give a use case: Imagine you have a file, very large, and you
+/// are trying to understand the minimal transformation that breaks it. Bugpoint
+/// and bisection is often helpful here in narrowing it down to a specific pass,
+/// but it's still a very large file, and a very complicated pass to try to
+/// debug. That is where debug counting steps in. You can instrument the pass
+/// with a debug counter before it does a certain thing, and depending on the
+/// counts, it will either execute that thing or not. The debug counter itself
+/// consists of a skip and a count. Skip is the number of times shouldExecute
+/// needs to be called before it returns true. Count is the number of times to
+/// return true once Skip is 0. So a skip=47, count=2 ,would skip the first 47
+/// executions by returning false from shouldExecute, then execute twice, and
+/// then return false again.
+/// Note that a counter set to a negative number will always execute.
+/// For a concrete example, during predicateinfo creation, the renaming pass
+/// replaces each use with a renamed use.
+////
+/// If I use DEBUG_COUNTER to create a counter called "predicateinfo", and
+/// variable name RenameCounter, and then instrument this renaming with a debug
+/// counter, like so:
+///
+/// if (!DebugCounter::shouldExecute(RenameCounter)
+/// <continue or return or whatever not executing looks like>
+///
+/// Now I can, from the command line, make it rename or not rename certain uses
+/// by setting the skip and count.
+/// So for example
+/// bin/opt -debug-counter=predicateinfo-skip=47,predicateinfo-count=1
+/// will skip renaming the first 47 uses, then rename one, then skip the rest.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DEBUGCOUNTER_H
+#define LLVM_SUPPORT_DEBUGCOUNTER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/UniqueVector.h"
+#include "llvm/Support/Debug.h"
+#include <string>
+
+namespace llvm {
+
+class raw_ostream;
+
+class DebugCounter {
+public:
+ /// Returns a reference to the singleton instance.
+ static DebugCounter &instance();
+
+ // Used by the command line option parser to push a new value it parsed.
+ void push_back(const std::string &);
+
+ // Register a counter with the specified name.
+ //
+ // FIXME: Currently, counter registration is required to happen before command
+ // line option parsing. The main reason to register counters is to produce a
+ // nice list of them on the command line, but i'm not sure this is worth it.
+ static unsigned registerCounter(StringRef Name, StringRef Desc) {
+ return instance().addCounter(std::string(Name), std::string(Desc));
+ }
+ inline static bool shouldExecute(unsigned CounterName) {
+ if (!isCountingEnabled())
+ return true;
+
+ auto &Us = instance();
+ auto Result = Us.Counters.find(CounterName);
+ if (Result != Us.Counters.end()) {
+ auto &CounterInfo = Result->second;
+ ++CounterInfo.Count;
+
+ // We only execute while the Skip is not smaller than Count,
+ // and the StopAfter + Skip is larger than Count.
+ // Negative counters always execute.
+ if (CounterInfo.Skip < 0)
+ return true;
+ if (CounterInfo.Skip >= CounterInfo.Count)
+ return false;
+ if (CounterInfo.StopAfter < 0)
+ return true;
+ return CounterInfo.StopAfter + CounterInfo.Skip >= CounterInfo.Count;
+ }
+ // Didn't find the counter, should we warn?
+ return true;
+ }
+
+ // Return true if a given counter had values set (either programatically or on
+ // the command line). This will return true even if those values are
+ // currently in a state where the counter will always execute.
+ static bool isCounterSet(unsigned ID) {
+ return instance().Counters[ID].IsSet;
+ }
+
+ // Return the Count for a counter. This only works for set counters.
+ static int64_t getCounterValue(unsigned ID) {
+ auto &Us = instance();
+ auto Result = Us.Counters.find(ID);
+ assert(Result != Us.Counters.end() && "Asking about a non-set counter");
+ return Result->second.Count;
+ }
+
+ // Set a registered counter to a given Count value.
+ static void setCounterValue(unsigned ID, int64_t Count) {
+ auto &Us = instance();
+ Us.Counters[ID].Count = Count;
+ }
+
+ // Dump or print the current counter set into llvm::dbgs().
+ LLVM_DUMP_METHOD void dump() const;
+
+ void print(raw_ostream &OS) const;
+
+ // Get the counter ID for a given named counter, or return 0 if none is found.
+ unsigned getCounterId(const std::string &Name) const {
+ return RegisteredCounters.idFor(Name);
+ }
+
+ // Return the number of registered counters.
+ unsigned int getNumCounters() const { return RegisteredCounters.size(); }
+
+ // Return the name and description of the counter with the given ID.
+ std::pair<std::string, std::string> getCounterInfo(unsigned ID) const {
+ return std::make_pair(RegisteredCounters[ID], Counters.lookup(ID).Desc);
+ }
+
+ // Iterate through the registered counters
+ typedef UniqueVector<std::string> CounterVector;
+ CounterVector::const_iterator begin() const {
+ return RegisteredCounters.begin();
+ }
+ CounterVector::const_iterator end() const { return RegisteredCounters.end(); }
+
+ // Force-enables counting all DebugCounters.
+ //
+ // Since DebugCounters are incompatible with threading (not only do they not
+ // make sense, but we'll also see data races), this should only be used in
+ // contexts where we're certain we won't spawn threads.
+ static void enableAllCounters() { instance().Enabled = true; }
+
+ static bool isCountingEnabled() {
+// Compile to nothing when debugging is off
+#ifdef NDEBUG
+ return false;
+#else
+ return instance().Enabled;
+#endif
+ }
+
+private:
+ unsigned addCounter(const std::string &Name, const std::string &Desc) {
+ unsigned Result = RegisteredCounters.insert(Name);
+ Counters[Result] = {};
+ Counters[Result].Desc = Desc;
+ return Result;
+ }
+ // Struct to store counter info.
+ struct CounterInfo {
+ int64_t Count = 0;
+ int64_t Skip = 0;
+ int64_t StopAfter = -1;
+ bool IsSet = false;
+ std::string Desc;
+ };
+ DenseMap<unsigned, CounterInfo> Counters;
+ CounterVector RegisteredCounters;
+
+ // Whether we should do DebugCounting at all. DebugCounters aren't
+ // thread-safe, so this should always be false in multithreaded scenarios.
+ bool Enabled = false;
+};
+
+#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC) \
+ static const unsigned VARNAME = \
+ DebugCounter::registerCounter(COUNTERNAME, DESC)
+
+} // namespace llvm
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Discriminator.h b/contrib/libs/llvm16/include/llvm/Support/Discriminator.h
new file mode 100644
index 00000000000..8f957f7ea8f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Discriminator.h
@@ -0,0 +1,144 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===---- llvm/Support/Discriminator.h -- Discriminator Utils ---*- 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 defines the constants and utility functions for discriminators.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DISCRIMINATOR_H
+#define LLVM_SUPPORT_DISCRIMINATOR_H
+
+#include "llvm/Support/Error.h"
+#include <assert.h>
+
+// Utility functions for encoding / decoding discriminators.
+/// With a given unsigned int \p U, use up to 13 bits to represent it.
+/// old_bit 1~5 --> new_bit 1~5
+/// old_bit 6~12 --> new_bit 7~13
+/// new_bit_6 is 0 if higher bits (7~13) are all 0
+static inline unsigned getPrefixEncodingFromUnsigned(unsigned U) {
+ U &= 0xfff;
+ return U > 0x1f ? (((U & 0xfe0) << 1) | (U & 0x1f) | 0x20) : U;
+}
+
+/// Reverse transformation as getPrefixEncodingFromUnsigned.
+static inline unsigned getUnsignedFromPrefixEncoding(unsigned U) {
+ if (U & 1)
+ return 0;
+ U >>= 1;
+ return (U & 0x20) ? (((U >> 1) & 0xfe0) | (U & 0x1f)) : (U & 0x1f);
+}
+
+/// Returns the next component stored in discriminator.
+static inline unsigned getNextComponentInDiscriminator(unsigned D) {
+ if ((D & 1) == 0)
+ return D >> ((D & 0x40) ? 14 : 7);
+ else
+ return D >> 1;
+}
+
+static inline unsigned encodeComponent(unsigned C) {
+ return (C == 0) ? 1U : (getPrefixEncodingFromUnsigned(C) << 1);
+}
+
+static inline unsigned encodingBits(unsigned C) {
+ return (C == 0) ? 1 : (C > 0x1f ? 14 : 7);
+}
+
+// Some constants used in FS Discriminators.
+//
+namespace llvm {
+namespace sampleprof {
+enum FSDiscriminatorPass {
+ Base = 0,
+ Pass0 = 0,
+ Pass1 = 1,
+ Pass2 = 2,
+ Pass3 = 3,
+ Pass4 = 4,
+ PassLast = 4,
+};
+} // namespace sampleprof
+
+using namespace sampleprof;
+
+// The number of bits reserved for the base discrimininator. The base
+// discriminaitor starts from bit 0.
+static const unsigned BaseDiscriminatorBitWidth = 8;
+
+// The number of bits reserved for each FS discriminator pass.
+static const unsigned FSDiscriminatorBitWidth = 6;
+
+// Return the number of FS passes, excluding the pass adding the base
+// discriminators.
+// The number of passes for FS discriminators. Note that the total
+// number of discriminaitor bits, i.e.
+// BaseDiscriminatorBitWidth
+// + FSDiscriminatorBitWidth * getNumFSPasses()
+// needs to fit in an unsigned int type.
+static inline unsigned getNumFSPasses() {
+ return static_cast<unsigned>(FSDiscriminatorPass::PassLast);
+}
+
+// Return the ending bit for FSPass P.
+static inline unsigned getFSPassBitEnd(FSDiscriminatorPass P) {
+ unsigned I = static_cast<unsigned>(P);
+ assert(I <= getNumFSPasses() && "Invalid FS discriminator pass number.");
+ return BaseDiscriminatorBitWidth + I * FSDiscriminatorBitWidth - 1;
+}
+
+// Return the begining bit for FSPass P.
+static inline unsigned getFSPassBitBegin(FSDiscriminatorPass P) {
+ if (P == FSDiscriminatorPass::Base)
+ return 0;
+ unsigned I = static_cast<unsigned>(P);
+ assert(I <= getNumFSPasses() && "Invalid FS discriminator pass number.");
+ return getFSPassBitEnd(static_cast<FSDiscriminatorPass>(I - 1)) + 1;
+}
+
+// Return the beginning bit for the last FSPass.
+static inline int getLastFSPassBitBegin() {
+ return getFSPassBitBegin(static_cast<FSDiscriminatorPass>(getNumFSPasses()));
+}
+
+// Return the ending bit for the last FSPass.
+static inline unsigned getLastFSPassBitEnd() {
+ return getFSPassBitEnd(static_cast<FSDiscriminatorPass>(getNumFSPasses()));
+}
+
+// Return the beginning bit for the base (first) FSPass.
+static inline unsigned getBaseFSBitBegin() { return 0; }
+
+// Return the ending bit for the base (first) FSPass.
+static inline unsigned getBaseFSBitEnd() {
+ return BaseDiscriminatorBitWidth - 1;
+}
+
+// Set bits in range of [0 .. n] to 1. Used in FS Discriminators.
+static inline unsigned getN1Bits(int N) {
+ // Work around the g++ bug that folding "(1U << (N + 1)) - 1" to 0.
+ if (N == 31)
+ return 0xFFFFFFFF;
+ assert((N < 32) && "N is invalid");
+ return (1U << (N + 1)) - 1;
+}
+
+} // namespace llvm
+
+#endif /* LLVM_SUPPORT_DISCRIMINATOR_H */
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/DivisionByConstantInfo.h b/contrib/libs/llvm16/include/llvm/Support/DivisionByConstantInfo.h
new file mode 100644
index 00000000000..698eda798cc
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/DivisionByConstantInfo.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/DivisionByConstantInfo.h ---------------------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// This file implements support for optimizing divisions by a constant
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DIVISIONBYCONSTANTINFO_H
+#define LLVM_SUPPORT_DIVISIONBYCONSTANTINFO_H
+
+#include "llvm/ADT/APInt.h"
+
+namespace llvm {
+
+/// Magic data for optimising signed division by a constant.
+struct SignedDivisionByConstantInfo {
+ static SignedDivisionByConstantInfo get(const APInt &D);
+ APInt Magic; ///< magic number
+ unsigned ShiftAmount; ///< shift amount
+};
+
+/// Magic data for optimising unsigned division by a constant.
+struct UnsignedDivisionByConstantInfo {
+ static UnsignedDivisionByConstantInfo
+ get(const APInt &D, unsigned LeadingZeros = 0,
+ bool AllowEvenDivisorOptimization = true);
+ APInt Magic; ///< magic number
+ bool IsAdd; ///< add indicator
+ unsigned PostShift; ///< post-shift amount
+ unsigned PreShift; ///< pre-shift amount
+};
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Duration.h b/contrib/libs/llvm16/include/llvm/Support/Duration.h
new file mode 100644
index 00000000000..6a8372a4d86
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Duration.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- Duration.h - wrapper around std::chrono::Duration ------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// The sole purpose of this file is to avoid the dependency on <chrono> in
+// raw_ostream.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DURATION_H
+#define LLVM_SUPPORT_DURATION_H
+
+#include <chrono>
+
+namespace llvm {
+class Duration {
+ std::chrono::milliseconds Value;
+ public:
+ Duration(std::chrono::milliseconds Value) : Value(Value) {}
+ std::chrono::milliseconds getDuration() const { return Value; }
+};
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/DynamicLibrary.h b/contrib/libs/llvm16/include/llvm/Support/DynamicLibrary.h
new file mode 100644
index 00000000000..98ca1ae44fa
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/DynamicLibrary.h
@@ -0,0 +1,165 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/DynamicLibrary.h - Portable Dynamic Library -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the sys::DynamicLibrary class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_DYNAMICLIBRARY_H
+#define LLVM_SUPPORT_DYNAMICLIBRARY_H
+
+#include <string>
+
+namespace llvm {
+
+class StringRef;
+
+namespace sys {
+
+/// This class provides a portable interface to dynamic libraries which also
+/// might be known as shared libraries, shared objects, dynamic shared
+/// objects, or dynamic link libraries. Regardless of the terminology or the
+/// operating system interface, this class provides a portable interface that
+/// allows dynamic libraries to be loaded and searched for externally
+/// defined symbols. This is typically used to provide "plug-in" support.
+/// It also allows for symbols to be defined which don't live in any library,
+/// but rather the main program itself, useful on Windows where the main
+/// executable cannot be searched.
+class DynamicLibrary {
+ // Placeholder whose address represents an invalid library.
+ // We use this instead of NULL or a pointer-int pair because the OS library
+ // might define 0 or 1 to be "special" handles, such as "search all".
+ static char Invalid;
+
+ // Opaque data used to interface with OS-specific dynamic library handling.
+ void *Data;
+
+public:
+ explicit DynamicLibrary(void *data = &Invalid) : Data(data) {}
+
+ /// Return the OS specific handle value.
+ void *getOSSpecificHandle() const { return Data; }
+
+ /// Returns true if the object refers to a valid library.
+ bool isValid() const { return Data != &Invalid; }
+
+ /// Searches through the library for the symbol \p symbolName. If it is
+ /// found, the address of that symbol is returned. If not, NULL is returned.
+ /// Note that NULL will also be returned if the library failed to load.
+ /// Use isValid() to distinguish these cases if it is important.
+ /// Note that this will \e not search symbols explicitly registered by
+ /// AddSymbol().
+ void *getAddressOfSymbol(const char *symbolName);
+
+ /// This function permanently loads the dynamic library at the given path
+ /// using the library load operation from the host operating system. The
+ /// library instance will only be closed when global destructors run, and
+ /// there is no guarantee when the library will be unloaded.
+ ///
+ /// This returns a valid DynamicLibrary instance on success and an invalid
+ /// instance on failure (see isValid()). \p *errMsg will only be modified if
+ /// the library fails to load.
+ ///
+ /// It is safe to call this function multiple times for the same library.
+ /// Open a dynamic library permanently.
+ static DynamicLibrary getPermanentLibrary(const char *filename,
+ std::string *errMsg = nullptr);
+
+ /// Registers an externally loaded library. The library will be unloaded
+ /// when the program terminates.
+ ///
+ /// It is safe to call this function multiple times for the same library,
+ /// though ownership is only taken if there was no error.
+ static DynamicLibrary addPermanentLibrary(void *handle,
+ std::string *errMsg = nullptr);
+
+ /// This function permanently loads the dynamic library at the given path.
+ /// Use this instead of getPermanentLibrary() when you won't need to get
+ /// symbols from the library itself.
+ ///
+ /// It is safe to call this function multiple times for the same library.
+ static bool LoadLibraryPermanently(const char *Filename,
+ std::string *ErrMsg = nullptr) {
+ return !getPermanentLibrary(Filename, ErrMsg).isValid();
+ }
+
+ /// This function loads the dynamic library at the given path, using the
+ /// library load operation from the host operating system. The library
+ /// instance will be closed when closeLibrary is called or global destructors
+ /// are run, but there is no guarantee when the library will be unloaded.
+ ///
+ /// This returns a valid DynamicLibrary instance on success and an invalid
+ /// instance on failure (see isValid()). \p *Err will only be modified if the
+ /// library fails to load.
+ ///
+ /// It is safe to call this function multiple times for the same library.
+ static DynamicLibrary getLibrary(const char *FileName,
+ std::string *Err = nullptr);
+
+ /// This function closes the dynamic library at the given path, using the
+ /// library close operation of the host operating system, and there is no
+ /// guarantee if or when this will cause the the library to be unloaded.
+ ///
+ /// This function should be called only if the library was loaded using the
+ /// getLibrary() function.
+ static void closeLibrary(DynamicLibrary &Lib);
+
+ enum SearchOrdering {
+ /// SO_Linker - Search as a call to dlsym(dlopen(NULL)) would when
+ /// DynamicLibrary::getPermanentLibrary(NULL) has been called or
+ /// search the list of explcitly loaded symbols if not.
+ SO_Linker,
+ /// SO_LoadedFirst - Search all loaded libraries, then as SO_Linker would.
+ SO_LoadedFirst,
+ /// SO_LoadedLast - Search as SO_Linker would, then loaded libraries.
+ /// Only useful to search if libraries with RTLD_LOCAL have been added.
+ SO_LoadedLast,
+ /// SO_LoadOrder - Or this in to search libraries in the ordered loaded.
+ /// The default bahaviour is to search loaded libraries in reverse.
+ SO_LoadOrder = 4
+ };
+ static SearchOrdering SearchOrder; // = SO_Linker
+
+ /// This function will search through all previously loaded dynamic
+ /// libraries for the symbol \p symbolName. If it is found, the address of
+ /// that symbol is returned. If not, null is returned. Note that this will
+ /// search permanently loaded libraries (getPermanentLibrary()) as well
+ /// as explicitly registered symbols (AddSymbol()).
+ /// @throws std::string on error.
+ /// Search through libraries for address of a symbol
+ static void *SearchForAddressOfSymbol(const char *symbolName);
+
+ /// Convenience function for C++ophiles.
+ static void *SearchForAddressOfSymbol(const std::string &symbolName) {
+ return SearchForAddressOfSymbol(symbolName.c_str());
+ }
+
+ /// This functions permanently adds the symbol \p symbolName with the
+ /// value \p symbolValue. These symbols are searched before any
+ /// libraries.
+ /// Add searchable symbol/value pair.
+ static void AddSymbol(StringRef symbolName, void *symbolValue);
+
+ class HandleSet;
+};
+
+} // End sys namespace
+} // End llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ELFAttributeParser.h b/contrib/libs/llvm16/include/llvm/Support/ELFAttributeParser.h
new file mode 100644
index 00000000000..5905108334f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ELFAttributeParser.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- ELF AttributeParser.h - ELF Attribute Parser -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_ELFATTRIBUTEPARSER_H
+
+#include "ELFAttributes.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+#include <optional>
+#include <unordered_map>
+
+namespace llvm {
+class StringRef;
+class ScopedPrinter;
+
+class ELFAttributeParser {
+ StringRef vendor;
+ std::unordered_map<unsigned, unsigned> attributes;
+ std::unordered_map<unsigned, StringRef> attributesStr;
+
+ virtual Error handler(uint64_t tag, bool &handled) = 0;
+
+protected:
+ ScopedPrinter *sw;
+ TagNameMap tagToStringMap;
+ DataExtractor de{ArrayRef<uint8_t>{}, true, 0};
+ DataExtractor::Cursor cursor{0};
+
+ void printAttribute(unsigned tag, unsigned value, StringRef valueDesc);
+
+ Error parseStringAttribute(const char *name, unsigned tag,
+ ArrayRef<const char *> strings);
+ Error parseAttributeList(uint32_t length);
+ void parseIndexList(SmallVectorImpl<uint8_t> &indexList);
+ Error parseSubsection(uint32_t length);
+
+ void setAttributeString(unsigned tag, StringRef value) {
+ attributesStr.emplace(tag, value);
+ }
+
+public:
+ virtual ~ELFAttributeParser() { static_cast<void>(!cursor.takeError()); }
+ Error integerAttribute(unsigned tag);
+ Error stringAttribute(unsigned tag);
+
+ ELFAttributeParser(ScopedPrinter *sw, TagNameMap tagNameMap, StringRef vendor)
+ : vendor(vendor), sw(sw), tagToStringMap(tagNameMap) {}
+
+ ELFAttributeParser(TagNameMap tagNameMap, StringRef vendor)
+ : vendor(vendor), sw(nullptr), tagToStringMap(tagNameMap) {}
+
+ Error parse(ArrayRef<uint8_t> section, support::endianness endian);
+
+ std::optional<unsigned> getAttributeValue(unsigned tag) const {
+ auto I = attributes.find(tag);
+ if (I == attributes.end())
+ return std::nullopt;
+ return I->second;
+ }
+ std::optional<StringRef> getAttributeString(unsigned tag) const {
+ auto I = attributesStr.find(tag);
+ if (I == attributesStr.end())
+ return std::nullopt;
+ return I->second;
+ }
+};
+
+} // namespace llvm
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ELFAttributes.h b/contrib/libs/llvm16/include/llvm/Support/ELFAttributes.h
new file mode 100644
index 00000000000..b392c7d8a46
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ELFAttributes.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- ELFAttributes.h - ELF Attributes ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ELFATTRIBUTES_H
+#define LLVM_SUPPORT_ELFATTRIBUTES_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include <optional>
+
+namespace llvm {
+
+struct TagNameItem {
+ unsigned attr;
+ StringRef tagName;
+};
+
+using TagNameMap = ArrayRef<TagNameItem>;
+
+namespace ELFAttrs {
+
+enum AttrType : unsigned { File = 1, Section = 2, Symbol = 3 };
+
+StringRef attrTypeAsString(unsigned attr, TagNameMap tagNameMap,
+ bool hasTagPrefix = true);
+std::optional<unsigned> attrTypeFromString(StringRef tag, TagNameMap tagNameMap);
+
+// Magic numbers for ELF attributes.
+enum AttrMagic { Format_Version = 0x41 };
+
+} // namespace ELFAttrs
+} // namespace llvm
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Endian.h b/contrib/libs/llvm16/include/llvm/Support/Endian.h
new file mode 100644
index 00000000000..6f0e54a2274
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Endian.h
@@ -0,0 +1,438 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares generic functions to read and write endian specific data.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ENDIAN_H
+#define LLVM_SUPPORT_ENDIAN_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/SwapByteOrder.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <type_traits>
+
+namespace llvm {
+namespace support {
+
+enum endianness {big, little, native};
+
+// These are named values for common alignments.
+enum {aligned = 0, unaligned = 1};
+
+namespace detail {
+
+/// ::value is either alignment, or alignof(T) if alignment is 0.
+template<class T, int alignment>
+struct PickAlignment {
+ enum { value = alignment == 0 ? alignof(T) : alignment };
+};
+
+} // end namespace detail
+
+namespace endian {
+
+constexpr endianness system_endianness() {
+ return sys::IsBigEndianHost ? big : little;
+}
+
+template <typename value_type>
+inline value_type byte_swap(value_type value, endianness endian) {
+ if ((endian != native) && (endian != system_endianness()))
+ sys::swapByteOrder(value);
+ return value;
+}
+
+/// Swap the bytes of value to match the given endianness.
+template<typename value_type, endianness endian>
+inline value_type byte_swap(value_type value) {
+ return byte_swap(value, endian);
+}
+
+/// Read a value of a particular endianness from memory.
+template <typename value_type, std::size_t alignment>
+inline value_type read(const void *memory, endianness endian) {
+ value_type ret;
+
+ memcpy(&ret,
+ LLVM_ASSUME_ALIGNED(
+ memory, (detail::PickAlignment<value_type, alignment>::value)),
+ sizeof(value_type));
+ return byte_swap<value_type>(ret, endian);
+}
+
+template<typename value_type,
+ endianness endian,
+ std::size_t alignment>
+inline value_type read(const void *memory) {
+ return read<value_type, alignment>(memory, endian);
+}
+
+/// Read a value of a particular endianness from a buffer, and increment the
+/// buffer past that value.
+template <typename value_type, std::size_t alignment, typename CharT>
+inline value_type readNext(const CharT *&memory, endianness endian) {
+ value_type ret = read<value_type, alignment>(memory, endian);
+ memory += sizeof(value_type);
+ return ret;
+}
+
+template<typename value_type, endianness endian, std::size_t alignment,
+ typename CharT>
+inline value_type readNext(const CharT *&memory) {
+ return readNext<value_type, alignment, CharT>(memory, endian);
+}
+
+/// Write a value to memory with a particular endianness.
+template <typename value_type, std::size_t alignment>
+inline void write(void *memory, value_type value, endianness endian) {
+ value = byte_swap<value_type>(value, endian);
+ memcpy(LLVM_ASSUME_ALIGNED(
+ memory, (detail::PickAlignment<value_type, alignment>::value)),
+ &value, sizeof(value_type));
+}
+
+template<typename value_type,
+ endianness endian,
+ std::size_t alignment>
+inline void write(void *memory, value_type value) {
+ write<value_type, alignment>(memory, value, endian);
+}
+
+template <typename value_type>
+using make_unsigned_t = std::make_unsigned_t<value_type>;
+
+/// Read a value of a particular endianness from memory, for a location
+/// that starts at the given bit offset within the first byte.
+template <typename value_type, endianness endian, std::size_t alignment>
+inline value_type readAtBitAlignment(const void *memory, uint64_t startBit) {
+ assert(startBit < 8);
+ if (startBit == 0)
+ return read<value_type, endian, alignment>(memory);
+ else {
+ // Read two values and compose the result from them.
+ value_type val[2];
+ memcpy(&val[0],
+ LLVM_ASSUME_ALIGNED(
+ memory, (detail::PickAlignment<value_type, alignment>::value)),
+ sizeof(value_type) * 2);
+ val[0] = byte_swap<value_type, endian>(val[0]);
+ val[1] = byte_swap<value_type, endian>(val[1]);
+
+ // Shift bits from the lower value into place.
+ make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
+ // Mask off upper bits after right shift in case of signed type.
+ make_unsigned_t<value_type> numBitsFirstVal =
+ (sizeof(value_type) * 8) - startBit;
+ lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
+
+ // Get the bits from the upper value.
+ make_unsigned_t<value_type> upperVal =
+ val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
+ // Shift them in to place.
+ upperVal <<= numBitsFirstVal;
+
+ return lowerVal | upperVal;
+ }
+}
+
+/// Write a value to memory with a particular endianness, for a location
+/// that starts at the given bit offset within the first byte.
+template <typename value_type, endianness endian, std::size_t alignment>
+inline void writeAtBitAlignment(void *memory, value_type value,
+ uint64_t startBit) {
+ assert(startBit < 8);
+ if (startBit == 0)
+ write<value_type, endian, alignment>(memory, value);
+ else {
+ // Read two values and shift the result into them.
+ value_type val[2];
+ memcpy(&val[0],
+ LLVM_ASSUME_ALIGNED(
+ memory, (detail::PickAlignment<value_type, alignment>::value)),
+ sizeof(value_type) * 2);
+ val[0] = byte_swap<value_type, endian>(val[0]);
+ val[1] = byte_swap<value_type, endian>(val[1]);
+
+ // Mask off any existing bits in the upper part of the lower value that
+ // we want to replace.
+ val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
+ make_unsigned_t<value_type> numBitsFirstVal =
+ (sizeof(value_type) * 8) - startBit;
+ make_unsigned_t<value_type> lowerVal = value;
+ if (startBit > 0) {
+ // Mask off the upper bits in the new value that are not going to go into
+ // the lower value. This avoids a left shift of a negative value, which
+ // is undefined behavior.
+ lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
+ // Now shift the new bits into place
+ lowerVal <<= startBit;
+ }
+ val[0] |= lowerVal;
+
+ // Mask off any existing bits in the lower part of the upper value that
+ // we want to replace.
+ val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
+ // Next shift the bits that go into the upper value into position.
+ make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
+ // Mask off upper bits after right shift in case of signed type.
+ upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
+ val[1] |= upperVal;
+
+ // Finally, rewrite values.
+ val[0] = byte_swap<value_type, endian>(val[0]);
+ val[1] = byte_swap<value_type, endian>(val[1]);
+ memcpy(LLVM_ASSUME_ALIGNED(
+ memory, (detail::PickAlignment<value_type, alignment>::value)),
+ &val[0], sizeof(value_type) * 2);
+ }
+}
+
+} // end namespace endian
+
+namespace detail {
+
+template <typename ValueType, endianness Endian, std::size_t Alignment,
+ std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
+struct packed_endian_specific_integral {
+ using value_type = ValueType;
+ static constexpr endianness endian = Endian;
+ static constexpr std::size_t alignment = Alignment;
+
+ packed_endian_specific_integral() = default;
+
+ explicit packed_endian_specific_integral(value_type val) { *this = val; }
+
+ operator value_type() const {
+ return endian::read<value_type, endian, alignment>(
+ (const void*)Value.buffer);
+ }
+
+ void operator=(value_type newValue) {
+ endian::write<value_type, endian, alignment>(
+ (void*)Value.buffer, newValue);
+ }
+
+ packed_endian_specific_integral &operator+=(value_type newValue) {
+ *this = *this + newValue;
+ return *this;
+ }
+
+ packed_endian_specific_integral &operator-=(value_type newValue) {
+ *this = *this - newValue;
+ return *this;
+ }
+
+ packed_endian_specific_integral &operator|=(value_type newValue) {
+ *this = *this | newValue;
+ return *this;
+ }
+
+ packed_endian_specific_integral &operator&=(value_type newValue) {
+ *this = *this & newValue;
+ return *this;
+ }
+
+private:
+ struct {
+ alignas(ALIGN) char buffer[sizeof(value_type)];
+ } Value;
+
+public:
+ struct ref {
+ explicit ref(void *Ptr) : Ptr(Ptr) {}
+
+ operator value_type() const {
+ return endian::read<value_type, endian, alignment>(Ptr);
+ }
+
+ void operator=(value_type NewValue) {
+ endian::write<value_type, endian, alignment>(Ptr, NewValue);
+ }
+
+ private:
+ void *Ptr;
+ };
+};
+
+} // end namespace detail
+
+using ulittle16_t =
+ detail::packed_endian_specific_integral<uint16_t, little, unaligned>;
+using ulittle32_t =
+ detail::packed_endian_specific_integral<uint32_t, little, unaligned>;
+using ulittle64_t =
+ detail::packed_endian_specific_integral<uint64_t, little, unaligned>;
+
+using little16_t =
+ detail::packed_endian_specific_integral<int16_t, little, unaligned>;
+using little32_t =
+ detail::packed_endian_specific_integral<int32_t, little, unaligned>;
+using little64_t =
+ detail::packed_endian_specific_integral<int64_t, little, unaligned>;
+
+using aligned_ulittle16_t =
+ detail::packed_endian_specific_integral<uint16_t, little, aligned>;
+using aligned_ulittle32_t =
+ detail::packed_endian_specific_integral<uint32_t, little, aligned>;
+using aligned_ulittle64_t =
+ detail::packed_endian_specific_integral<uint64_t, little, aligned>;
+
+using aligned_little16_t =
+ detail::packed_endian_specific_integral<int16_t, little, aligned>;
+using aligned_little32_t =
+ detail::packed_endian_specific_integral<int32_t, little, aligned>;
+using aligned_little64_t =
+ detail::packed_endian_specific_integral<int64_t, little, aligned>;
+
+using ubig16_t =
+ detail::packed_endian_specific_integral<uint16_t, big, unaligned>;
+using ubig32_t =
+ detail::packed_endian_specific_integral<uint32_t, big, unaligned>;
+using ubig64_t =
+ detail::packed_endian_specific_integral<uint64_t, big, unaligned>;
+
+using big16_t =
+ detail::packed_endian_specific_integral<int16_t, big, unaligned>;
+using big32_t =
+ detail::packed_endian_specific_integral<int32_t, big, unaligned>;
+using big64_t =
+ detail::packed_endian_specific_integral<int64_t, big, unaligned>;
+
+using aligned_ubig16_t =
+ detail::packed_endian_specific_integral<uint16_t, big, aligned>;
+using aligned_ubig32_t =
+ detail::packed_endian_specific_integral<uint32_t, big, aligned>;
+using aligned_ubig64_t =
+ detail::packed_endian_specific_integral<uint64_t, big, aligned>;
+
+using aligned_big16_t =
+ detail::packed_endian_specific_integral<int16_t, big, aligned>;
+using aligned_big32_t =
+ detail::packed_endian_specific_integral<int32_t, big, aligned>;
+using aligned_big64_t =
+ detail::packed_endian_specific_integral<int64_t, big, aligned>;
+
+using unaligned_uint16_t =
+ detail::packed_endian_specific_integral<uint16_t, native, unaligned>;
+using unaligned_uint32_t =
+ detail::packed_endian_specific_integral<uint32_t, native, unaligned>;
+using unaligned_uint64_t =
+ detail::packed_endian_specific_integral<uint64_t, native, unaligned>;
+
+using unaligned_int16_t =
+ detail::packed_endian_specific_integral<int16_t, native, unaligned>;
+using unaligned_int32_t =
+ detail::packed_endian_specific_integral<int32_t, native, unaligned>;
+using unaligned_int64_t =
+ detail::packed_endian_specific_integral<int64_t, native, unaligned>;
+
+template <typename T>
+using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
+template <typename T>
+using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
+
+template <typename T>
+using aligned_little_t =
+ detail::packed_endian_specific_integral<T, little, aligned>;
+template <typename T>
+using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
+
+namespace endian {
+
+template <typename T> inline T read(const void *P, endianness E) {
+ return read<T, unaligned>(P, E);
+}
+
+template <typename T, endianness E> inline T read(const void *P) {
+ return *(const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
+}
+
+inline uint16_t read16(const void *P, endianness E) {
+ return read<uint16_t>(P, E);
+}
+inline uint32_t read32(const void *P, endianness E) {
+ return read<uint32_t>(P, E);
+}
+inline uint64_t read64(const void *P, endianness E) {
+ return read<uint64_t>(P, E);
+}
+
+template <endianness E> inline uint16_t read16(const void *P) {
+ return read<uint16_t, E>(P);
+}
+template <endianness E> inline uint32_t read32(const void *P) {
+ return read<uint32_t, E>(P);
+}
+template <endianness E> inline uint64_t read64(const void *P) {
+ return read<uint64_t, E>(P);
+}
+
+inline uint16_t read16le(const void *P) { return read16<little>(P); }
+inline uint32_t read32le(const void *P) { return read32<little>(P); }
+inline uint64_t read64le(const void *P) { return read64<little>(P); }
+inline uint16_t read16be(const void *P) { return read16<big>(P); }
+inline uint32_t read32be(const void *P) { return read32<big>(P); }
+inline uint64_t read64be(const void *P) { return read64<big>(P); }
+
+template <typename T> inline void write(void *P, T V, endianness E) {
+ write<T, unaligned>(P, V, E);
+}
+
+template <typename T, endianness E> inline void write(void *P, T V) {
+ *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
+}
+
+inline void write16(void *P, uint16_t V, endianness E) {
+ write<uint16_t>(P, V, E);
+}
+inline void write32(void *P, uint32_t V, endianness E) {
+ write<uint32_t>(P, V, E);
+}
+inline void write64(void *P, uint64_t V, endianness E) {
+ write<uint64_t>(P, V, E);
+}
+
+template <endianness E> inline void write16(void *P, uint16_t V) {
+ write<uint16_t, E>(P, V);
+}
+template <endianness E> inline void write32(void *P, uint32_t V) {
+ write<uint32_t, E>(P, V);
+}
+template <endianness E> inline void write64(void *P, uint64_t V) {
+ write<uint64_t, E>(P, V);
+}
+
+inline void write16le(void *P, uint16_t V) { write16<little>(P, V); }
+inline void write32le(void *P, uint32_t V) { write32<little>(P, V); }
+inline void write64le(void *P, uint64_t V) { write64<little>(P, V); }
+inline void write16be(void *P, uint16_t V) { write16<big>(P, V); }
+inline void write32be(void *P, uint32_t V) { write32<big>(P, V); }
+inline void write64be(void *P, uint64_t V) { write64<big>(P, V); }
+
+} // end namespace endian
+
+} // end namespace support
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ENDIAN_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/EndianStream.h b/contrib/libs/llvm16/include/llvm/Support/EndianStream.h
new file mode 100644
index 00000000000..f21049677e9
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/EndianStream.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- EndianStream.h - Stream ops with endian specific data ----*- 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 defines utilities for operating on streams that have endian
+// specific data.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ENDIANSTREAM_H
+#define LLVM_SUPPORT_ENDIANSTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+namespace support {
+
+namespace endian {
+
+template <typename value_type>
+inline void write(raw_ostream &os, value_type value, endianness endian) {
+ value = byte_swap<value_type>(value, endian);
+ os.write((const char *)&value, sizeof(value_type));
+}
+
+template <>
+inline void write<float>(raw_ostream &os, float value, endianness endian) {
+ write(os, FloatToBits(value), endian);
+}
+
+template <>
+inline void write<double>(raw_ostream &os, double value,
+ endianness endian) {
+ write(os, DoubleToBits(value), endian);
+}
+
+template <typename value_type>
+inline void write(raw_ostream &os, ArrayRef<value_type> vals,
+ endianness endian) {
+ for (value_type v : vals)
+ write(os, v, endian);
+}
+
+/// Adapter to write values to a stream in a particular byte order.
+struct Writer {
+ raw_ostream &OS;
+ endianness Endian;
+ Writer(raw_ostream &OS, endianness Endian) : OS(OS), Endian(Endian) {}
+ template <typename value_type> void write(ArrayRef<value_type> Val) {
+ endian::write(OS, Val, Endian);
+ }
+ template <typename value_type> void write(value_type Val) {
+ endian::write(OS, Val, Endian);
+ }
+};
+
+} // end namespace endian
+
+} // end namespace support
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Errc.h b/contrib/libs/llvm16/include/llvm/Support/Errc.h
new file mode 100644
index 00000000000..dc8351073fe
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Errc.h
@@ -0,0 +1,97 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Errc.h - Defines the llvm::errc enum --------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// While std::error_code works OK on all platforms we use, there are some
+// some problems with std::errc that can be avoided by using our own
+// enumeration:
+//
+// * std::errc is a namespace in some implementations. That means that ADL
+// doesn't work and it is sometimes necessary to write std::make_error_code
+// or in templates:
+// using std::make_error_code;
+// make_error_code(...);
+//
+// with this enum it is safe to always just use make_error_code.
+//
+// * Some implementations define fewer names than others. This header has
+// the intersection of all the ones we support.
+//
+// * std::errc is just marked with is_error_condition_enum. This means that
+// common patterns like AnErrorCode == errc::no_such_file_or_directory take
+// 4 virtual calls instead of two comparisons.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERRC_H
+#define LLVM_SUPPORT_ERRC_H
+
+#include <system_error>
+
+namespace llvm {
+enum class errc {
+ argument_list_too_long = int(std::errc::argument_list_too_long),
+ argument_out_of_domain = int(std::errc::argument_out_of_domain),
+ bad_address = int(std::errc::bad_address),
+ bad_file_descriptor = int(std::errc::bad_file_descriptor),
+ broken_pipe = int(std::errc::broken_pipe),
+ device_or_resource_busy = int(std::errc::device_or_resource_busy),
+ directory_not_empty = int(std::errc::directory_not_empty),
+ executable_format_error = int(std::errc::executable_format_error),
+ file_exists = int(std::errc::file_exists),
+ file_too_large = int(std::errc::file_too_large),
+ filename_too_long = int(std::errc::filename_too_long),
+ function_not_supported = int(std::errc::function_not_supported),
+ illegal_byte_sequence = int(std::errc::illegal_byte_sequence),
+ inappropriate_io_control_operation =
+ int(std::errc::inappropriate_io_control_operation),
+ interrupted = int(std::errc::interrupted),
+ invalid_argument = int(std::errc::invalid_argument),
+ invalid_seek = int(std::errc::invalid_seek),
+ io_error = int(std::errc::io_error),
+ is_a_directory = int(std::errc::is_a_directory),
+ no_child_process = int(std::errc::no_child_process),
+ no_lock_available = int(std::errc::no_lock_available),
+ no_space_on_device = int(std::errc::no_space_on_device),
+ no_such_device_or_address = int(std::errc::no_such_device_or_address),
+ no_such_device = int(std::errc::no_such_device),
+ no_such_file_or_directory = int(std::errc::no_such_file_or_directory),
+ no_such_process = int(std::errc::no_such_process),
+ not_a_directory = int(std::errc::not_a_directory),
+ not_enough_memory = int(std::errc::not_enough_memory),
+ not_supported = int(std::errc::not_supported),
+ operation_not_permitted = int(std::errc::operation_not_permitted),
+ permission_denied = int(std::errc::permission_denied),
+ read_only_file_system = int(std::errc::read_only_file_system),
+ resource_deadlock_would_occur = int(std::errc::resource_deadlock_would_occur),
+ resource_unavailable_try_again =
+ int(std::errc::resource_unavailable_try_again),
+ result_out_of_range = int(std::errc::result_out_of_range),
+ too_many_files_open_in_system = int(std::errc::too_many_files_open_in_system),
+ too_many_files_open = int(std::errc::too_many_files_open),
+ too_many_links = int(std::errc::too_many_links)
+};
+
+inline std::error_code make_error_code(errc E) {
+ return std::error_code(static_cast<int>(E), std::generic_category());
+}
+}
+
+namespace std {
+template <> struct is_error_code_enum<llvm::errc> : std::true_type {};
+}
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Errno.h b/contrib/libs/llvm16/include/llvm/Support/Errno.h
new file mode 100644
index 00000000000..6e7fd797585
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Errno.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares some portable and convenient functions to deal with errno.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERRNO_H
+#define LLVM_SUPPORT_ERRNO_H
+
+#include <cerrno>
+#include <string>
+
+namespace llvm {
+namespace sys {
+
+/// Returns a string representation of the errno value, using whatever
+/// thread-safe variant of strerror() is available. Be sure to call this
+/// immediately after the function that set errno, or errno may have been
+/// overwritten by an intervening call.
+std::string StrError();
+
+/// Like the no-argument version above, but uses \p errnum instead of errno.
+std::string StrError(int errnum);
+
+template <typename FailT, typename Fun, typename... Args>
+inline decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F,
+ const Args &... As) {
+ decltype(F(As...)) Res;
+ do {
+ errno = 0;
+ Res = F(As...);
+ } while (Res == Fail && errno == EINTR);
+ return Res;
+}
+
+} // namespace sys
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_ERRNO_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Error.h b/contrib/libs/llvm16/include/llvm/Support/Error.h
new file mode 100644
index 00000000000..cc31f10df50
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Error.h
@@ -0,0 +1,1424 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Error.h - Recoverable error handling --------*- 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 defines an API used to report recoverable errors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERROR_H
+#define LLVM_SUPPORT_ERROR_H
+
+#include "llvm-c/Error.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/abi-breaking.h"
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <functional>
+#include <memory>
+#include <new>
+#include <optional>
+#include <string>
+#include <system_error>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+class ErrorSuccess;
+
+/// Base class for error info classes. Do not extend this directly: Extend
+/// the ErrorInfo template subclass instead.
+class ErrorInfoBase {
+public:
+ virtual ~ErrorInfoBase() = default;
+
+ /// Print an error message to an output stream.
+ virtual void log(raw_ostream &OS) const = 0;
+
+ /// Return the error message as a string.
+ virtual std::string message() const {
+ std::string Msg;
+ raw_string_ostream OS(Msg);
+ log(OS);
+ return OS.str();
+ }
+
+ /// Convert this error to a std::error_code.
+ ///
+ /// This is a temporary crutch to enable interaction with code still
+ /// using std::error_code. It will be removed in the future.
+ virtual std::error_code convertToErrorCode() const = 0;
+
+ // Returns the class ID for this type.
+ static const void *classID() { return &ID; }
+
+ // Returns the class ID for the dynamic type of this ErrorInfoBase instance.
+ virtual const void *dynamicClassID() const = 0;
+
+ // Check whether this instance is a subclass of the class identified by
+ // ClassID.
+ virtual bool isA(const void *const ClassID) const {
+ return ClassID == classID();
+ }
+
+ // Check whether this instance is a subclass of ErrorInfoT.
+ template <typename ErrorInfoT> bool isA() const {
+ return isA(ErrorInfoT::classID());
+ }
+
+private:
+ virtual void anchor();
+
+ static char ID;
+};
+
+/// Lightweight error class with error context and mandatory checking.
+///
+/// Instances of this class wrap a ErrorInfoBase pointer. Failure states
+/// are represented by setting the pointer to a ErrorInfoBase subclass
+/// instance containing information describing the failure. Success is
+/// represented by a null pointer value.
+///
+/// Instances of Error also contains a 'Checked' flag, which must be set
+/// before the destructor is called, otherwise the destructor will trigger a
+/// runtime error. This enforces at runtime the requirement that all Error
+/// instances be checked or returned to the caller.
+///
+/// There are two ways to set the checked flag, depending on what state the
+/// Error instance is in. For Error instances indicating success, it
+/// is sufficient to invoke the boolean conversion operator. E.g.:
+///
+/// @code{.cpp}
+/// Error foo(<...>);
+///
+/// if (auto E = foo(<...>))
+/// return E; // <- Return E if it is in the error state.
+/// // We have verified that E was in the success state. It can now be safely
+/// // destroyed.
+/// @endcode
+///
+/// A success value *can not* be dropped. For example, just calling 'foo(<...>)'
+/// without testing the return value will raise a runtime error, even if foo
+/// returns success.
+///
+/// For Error instances representing failure, you must use either the
+/// handleErrors or handleAllErrors function with a typed handler. E.g.:
+///
+/// @code{.cpp}
+/// class MyErrorInfo : public ErrorInfo<MyErrorInfo> {
+/// // Custom error info.
+/// };
+///
+/// Error foo(<...>) { return make_error<MyErrorInfo>(...); }
+///
+/// auto E = foo(<...>); // <- foo returns failure with MyErrorInfo.
+/// auto NewE =
+/// handleErrors(E,
+/// [](const MyErrorInfo &M) {
+/// // Deal with the error.
+/// },
+/// [](std::unique_ptr<OtherError> M) -> Error {
+/// if (canHandle(*M)) {
+/// // handle error.
+/// return Error::success();
+/// }
+/// // Couldn't handle this error instance. Pass it up the stack.
+/// return Error(std::move(M));
+/// );
+/// // Note - we must check or return NewE in case any of the handlers
+/// // returned a new error.
+/// @endcode
+///
+/// The handleAllErrors function is identical to handleErrors, except
+/// that it has a void return type, and requires all errors to be handled and
+/// no new errors be returned. It prevents errors (assuming they can all be
+/// handled) from having to be bubbled all the way to the top-level.
+///
+/// *All* Error instances must be checked before destruction, even if
+/// they're moved-assigned or constructed from Success values that have already
+/// been checked. This enforces checking through all levels of the call stack.
+class [[nodiscard]] Error {
+ // ErrorList needs to be able to yank ErrorInfoBase pointers out of Errors
+ // to add to the error list. It can't rely on handleErrors for this, since
+ // handleErrors does not support ErrorList handlers.
+ friend class ErrorList;
+
+ // handleErrors needs to be able to set the Checked flag.
+ template <typename... HandlerTs>
+ friend Error handleErrors(Error E, HandlerTs &&... Handlers);
+
+ // Expected<T> needs to be able to steal the payload when constructed from an
+ // error.
+ template <typename T> friend class Expected;
+
+ // wrap needs to be able to steal the payload.
+ friend LLVMErrorRef wrap(Error);
+
+protected:
+ /// Create a success value. Prefer using 'Error::success()' for readability
+ Error() {
+ setPtr(nullptr);
+ setChecked(false);
+ }
+
+public:
+ /// Create a success value.
+ static ErrorSuccess success();
+
+ // Errors are not copy-constructable.
+ Error(const Error &Other) = delete;
+
+ /// Move-construct an error value. The newly constructed error is considered
+ /// unchecked, even if the source error had been checked. The original error
+ /// becomes a checked Success value, regardless of its original state.
+ Error(Error &&Other) {
+ setChecked(true);
+ *this = std::move(Other);
+ }
+
+ /// Create an error value. Prefer using the 'make_error' function, but
+ /// this constructor can be useful when "re-throwing" errors from handlers.
+ Error(std::unique_ptr<ErrorInfoBase> Payload) {
+ setPtr(Payload.release());
+ setChecked(false);
+ }
+
+ // Errors are not copy-assignable.
+ Error &operator=(const Error &Other) = delete;
+
+ /// Move-assign an error value. The current error must represent success, you
+ /// you cannot overwrite an unhandled error. The current error is then
+ /// considered unchecked. The source error becomes a checked success value,
+ /// regardless of its original state.
+ Error &operator=(Error &&Other) {
+ // Don't allow overwriting of unchecked values.
+ assertIsChecked();
+ setPtr(Other.getPtr());
+
+ // This Error is unchecked, even if the source error was checked.
+ setChecked(false);
+
+ // Null out Other's payload and set its checked bit.
+ Other.setPtr(nullptr);
+ Other.setChecked(true);
+
+ return *this;
+ }
+
+ /// Destroy a Error. Fails with a call to abort() if the error is
+ /// unchecked.
+ ~Error() {
+ assertIsChecked();
+ delete getPtr();
+ }
+
+ /// Bool conversion. Returns true if this Error is in a failure state,
+ /// and false if it is in an accept state. If the error is in a Success state
+ /// it will be considered checked.
+ explicit operator bool() {
+ setChecked(getPtr() == nullptr);
+ return getPtr() != nullptr;
+ }
+
+ /// Check whether one error is a subclass of another.
+ template <typename ErrT> bool isA() const {
+ return getPtr() && getPtr()->isA(ErrT::classID());
+ }
+
+ /// Returns the dynamic class id of this error, or null if this is a success
+ /// value.
+ const void* dynamicClassID() const {
+ if (!getPtr())
+ return nullptr;
+ return getPtr()->dynamicClassID();
+ }
+
+private:
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ // assertIsChecked() happens very frequently, but under normal circumstances
+ // is supposed to be a no-op. So we want it to be inlined, but having a bunch
+ // of debug prints can cause the function to be too large for inlining. So
+ // it's important that we define this function out of line so that it can't be
+ // inlined.
+ [[noreturn]] void fatalUncheckedError() const;
+#endif
+
+ void assertIsChecked() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ if (LLVM_UNLIKELY(!getChecked() || getPtr()))
+ fatalUncheckedError();
+#endif
+ }
+
+ ErrorInfoBase *getPtr() const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ return reinterpret_cast<ErrorInfoBase*>(
+ reinterpret_cast<uintptr_t>(Payload) &
+ ~static_cast<uintptr_t>(0x1));
+#else
+ return Payload;
+#endif
+ }
+
+ void setPtr(ErrorInfoBase *EI) {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ Payload = reinterpret_cast<ErrorInfoBase*>(
+ (reinterpret_cast<uintptr_t>(EI) &
+ ~static_cast<uintptr_t>(0x1)) |
+ (reinterpret_cast<uintptr_t>(Payload) & 0x1));
+#else
+ Payload = EI;
+#endif
+ }
+
+ bool getChecked() const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ return (reinterpret_cast<uintptr_t>(Payload) & 0x1) == 0;
+#else
+ return true;
+#endif
+ }
+
+ void setChecked(bool V) {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ Payload = reinterpret_cast<ErrorInfoBase*>(
+ (reinterpret_cast<uintptr_t>(Payload) &
+ ~static_cast<uintptr_t>(0x1)) |
+ (V ? 0 : 1));
+#endif
+ }
+
+ std::unique_ptr<ErrorInfoBase> takePayload() {
+ std::unique_ptr<ErrorInfoBase> Tmp(getPtr());
+ setPtr(nullptr);
+ setChecked(true);
+ return Tmp;
+ }
+
+ friend raw_ostream &operator<<(raw_ostream &OS, const Error &E) {
+ if (auto *P = E.getPtr())
+ P->log(OS);
+ else
+ OS << "success";
+ return OS;
+ }
+
+ ErrorInfoBase *Payload = nullptr;
+};
+
+/// Subclass of Error for the sole purpose of identifying the success path in
+/// the type system. This allows to catch invalid conversion to Expected<T> at
+/// compile time.
+class ErrorSuccess final : public Error {};
+
+inline ErrorSuccess Error::success() { return ErrorSuccess(); }
+
+/// Make a Error instance representing failure using the given error info
+/// type.
+template <typename ErrT, typename... ArgTs> Error make_error(ArgTs &&... Args) {
+ return Error(std::make_unique<ErrT>(std::forward<ArgTs>(Args)...));
+}
+
+/// Base class for user error types. Users should declare their error types
+/// like:
+///
+/// class MyError : public ErrorInfo<MyError> {
+/// ....
+/// };
+///
+/// This class provides an implementation of the ErrorInfoBase::kind
+/// method, which is used by the Error RTTI system.
+template <typename ThisErrT, typename ParentErrT = ErrorInfoBase>
+class ErrorInfo : public ParentErrT {
+public:
+ using ParentErrT::ParentErrT; // inherit constructors
+
+ static const void *classID() { return &ThisErrT::ID; }
+
+ const void *dynamicClassID() const override { return &ThisErrT::ID; }
+
+ bool isA(const void *const ClassID) const override {
+ return ClassID == classID() || ParentErrT::isA(ClassID);
+ }
+};
+
+/// Special ErrorInfo subclass representing a list of ErrorInfos.
+/// Instances of this class are constructed by joinError.
+class ErrorList final : public ErrorInfo<ErrorList> {
+ // handleErrors needs to be able to iterate the payload list of an
+ // ErrorList.
+ template <typename... HandlerTs>
+ friend Error handleErrors(Error E, HandlerTs &&... Handlers);
+
+ // joinErrors is implemented in terms of join.
+ friend Error joinErrors(Error, Error);
+
+public:
+ void log(raw_ostream &OS) const override {
+ OS << "Multiple errors:\n";
+ for (const auto &ErrPayload : Payloads) {
+ ErrPayload->log(OS);
+ OS << "\n";
+ }
+ }
+
+ std::error_code convertToErrorCode() const override;
+
+ // Used by ErrorInfo::classID.
+ static char ID;
+
+private:
+ ErrorList(std::unique_ptr<ErrorInfoBase> Payload1,
+ std::unique_ptr<ErrorInfoBase> Payload2) {
+ assert(!Payload1->isA<ErrorList>() && !Payload2->isA<ErrorList>() &&
+ "ErrorList constructor payloads should be singleton errors");
+ Payloads.push_back(std::move(Payload1));
+ Payloads.push_back(std::move(Payload2));
+ }
+
+ static Error join(Error E1, Error E2) {
+ if (!E1)
+ return E2;
+ if (!E2)
+ return E1;
+ if (E1.isA<ErrorList>()) {
+ auto &E1List = static_cast<ErrorList &>(*E1.getPtr());
+ if (E2.isA<ErrorList>()) {
+ auto E2Payload = E2.takePayload();
+ auto &E2List = static_cast<ErrorList &>(*E2Payload);
+ for (auto &Payload : E2List.Payloads)
+ E1List.Payloads.push_back(std::move(Payload));
+ } else
+ E1List.Payloads.push_back(E2.takePayload());
+
+ return E1;
+ }
+ if (E2.isA<ErrorList>()) {
+ auto &E2List = static_cast<ErrorList &>(*E2.getPtr());
+ E2List.Payloads.insert(E2List.Payloads.begin(), E1.takePayload());
+ return E2;
+ }
+ return Error(std::unique_ptr<ErrorList>(
+ new ErrorList(E1.takePayload(), E2.takePayload())));
+ }
+
+ std::vector<std::unique_ptr<ErrorInfoBase>> Payloads;
+};
+
+/// Concatenate errors. The resulting Error is unchecked, and contains the
+/// ErrorInfo(s), if any, contained in E1, followed by the
+/// ErrorInfo(s), if any, contained in E2.
+inline Error joinErrors(Error E1, Error E2) {
+ return ErrorList::join(std::move(E1), std::move(E2));
+}
+
+/// Tagged union holding either a T or a Error.
+///
+/// This class parallels ErrorOr, but replaces error_code with Error. Since
+/// Error cannot be copied, this class replaces getError() with
+/// takeError(). It also adds an bool errorIsA<ErrT>() method for testing the
+/// error class type.
+///
+/// Example usage of 'Expected<T>' as a function return type:
+///
+/// @code{.cpp}
+/// Expected<int> myDivide(int A, int B) {
+/// if (B == 0) {
+/// // return an Error
+/// return createStringError(inconvertibleErrorCode(),
+/// "B must not be zero!");
+/// }
+/// // return an integer
+/// return A / B;
+/// }
+/// @endcode
+///
+/// Checking the results of to a function returning 'Expected<T>':
+/// @code{.cpp}
+/// if (auto E = Result.takeError()) {
+/// // We must consume the error. Typically one of:
+/// // - return the error to our caller
+/// // - toString(), when logging
+/// // - consumeError(), to silently swallow the error
+/// // - handleErrors(), to distinguish error types
+/// errs() << "Problem with division " << toString(std::move(E)) << "\n";
+/// return;
+/// }
+/// // use the result
+/// outs() << "The answer is " << *Result << "\n";
+/// @endcode
+///
+/// For unit-testing a function returning an 'Expected<T>', see the
+/// 'EXPECT_THAT_EXPECTED' macros in llvm/Testing/Support/Error.h
+
+template <class T> class [[nodiscard]] Expected {
+ template <class T1> friend class ExpectedAsOutParameter;
+ template <class OtherT> friend class Expected;
+
+ static constexpr bool isRef = std::is_reference<T>::value;
+
+ using wrap = std::reference_wrapper<std::remove_reference_t<T>>;
+
+ using error_type = std::unique_ptr<ErrorInfoBase>;
+
+public:
+ using storage_type = std::conditional_t<isRef, wrap, T>;
+ using value_type = T;
+
+private:
+ using reference = std::remove_reference_t<T> &;
+ using const_reference = const std::remove_reference_t<T> &;
+ using pointer = std::remove_reference_t<T> *;
+ using const_pointer = const std::remove_reference_t<T> *;
+
+public:
+ /// Create an Expected<T> error value from the given Error.
+ Expected(Error Err)
+ : HasError(true)
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ // Expected is unchecked upon construction in Debug builds.
+ , Unchecked(true)
+#endif
+ {
+ assert(Err && "Cannot create Expected<T> from Error success value.");
+ new (getErrorStorage()) error_type(Err.takePayload());
+ }
+
+ /// Forbid to convert from Error::success() implicitly, this avoids having
+ /// Expected<T> foo() { return Error::success(); } which compiles otherwise
+ /// but triggers the assertion above.
+ Expected(ErrorSuccess) = delete;
+
+ /// Create an Expected<T> success value from the given OtherT value, which
+ /// must be convertible to T.
+ template <typename OtherT>
+ Expected(OtherT &&Val,
+ std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr)
+ : HasError(false)
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ // Expected is unchecked upon construction in Debug builds.
+ ,
+ Unchecked(true)
+#endif
+ {
+ new (getStorage()) storage_type(std::forward<OtherT>(Val));
+ }
+
+ /// Move construct an Expected<T> value.
+ Expected(Expected &&Other) { moveConstruct(std::move(Other)); }
+
+ /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
+ /// must be convertible to T.
+ template <class OtherT>
+ Expected(Expected<OtherT> &&Other,
+ std::enable_if_t<std::is_convertible_v<OtherT, T>> * = nullptr) {
+ moveConstruct(std::move(Other));
+ }
+
+ /// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
+ /// isn't convertible to T.
+ template <class OtherT>
+ explicit Expected(
+ Expected<OtherT> &&Other,
+ std::enable_if_t<!std::is_convertible_v<OtherT, T>> * = nullptr) {
+ moveConstruct(std::move(Other));
+ }
+
+ /// Move-assign from another Expected<T>.
+ Expected &operator=(Expected &&Other) {
+ moveAssign(std::move(Other));
+ return *this;
+ }
+
+ /// Destroy an Expected<T>.
+ ~Expected() {
+ assertIsChecked();
+ if (!HasError)
+ getStorage()->~storage_type();
+ else
+ getErrorStorage()->~error_type();
+ }
+
+ /// Return false if there is an error.
+ explicit operator bool() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ Unchecked = HasError;
+#endif
+ return !HasError;
+ }
+
+ /// Returns a reference to the stored T value.
+ reference get() {
+ assertIsChecked();
+ return *getStorage();
+ }
+
+ /// Returns a const reference to the stored T value.
+ const_reference get() const {
+ assertIsChecked();
+ return const_cast<Expected<T> *>(this)->get();
+ }
+
+ /// Returns \a takeError() after moving the held T (if any) into \p V.
+ template <class OtherT>
+ Error moveInto(OtherT &Value,
+ std::enable_if_t<std::is_assignable<OtherT &, T &&>::value> * =
+ nullptr) && {
+ if (*this)
+ Value = std::move(get());
+ return takeError();
+ }
+
+ /// Check that this Expected<T> is an error of type ErrT.
+ template <typename ErrT> bool errorIsA() const {
+ return HasError && (*getErrorStorage())->template isA<ErrT>();
+ }
+
+ /// Take ownership of the stored error.
+ /// After calling this the Expected<T> is in an indeterminate state that can
+ /// only be safely destructed. No further calls (beside the destructor) should
+ /// be made on the Expected<T> value.
+ Error takeError() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ Unchecked = false;
+#endif
+ return HasError ? Error(std::move(*getErrorStorage())) : Error::success();
+ }
+
+ /// Returns a pointer to the stored T value.
+ pointer operator->() {
+ assertIsChecked();
+ return toPointer(getStorage());
+ }
+
+ /// Returns a const pointer to the stored T value.
+ const_pointer operator->() const {
+ assertIsChecked();
+ return toPointer(getStorage());
+ }
+
+ /// Returns a reference to the stored T value.
+ reference operator*() {
+ assertIsChecked();
+ return *getStorage();
+ }
+
+ /// Returns a const reference to the stored T value.
+ const_reference operator*() const {
+ assertIsChecked();
+ return *getStorage();
+ }
+
+private:
+ template <class T1>
+ static bool compareThisIfSameType(const T1 &a, const T1 &b) {
+ return &a == &b;
+ }
+
+ template <class T1, class T2>
+ static bool compareThisIfSameType(const T1 &, const T2 &) {
+ return false;
+ }
+
+ template <class OtherT> void moveConstruct(Expected<OtherT> &&Other) {
+ HasError = Other.HasError;
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ Unchecked = true;
+ Other.Unchecked = false;
+#endif
+
+ if (!HasError)
+ new (getStorage()) storage_type(std::move(*Other.getStorage()));
+ else
+ new (getErrorStorage()) error_type(std::move(*Other.getErrorStorage()));
+ }
+
+ template <class OtherT> void moveAssign(Expected<OtherT> &&Other) {
+ assertIsChecked();
+
+ if (compareThisIfSameType(*this, Other))
+ return;
+
+ this->~Expected();
+ new (this) Expected(std::move(Other));
+ }
+
+ pointer toPointer(pointer Val) { return Val; }
+
+ const_pointer toPointer(const_pointer Val) const { return Val; }
+
+ pointer toPointer(wrap *Val) { return &Val->get(); }
+
+ const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
+
+ storage_type *getStorage() {
+ assert(!HasError && "Cannot get value when an error exists!");
+ return reinterpret_cast<storage_type *>(&TStorage);
+ }
+
+ const storage_type *getStorage() const {
+ assert(!HasError && "Cannot get value when an error exists!");
+ return reinterpret_cast<const storage_type *>(&TStorage);
+ }
+
+ error_type *getErrorStorage() {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<error_type *>(&ErrorStorage);
+ }
+
+ const error_type *getErrorStorage() const {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<const error_type *>(&ErrorStorage);
+ }
+
+ // Used by ExpectedAsOutParameter to reset the checked flag.
+ void setUnchecked() {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ Unchecked = true;
+#endif
+ }
+
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ [[noreturn]] LLVM_ATTRIBUTE_NOINLINE void fatalUncheckedExpected() const {
+ dbgs() << "Expected<T> must be checked before access or destruction.\n";
+ if (HasError) {
+ dbgs() << "Unchecked Expected<T> contained error:\n";
+ (*getErrorStorage())->log(dbgs());
+ } else
+ dbgs() << "Expected<T> value was in success state. (Note: Expected<T> "
+ "values in success mode must still be checked prior to being "
+ "destroyed).\n";
+ abort();
+ }
+#endif
+
+ void assertIsChecked() const {
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ if (LLVM_UNLIKELY(Unchecked))
+ fatalUncheckedExpected();
+#endif
+ }
+
+ union {
+ AlignedCharArrayUnion<storage_type> TStorage;
+ AlignedCharArrayUnion<error_type> ErrorStorage;
+ };
+ bool HasError : 1;
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS
+ bool Unchecked : 1;
+#endif
+};
+
+/// Report a serious error, calling any installed error handler. See
+/// ErrorHandling.h.
+[[noreturn]] void report_fatal_error(Error Err, bool gen_crash_diag = true);
+
+/// Report a fatal error if Err is a failure value.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+/// @code{.cpp}
+/// // foo only attempts the fallible operation if DoFallibleOperation is
+/// // true. If DoFallibleOperation is false then foo always returns
+/// // Error::success().
+/// Error foo(bool DoFallibleOperation);
+///
+/// cantFail(foo(false));
+/// @endcode
+inline void cantFail(Error Err, const char *Msg = nullptr) {
+ if (Err) {
+ if (!Msg)
+ Msg = "Failure value returned from cantFail wrapped call";
+#ifndef NDEBUG
+ std::string Str;
+ raw_string_ostream OS(Str);
+ OS << Msg << "\n" << Err;
+ Msg = OS.str().c_str();
+#endif
+ llvm_unreachable(Msg);
+ }
+}
+
+/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
+/// returns the contained value.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+/// @code{.cpp}
+/// // foo only attempts the fallible operation if DoFallibleOperation is
+/// // true. If DoFallibleOperation is false then foo always returns an int.
+/// Expected<int> foo(bool DoFallibleOperation);
+///
+/// int X = cantFail(foo(false));
+/// @endcode
+template <typename T>
+T cantFail(Expected<T> ValOrErr, const char *Msg = nullptr) {
+ if (ValOrErr)
+ return std::move(*ValOrErr);
+ else {
+ if (!Msg)
+ Msg = "Failure value returned from cantFail wrapped call";
+#ifndef NDEBUG
+ std::string Str;
+ raw_string_ostream OS(Str);
+ auto E = ValOrErr.takeError();
+ OS << Msg << "\n" << E;
+ Msg = OS.str().c_str();
+#endif
+ llvm_unreachable(Msg);
+ }
+}
+
+/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and
+/// returns the contained reference.
+///
+/// This function can be used to wrap calls to fallible functions ONLY when it
+/// is known that the Error will always be a success value. E.g.
+///
+/// @code{.cpp}
+/// // foo only attempts the fallible operation if DoFallibleOperation is
+/// // true. If DoFallibleOperation is false then foo always returns a Bar&.
+/// Expected<Bar&> foo(bool DoFallibleOperation);
+///
+/// Bar &X = cantFail(foo(false));
+/// @endcode
+template <typename T>
+T& cantFail(Expected<T&> ValOrErr, const char *Msg = nullptr) {
+ if (ValOrErr)
+ return *ValOrErr;
+ else {
+ if (!Msg)
+ Msg = "Failure value returned from cantFail wrapped call";
+#ifndef NDEBUG
+ std::string Str;
+ raw_string_ostream OS(Str);
+ auto E = ValOrErr.takeError();
+ OS << Msg << "\n" << E;
+ Msg = OS.str().c_str();
+#endif
+ llvm_unreachable(Msg);
+ }
+}
+
+/// Helper for testing applicability of, and applying, handlers for
+/// ErrorInfo types.
+template <typename HandlerT>
+class ErrorHandlerTraits
+ : public ErrorHandlerTraits<
+ decltype(&std::remove_reference_t<HandlerT>::operator())> {};
+
+// Specialization functions of the form 'Error (const ErrT&)'.
+template <typename ErrT> class ErrorHandlerTraits<Error (&)(ErrT &)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ return H(static_cast<ErrT &>(*E));
+ }
+};
+
+// Specialization functions of the form 'void (const ErrT&)'.
+template <typename ErrT> class ErrorHandlerTraits<void (&)(ErrT &)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ H(static_cast<ErrT &>(*E));
+ return Error::success();
+ }
+};
+
+/// Specialization for functions of the form 'Error (std::unique_ptr<ErrT>)'.
+template <typename ErrT>
+class ErrorHandlerTraits<Error (&)(std::unique_ptr<ErrT>)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
+ return H(std::move(SubE));
+ }
+};
+
+/// Specialization for functions of the form 'void (std::unique_ptr<ErrT>)'.
+template <typename ErrT>
+class ErrorHandlerTraits<void (&)(std::unique_ptr<ErrT>)> {
+public:
+ static bool appliesTo(const ErrorInfoBase &E) {
+ return E.template isA<ErrT>();
+ }
+
+ template <typename HandlerT>
+ static Error apply(HandlerT &&H, std::unique_ptr<ErrorInfoBase> E) {
+ assert(appliesTo(*E) && "Applying incorrect handler");
+ std::unique_ptr<ErrT> SubE(static_cast<ErrT *>(E.release()));
+ H(std::move(SubE));
+ return Error::success();
+ }
+};
+
+// Specialization for member functions of the form 'RetT (const ErrT&)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(ErrT &)>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(ErrT &) const>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(const ErrT &)>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+// Specialization for member functions of the form 'RetT (const ErrT&) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(const ErrT &) const>
+ : public ErrorHandlerTraits<RetT (&)(ErrT &)> {};
+
+/// Specialization for member functions of the form
+/// 'RetT (std::unique_ptr<ErrT>)'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>)>
+ : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
+
+/// Specialization for member functions of the form
+/// 'RetT (std::unique_ptr<ErrT>) const'.
+template <typename C, typename RetT, typename ErrT>
+class ErrorHandlerTraits<RetT (C::*)(std::unique_ptr<ErrT>) const>
+ : public ErrorHandlerTraits<RetT (&)(std::unique_ptr<ErrT>)> {};
+
+inline Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload) {
+ return Error(std::move(Payload));
+}
+
+template <typename HandlerT, typename... HandlerTs>
+Error handleErrorImpl(std::unique_ptr<ErrorInfoBase> Payload,
+ HandlerT &&Handler, HandlerTs &&... Handlers) {
+ if (ErrorHandlerTraits<HandlerT>::appliesTo(*Payload))
+ return ErrorHandlerTraits<HandlerT>::apply(std::forward<HandlerT>(Handler),
+ std::move(Payload));
+ return handleErrorImpl(std::move(Payload),
+ std::forward<HandlerTs>(Handlers)...);
+}
+
+/// Pass the ErrorInfo(s) contained in E to their respective handlers. Any
+/// unhandled errors (or Errors returned by handlers) are re-concatenated and
+/// returned.
+/// Because this function returns an error, its result must also be checked
+/// or returned. If you intend to handle all errors use handleAllErrors
+/// (which returns void, and will abort() on unhandled errors) instead.
+template <typename... HandlerTs>
+Error handleErrors(Error E, HandlerTs &&... Hs) {
+ if (!E)
+ return Error::success();
+
+ std::unique_ptr<ErrorInfoBase> Payload = E.takePayload();
+
+ if (Payload->isA<ErrorList>()) {
+ ErrorList &List = static_cast<ErrorList &>(*Payload);
+ Error R;
+ for (auto &P : List.Payloads)
+ R = ErrorList::join(
+ std::move(R),
+ handleErrorImpl(std::move(P), std::forward<HandlerTs>(Hs)...));
+ return R;
+ }
+
+ return handleErrorImpl(std::move(Payload), std::forward<HandlerTs>(Hs)...);
+}
+
+/// Behaves the same as handleErrors, except that by contract all errors
+/// *must* be handled by the given handlers (i.e. there must be no remaining
+/// errors after running the handlers, or llvm_unreachable is called).
+template <typename... HandlerTs>
+void handleAllErrors(Error E, HandlerTs &&... Handlers) {
+ cantFail(handleErrors(std::move(E), std::forward<HandlerTs>(Handlers)...));
+}
+
+/// Check that E is a non-error, then drop it.
+/// If E is an error, llvm_unreachable will be called.
+inline void handleAllErrors(Error E) {
+ cantFail(std::move(E));
+}
+
+/// Handle any errors (if present) in an Expected<T>, then try a recovery path.
+///
+/// If the incoming value is a success value it is returned unmodified. If it
+/// is a failure value then it the contained error is passed to handleErrors.
+/// If handleErrors is able to handle the error then the RecoveryPath functor
+/// is called to supply the final result. If handleErrors is not able to
+/// handle all errors then the unhandled errors are returned.
+///
+/// This utility enables the follow pattern:
+///
+/// @code{.cpp}
+/// enum FooStrategy { Aggressive, Conservative };
+/// Expected<Foo> foo(FooStrategy S);
+///
+/// auto ResultOrErr =
+/// handleExpected(
+/// foo(Aggressive),
+/// []() { return foo(Conservative); },
+/// [](AggressiveStrategyError&) {
+/// // Implicitly conusme this - we'll recover by using a conservative
+/// // strategy.
+/// });
+///
+/// @endcode
+template <typename T, typename RecoveryFtor, typename... HandlerTs>
+Expected<T> handleExpected(Expected<T> ValOrErr, RecoveryFtor &&RecoveryPath,
+ HandlerTs &&... Handlers) {
+ if (ValOrErr)
+ return ValOrErr;
+
+ if (auto Err = handleErrors(ValOrErr.takeError(),
+ std::forward<HandlerTs>(Handlers)...))
+ return std::move(Err);
+
+ return RecoveryPath();
+}
+
+/// Log all errors (if any) in E to OS. If there are any errors, ErrorBanner
+/// will be printed before the first one is logged. A newline will be printed
+/// after each error.
+///
+/// This function is compatible with the helpers from Support/WithColor.h. You
+/// can pass any of them as the OS. Please consider using them instead of
+/// including 'error: ' in the ErrorBanner.
+///
+/// This is useful in the base level of your program to allow clean termination
+/// (allowing clean deallocation of resources, etc.), while reporting error
+/// information to the user.
+void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner = {});
+
+/// Write all error messages (if any) in E to a string. The newline character
+/// is used to separate error messages.
+inline std::string toString(Error E) {
+ SmallVector<std::string, 2> Errors;
+ handleAllErrors(std::move(E), [&Errors](const ErrorInfoBase &EI) {
+ Errors.push_back(EI.message());
+ });
+ return join(Errors.begin(), Errors.end(), "\n");
+}
+
+/// Consume a Error without doing anything. This method should be used
+/// only where an error can be considered a reasonable and expected return
+/// value.
+///
+/// Uses of this method are potentially indicative of design problems: If it's
+/// legitimate to do nothing while processing an "error", the error-producer
+/// might be more clearly refactored to return an std::optional<T>.
+inline void consumeError(Error Err) {
+ handleAllErrors(std::move(Err), [](const ErrorInfoBase &) {});
+}
+
+/// Convert an Expected to an Optional without doing anything. This method
+/// should be used only where an error can be considered a reasonable and
+/// expected return value.
+///
+/// Uses of this method are potentially indicative of problems: perhaps the
+/// error should be propagated further, or the error-producer should just
+/// return an Optional in the first place.
+template <typename T> std::optional<T> expectedToOptional(Expected<T> &&E) {
+ if (E)
+ return std::move(*E);
+ consumeError(E.takeError());
+ return std::nullopt;
+}
+
+template <typename T> std::optional<T> expectedToStdOptional(Expected<T> &&E) {
+ if (E)
+ return std::move(*E);
+ consumeError(E.takeError());
+ return std::nullopt;
+}
+
+/// Helper for converting an Error to a bool.
+///
+/// This method returns true if Err is in an error state, or false if it is
+/// in a success state. Puts Err in a checked state in both cases (unlike
+/// Error::operator bool(), which only does this for success states).
+inline bool errorToBool(Error Err) {
+ bool IsError = static_cast<bool>(Err);
+ if (IsError)
+ consumeError(std::move(Err));
+ return IsError;
+}
+
+/// Helper for Errors used as out-parameters.
+///
+/// This helper is for use with the Error-as-out-parameter idiom, where an error
+/// is passed to a function or method by reference, rather than being returned.
+/// In such cases it is helpful to set the checked bit on entry to the function
+/// so that the error can be written to (unchecked Errors abort on assignment)
+/// and clear the checked bit on exit so that clients cannot accidentally forget
+/// to check the result. This helper performs these actions automatically using
+/// RAII:
+///
+/// @code{.cpp}
+/// Result foo(Error &Err) {
+/// ErrorAsOutParameter ErrAsOutParam(&Err); // 'Checked' flag set
+/// // <body of foo>
+/// // <- 'Checked' flag auto-cleared when ErrAsOutParam is destructed.
+/// }
+/// @endcode
+///
+/// ErrorAsOutParameter takes an Error* rather than Error& so that it can be
+/// used with optional Errors (Error pointers that are allowed to be null). If
+/// ErrorAsOutParameter took an Error reference, an instance would have to be
+/// created inside every condition that verified that Error was non-null. By
+/// taking an Error pointer we can just create one instance at the top of the
+/// function.
+class ErrorAsOutParameter {
+public:
+ ErrorAsOutParameter(Error *Err) : Err(Err) {
+ // Raise the checked bit if Err is success.
+ if (Err)
+ (void)!!*Err;
+ }
+
+ ~ErrorAsOutParameter() {
+ // Clear the checked bit.
+ if (Err && !*Err)
+ *Err = Error::success();
+ }
+
+private:
+ Error *Err;
+};
+
+/// Helper for Expected<T>s used as out-parameters.
+///
+/// See ErrorAsOutParameter.
+template <typename T>
+class ExpectedAsOutParameter {
+public:
+ ExpectedAsOutParameter(Expected<T> *ValOrErr)
+ : ValOrErr(ValOrErr) {
+ if (ValOrErr)
+ (void)!!*ValOrErr;
+ }
+
+ ~ExpectedAsOutParameter() {
+ if (ValOrErr)
+ ValOrErr->setUnchecked();
+ }
+
+private:
+ Expected<T> *ValOrErr;
+};
+
+/// This class wraps a std::error_code in a Error.
+///
+/// This is useful if you're writing an interface that returns a Error
+/// (or Expected) and you want to call code that still returns
+/// std::error_codes.
+class ECError : public ErrorInfo<ECError> {
+ friend Error errorCodeToError(std::error_code);
+
+ void anchor() override;
+
+public:
+ void setErrorCode(std::error_code EC) { this->EC = EC; }
+ std::error_code convertToErrorCode() const override { return EC; }
+ void log(raw_ostream &OS) const override { OS << EC.message(); }
+
+ // Used by ErrorInfo::classID.
+ static char ID;
+
+protected:
+ ECError() = default;
+ ECError(std::error_code EC) : EC(EC) {}
+
+ std::error_code EC;
+};
+
+/// The value returned by this function can be returned from convertToErrorCode
+/// for Error values where no sensible translation to std::error_code exists.
+/// It should only be used in this situation, and should never be used where a
+/// sensible conversion to std::error_code is available, as attempts to convert
+/// to/from this error will result in a fatal error. (i.e. it is a programmatic
+/// error to try to convert such a value).
+std::error_code inconvertibleErrorCode();
+
+/// Helper for converting an std::error_code to a Error.
+Error errorCodeToError(std::error_code EC);
+
+/// Helper for converting an ECError to a std::error_code.
+///
+/// This method requires that Err be Error() or an ECError, otherwise it
+/// will trigger a call to abort().
+std::error_code errorToErrorCode(Error Err);
+
+/// Convert an ErrorOr<T> to an Expected<T>.
+template <typename T> Expected<T> errorOrToExpected(ErrorOr<T> &&EO) {
+ if (auto EC = EO.getError())
+ return errorCodeToError(EC);
+ return std::move(*EO);
+}
+
+/// Convert an Expected<T> to an ErrorOr<T>.
+template <typename T> ErrorOr<T> expectedToErrorOr(Expected<T> &&E) {
+ if (auto Err = E.takeError())
+ return errorToErrorCode(std::move(Err));
+ return std::move(*E);
+}
+
+/// This class wraps a string in an Error.
+///
+/// StringError is useful in cases where the client is not expected to be able
+/// to consume the specific error message programmatically (for example, if the
+/// error message is to be presented to the user).
+///
+/// StringError can also be used when additional information is to be printed
+/// along with a error_code message. Depending on the constructor called, this
+/// class can either display:
+/// 1. the error_code message (ECError behavior)
+/// 2. a string
+/// 3. the error_code message and a string
+///
+/// These behaviors are useful when subtyping is required; for example, when a
+/// specific library needs an explicit error type. In the example below,
+/// PDBError is derived from StringError:
+///
+/// @code{.cpp}
+/// Expected<int> foo() {
+/// return llvm::make_error<PDBError>(pdb_error_code::dia_failed_loading,
+/// "Additional information");
+/// }
+/// @endcode
+///
+class StringError : public ErrorInfo<StringError> {
+public:
+ static char ID;
+
+ // Prints EC + S and converts to EC
+ StringError(std::error_code EC, const Twine &S = Twine());
+
+ // Prints S and converts to EC
+ StringError(const Twine &S, std::error_code EC);
+
+ void log(raw_ostream &OS) const override;
+ std::error_code convertToErrorCode() const override;
+
+ const std::string &getMessage() const { return Msg; }
+
+private:
+ std::string Msg;
+ std::error_code EC;
+ const bool PrintMsgOnly = false;
+};
+
+/// Create formatted StringError object.
+template <typename... Ts>
+inline Error createStringError(std::error_code EC, char const *Fmt,
+ const Ts &... Vals) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ return make_error<StringError>(Stream.str(), EC);
+}
+
+Error createStringError(std::error_code EC, char const *Msg);
+
+inline Error createStringError(std::error_code EC, const Twine &S) {
+ return createStringError(EC, S.str().c_str());
+}
+
+template <typename... Ts>
+inline Error createStringError(std::errc EC, char const *Fmt,
+ const Ts &... Vals) {
+ return createStringError(std::make_error_code(EC), Fmt, Vals...);
+}
+
+/// This class wraps a filename and another Error.
+///
+/// In some cases, an error needs to live along a 'source' name, in order to
+/// show more detailed information to the user.
+class FileError final : public ErrorInfo<FileError> {
+
+ friend Error createFileError(const Twine &, Error);
+ friend Error createFileError(const Twine &, size_t, Error);
+
+public:
+ void log(raw_ostream &OS) const override {
+ assert(Err && "Trying to log after takeError().");
+ OS << "'" << FileName << "': ";
+ if (Line)
+ OS << "line " << *Line << ": ";
+ Err->log(OS);
+ }
+
+ std::string messageWithoutFileInfo() const {
+ std::string Msg;
+ raw_string_ostream OS(Msg);
+ Err->log(OS);
+ return OS.str();
+ }
+
+ StringRef getFileName() const { return FileName; }
+
+ Error takeError() { return Error(std::move(Err)); }
+
+ std::error_code convertToErrorCode() const override;
+
+ // Used by ErrorInfo::classID.
+ static char ID;
+
+private:
+ FileError(const Twine &F, std::optional<size_t> LineNum,
+ std::unique_ptr<ErrorInfoBase> E) {
+ assert(E && "Cannot create FileError from Error success value.");
+ FileName = F.str();
+ Err = std::move(E);
+ Line = std::move(LineNum);
+ }
+
+ static Error build(const Twine &F, std::optional<size_t> Line, Error E) {
+ std::unique_ptr<ErrorInfoBase> Payload;
+ handleAllErrors(std::move(E),
+ [&](std::unique_ptr<ErrorInfoBase> EIB) -> Error {
+ Payload = std::move(EIB);
+ return Error::success();
+ });
+ return Error(
+ std::unique_ptr<FileError>(new FileError(F, Line, std::move(Payload))));
+ }
+
+ std::string FileName;
+ std::optional<size_t> Line;
+ std::unique_ptr<ErrorInfoBase> Err;
+};
+
+/// Concatenate a source file path and/or name with an Error. The resulting
+/// Error is unchecked.
+inline Error createFileError(const Twine &F, Error E) {
+ return FileError::build(F, std::optional<size_t>(), std::move(E));
+}
+
+/// Concatenate a source file path and/or name with line number and an Error.
+/// The resulting Error is unchecked.
+inline Error createFileError(const Twine &F, size_t Line, Error E) {
+ return FileError::build(F, std::optional<size_t>(Line), std::move(E));
+}
+
+/// Concatenate a source file path and/or name with a std::error_code
+/// to form an Error object.
+inline Error createFileError(const Twine &F, std::error_code EC) {
+ return createFileError(F, errorCodeToError(EC));
+}
+
+/// Concatenate a source file path and/or name with line number and
+/// std::error_code to form an Error object.
+inline Error createFileError(const Twine &F, size_t Line, std::error_code EC) {
+ return createFileError(F, Line, errorCodeToError(EC));
+}
+
+Error createFileError(const Twine &F, ErrorSuccess) = delete;
+
+/// Helper for check-and-exit error handling.
+///
+/// For tool use only. NOT FOR USE IN LIBRARY CODE.
+///
+class ExitOnError {
+public:
+ /// Create an error on exit helper.
+ ExitOnError(std::string Banner = "", int DefaultErrorExitCode = 1)
+ : Banner(std::move(Banner)),
+ GetExitCode([=](const Error &) { return DefaultErrorExitCode; }) {}
+
+ /// Set the banner string for any errors caught by operator().
+ void setBanner(std::string Banner) { this->Banner = std::move(Banner); }
+
+ /// Set the exit-code mapper function.
+ void setExitCodeMapper(std::function<int(const Error &)> GetExitCode) {
+ this->GetExitCode = std::move(GetExitCode);
+ }
+
+ /// Check Err. If it's in a failure state log the error(s) and exit.
+ void operator()(Error Err) const { checkError(std::move(Err)); }
+
+ /// Check E. If it's in a success state then return the contained value. If
+ /// it's in a failure state log the error(s) and exit.
+ template <typename T> T operator()(Expected<T> &&E) const {
+ checkError(E.takeError());
+ return std::move(*E);
+ }
+
+ /// Check E. If it's in a success state then return the contained reference. If
+ /// it's in a failure state log the error(s) and exit.
+ template <typename T> T& operator()(Expected<T&> &&E) const {
+ checkError(E.takeError());
+ return *E;
+ }
+
+private:
+ void checkError(Error Err) const {
+ if (Err) {
+ int ExitCode = GetExitCode(Err);
+ logAllUnhandledErrors(std::move(Err), errs(), Banner);
+ exit(ExitCode);
+ }
+ }
+
+ std::string Banner;
+ std::function<int(const Error &)> GetExitCode;
+};
+
+/// Conversion from Error to LLVMErrorRef for C error bindings.
+inline LLVMErrorRef wrap(Error Err) {
+ return reinterpret_cast<LLVMErrorRef>(Err.takePayload().release());
+}
+
+/// Conversion from LLVMErrorRef to Error for C error bindings.
+inline Error unwrap(LLVMErrorRef ErrRef) {
+ return Error(std::unique_ptr<ErrorInfoBase>(
+ reinterpret_cast<ErrorInfoBase *>(ErrRef)));
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ERROR_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ErrorHandling.h b/contrib/libs/llvm16/include/llvm/Support/ErrorHandling.h
new file mode 100644
index 00000000000..f1292b31178
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ErrorHandling.h
@@ -0,0 +1,168 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- 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 defines an API used to indicate fatal error conditions. Non-fatal
+// errors (most of them) should be handled through LLVMContext.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERRORHANDLING_H
+#define LLVM_SUPPORT_ERRORHANDLING_H
+
+#include "llvm/Support/Compiler.h"
+
+namespace llvm {
+ class StringRef;
+ class Twine;
+
+ /// An error handler callback.
+ typedef void (*fatal_error_handler_t)(void *user_data,
+ const char *reason,
+ bool gen_crash_diag);
+
+ /// install_fatal_error_handler - Installs a new error handler to be used
+ /// whenever a serious (non-recoverable) error is encountered by LLVM.
+ ///
+ /// If no error handler is installed the default is to print the error message
+ /// to stderr, and call exit(1). If an error handler is installed then it is
+ /// the handler's responsibility to log the message, it will no longer be
+ /// printed to stderr. If the error handler returns, then exit(1) will be
+ /// called.
+ ///
+ /// It is dangerous to naively use an error handler which throws an exception.
+ /// Even though some applications desire to gracefully recover from arbitrary
+ /// faults, blindly throwing exceptions through unfamiliar code isn't a way to
+ /// achieve this.
+ ///
+ /// \param user_data - An argument which will be passed to the install error
+ /// handler.
+ void install_fatal_error_handler(fatal_error_handler_t handler,
+ void *user_data = nullptr);
+
+ /// Restores default error handling behaviour.
+ void remove_fatal_error_handler();
+
+ /// ScopedFatalErrorHandler - This is a simple helper class which just
+ /// calls install_fatal_error_handler in its constructor and
+ /// remove_fatal_error_handler in its destructor.
+ struct ScopedFatalErrorHandler {
+ explicit ScopedFatalErrorHandler(fatal_error_handler_t handler,
+ void *user_data = nullptr) {
+ install_fatal_error_handler(handler, user_data);
+ }
+
+ ~ScopedFatalErrorHandler() { remove_fatal_error_handler(); }
+ };
+
+/// Reports a serious error, calling any installed error handler. These
+/// functions are intended to be used for error conditions which are outside
+/// the control of the compiler (I/O errors, invalid user input, etc.)
+///
+/// If no error handler is installed the default is to print the message to
+/// standard error, followed by a newline.
+/// After the error handler is called this function will call abort(), it
+/// does not return.
+/// NOTE: The std::string variant was removed to avoid a <string> dependency.
+[[noreturn]] void report_fatal_error(const char *reason,
+ bool gen_crash_diag = true);
+[[noreturn]] void report_fatal_error(StringRef reason,
+ bool gen_crash_diag = true);
+[[noreturn]] void report_fatal_error(const Twine &reason,
+ bool gen_crash_diag = true);
+
+/// Installs a new bad alloc error handler that should be used whenever a
+/// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
+///
+/// The user can install a bad alloc handler, in order to define the behavior
+/// in case of failing allocations, e.g. throwing an exception. Note that this
+/// handler must not trigger any additional allocations itself.
+///
+/// If no error handler is installed the default is to print the error message
+/// to stderr, and call exit(1). If an error handler is installed then it is
+/// the handler's responsibility to log the message, it will no longer be
+/// printed to stderr. If the error handler returns, then exit(1) will be
+/// called.
+///
+///
+/// \param user_data - An argument which will be passed to the installed error
+/// handler.
+void install_bad_alloc_error_handler(fatal_error_handler_t handler,
+ void *user_data = nullptr);
+
+/// Restores default bad alloc error handling behavior.
+void remove_bad_alloc_error_handler();
+
+void install_out_of_memory_new_handler();
+
+/// Reports a bad alloc error, calling any user defined bad alloc
+/// error handler. In contrast to the generic 'report_fatal_error'
+/// functions, this function might not terminate, e.g. the user
+/// defined error handler throws an exception, but it won't return.
+///
+/// Note: When throwing an exception in the bad alloc handler, make sure that
+/// the following unwind succeeds, e.g. do not trigger additional allocations
+/// in the unwind chain.
+///
+/// If no error handler is installed (default), throws a bad_alloc exception
+/// if LLVM is compiled with exception support. Otherwise prints the error
+/// to standard error and calls abort().
+[[noreturn]] void report_bad_alloc_error(const char *Reason,
+ bool GenCrashDiag = true);
+
+/// This function calls abort(), and prints the optional message to stderr.
+/// Use the llvm_unreachable macro (that adds location info), instead of
+/// calling this function directly.
+[[noreturn]] void
+llvm_unreachable_internal(const char *msg = nullptr, const char *file = nullptr,
+ unsigned line = 0);
+}
+
+/// Marks that the current location is not supposed to be reachable.
+/// In !NDEBUG builds, prints the message and location info to stderr.
+/// In NDEBUG builds, if the platform does not support a builtin unreachable
+/// then we call an internal LLVM runtime function. Otherwise the behavior is
+/// controlled by the CMake flag
+/// -DLLVM_UNREACHABLE_OPTIMIZE
+/// * When "ON" (default) llvm_unreachable() becomes an optimizer hint
+/// that the current location is not supposed to be reachable: the hint
+/// turns such code path into undefined behavior. On compilers that don't
+/// support such hints, prints a reduced message instead and aborts the
+/// program.
+/// * When "OFF", a builtin_trap is emitted instead of an
+// optimizer hint or printing a reduced message.
+///
+/// Use this instead of assert(0). It conveys intent more clearly, suppresses
+/// diagnostics for unreachable code paths, and allows compilers to omit
+/// unnecessary code.
+#ifndef NDEBUG
+#define llvm_unreachable(msg) \
+ ::llvm::llvm_unreachable_internal(msg, __FILE__, __LINE__)
+#elif !defined(LLVM_BUILTIN_UNREACHABLE)
+#define llvm_unreachable(msg) ::llvm::llvm_unreachable_internal()
+#elif LLVM_UNREACHABLE_OPTIMIZE
+#define llvm_unreachable(msg) LLVM_BUILTIN_UNREACHABLE
+#else
+#define llvm_unreachable(msg) \
+ do { \
+ LLVM_BUILTIN_TRAP; \
+ LLVM_BUILTIN_UNREACHABLE; \
+ } while (false)
+#endif
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ErrorOr.h b/contrib/libs/llvm16/include/llvm/Support/ErrorOr.h
new file mode 100644
index 00000000000..67d9a081267
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ErrorOr.h
@@ -0,0 +1,283 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/ErrorOr.h - Error Smart Pointer -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Provides ErrorOr<T> smart pointer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ERROROR_H
+#define LLVM_SUPPORT_ERROROR_H
+
+#include "llvm/Support/AlignOf.h"
+#include <cassert>
+#include <system_error>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+/// Represents either an error or a value T.
+///
+/// ErrorOr<T> is a pointer-like class that represents the result of an
+/// operation. The result is either an error, or a value of type T. This is
+/// designed to emulate the usage of returning a pointer where nullptr indicates
+/// failure. However instead of just knowing that the operation failed, we also
+/// have an error_code and optional user data that describes why it failed.
+///
+/// It is used like the following.
+/// \code
+/// ErrorOr<Buffer> getBuffer();
+///
+/// auto buffer = getBuffer();
+/// if (error_code ec = buffer.getError())
+/// return ec;
+/// buffer->write("adena");
+/// \endcode
+///
+///
+/// Implicit conversion to bool returns true if there is a usable value. The
+/// unary * and -> operators provide pointer like access to the value. Accessing
+/// the value when there is an error has undefined behavior.
+///
+/// When T is a reference type the behavior is slightly different. The reference
+/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
+/// there is special handling to make operator -> work as if T was not a
+/// reference.
+///
+/// T cannot be a rvalue reference.
+template<class T>
+class ErrorOr {
+ template <class OtherT> friend class ErrorOr;
+
+ static constexpr bool isRef = std::is_reference<T>::value;
+
+ using wrap = std::reference_wrapper<std::remove_reference_t<T>>;
+
+public:
+ using storage_type = std::conditional_t<isRef, wrap, T>;
+
+private:
+ using reference = std::remove_reference_t<T> &;
+ using const_reference = const std::remove_reference_t<T> &;
+ using pointer = std::remove_reference_t<T> *;
+ using const_pointer = const std::remove_reference_t<T> *;
+
+public:
+ template <class E>
+ ErrorOr(E ErrorCode,
+ std::enable_if_t<std::is_error_code_enum<E>::value ||
+ std::is_error_condition_enum<E>::value,
+ void *> = nullptr)
+ : HasError(true) {
+ new (getErrorStorage()) std::error_code(make_error_code(ErrorCode));
+ }
+
+ ErrorOr(std::error_code EC) : HasError(true) {
+ new (getErrorStorage()) std::error_code(EC);
+ }
+
+ template <class OtherT>
+ ErrorOr(OtherT &&Val,
+ std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr)
+ : HasError(false) {
+ new (getStorage()) storage_type(std::forward<OtherT>(Val));
+ }
+
+ ErrorOr(const ErrorOr &Other) {
+ copyConstruct(Other);
+ }
+
+ template <class OtherT>
+ ErrorOr(const ErrorOr<OtherT> &Other,
+ std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) {
+ copyConstruct(Other);
+ }
+
+ template <class OtherT>
+ explicit ErrorOr(
+ const ErrorOr<OtherT> &Other,
+ std::enable_if_t<!std::is_convertible<OtherT, const T &>::value> * =
+ nullptr) {
+ copyConstruct(Other);
+ }
+
+ ErrorOr(ErrorOr &&Other) {
+ moveConstruct(std::move(Other));
+ }
+
+ template <class OtherT>
+ ErrorOr(ErrorOr<OtherT> &&Other,
+ std::enable_if_t<std::is_convertible<OtherT, T>::value> * = nullptr) {
+ moveConstruct(std::move(Other));
+ }
+
+ // This might eventually need SFINAE but it's more complex than is_convertible
+ // & I'm too lazy to write it right now.
+ template <class OtherT>
+ explicit ErrorOr(
+ ErrorOr<OtherT> &&Other,
+ std::enable_if_t<!std::is_convertible<OtherT, T>::value> * = nullptr) {
+ moveConstruct(std::move(Other));
+ }
+
+ ErrorOr &operator=(const ErrorOr &Other) {
+ copyAssign(Other);
+ return *this;
+ }
+
+ ErrorOr &operator=(ErrorOr &&Other) {
+ moveAssign(std::move(Other));
+ return *this;
+ }
+
+ ~ErrorOr() {
+ if (!HasError)
+ getStorage()->~storage_type();
+ }
+
+ /// Return false if there is an error.
+ explicit operator bool() const {
+ return !HasError;
+ }
+
+ reference get() { return *getStorage(); }
+ const_reference get() const { return const_cast<ErrorOr<T> *>(this)->get(); }
+
+ std::error_code getError() const {
+ return HasError ? *getErrorStorage() : std::error_code();
+ }
+
+ pointer operator ->() {
+ return toPointer(getStorage());
+ }
+
+ const_pointer operator->() const { return toPointer(getStorage()); }
+
+ reference operator *() {
+ return *getStorage();
+ }
+
+ const_reference operator*() const { return *getStorage(); }
+
+private:
+ template <class OtherT>
+ void copyConstruct(const ErrorOr<OtherT> &Other) {
+ if (!Other.HasError) {
+ // Get the other value.
+ HasError = false;
+ new (getStorage()) storage_type(*Other.getStorage());
+ } else {
+ // Get other's error.
+ HasError = true;
+ new (getErrorStorage()) std::error_code(Other.getError());
+ }
+ }
+
+ template <class T1>
+ static bool compareThisIfSameType(const T1 &a, const T1 &b) {
+ return &a == &b;
+ }
+
+ template <class T1, class T2>
+ static bool compareThisIfSameType(const T1 &a, const T2 &b) {
+ return false;
+ }
+
+ template <class OtherT>
+ void copyAssign(const ErrorOr<OtherT> &Other) {
+ if (compareThisIfSameType(*this, Other))
+ return;
+
+ this->~ErrorOr();
+ new (this) ErrorOr(Other);
+ }
+
+ template <class OtherT>
+ void moveConstruct(ErrorOr<OtherT> &&Other) {
+ if (!Other.HasError) {
+ // Get the other value.
+ HasError = false;
+ new (getStorage()) storage_type(std::move(*Other.getStorage()));
+ } else {
+ // Get other's error.
+ HasError = true;
+ new (getErrorStorage()) std::error_code(Other.getError());
+ }
+ }
+
+ template <class OtherT>
+ void moveAssign(ErrorOr<OtherT> &&Other) {
+ if (compareThisIfSameType(*this, Other))
+ return;
+
+ this->~ErrorOr();
+ new (this) ErrorOr(std::move(Other));
+ }
+
+ pointer toPointer(pointer Val) {
+ return Val;
+ }
+
+ const_pointer toPointer(const_pointer Val) const { return Val; }
+
+ pointer toPointer(wrap *Val) {
+ return &Val->get();
+ }
+
+ const_pointer toPointer(const wrap *Val) const { return &Val->get(); }
+
+ storage_type *getStorage() {
+ assert(!HasError && "Cannot get value when an error exists!");
+ return reinterpret_cast<storage_type *>(&TStorage);
+ }
+
+ const storage_type *getStorage() const {
+ assert(!HasError && "Cannot get value when an error exists!");
+ return reinterpret_cast<const storage_type *>(&TStorage);
+ }
+
+ std::error_code *getErrorStorage() {
+ assert(HasError && "Cannot get error when a value exists!");
+ return reinterpret_cast<std::error_code *>(&ErrorStorage);
+ }
+
+ const std::error_code *getErrorStorage() const {
+ return const_cast<ErrorOr<T> *>(this)->getErrorStorage();
+ }
+
+ union {
+ AlignedCharArrayUnion<storage_type> TStorage;
+ AlignedCharArrayUnion<std::error_code> ErrorStorage;
+ };
+ bool HasError : 1;
+};
+
+template <class T, class E>
+std::enable_if_t<std::is_error_code_enum<E>::value ||
+ std::is_error_condition_enum<E>::value,
+ bool>
+operator==(const ErrorOr<T> &Err, E Code) {
+ return Err.getError() == Code;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_ERROROR_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ExitCodes.h b/contrib/libs/llvm16/include/llvm/Support/ExitCodes.h
new file mode 100644
index 00000000000..336cab190dd
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ExitCodes.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/ExitCodes.h - Exit codes for exit() -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains definitions of exit codes for exit() function. They are
+/// either defined by sysexits.h if it is supported, or defined here if
+/// sysexits.h is not supported.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_EXITCODES_H
+#define LLVM_SUPPORT_EXITCODES_H
+
+#include "llvm/Config/llvm-config.h"
+
+#if HAVE_SYSEXITS_H
+#include <sysexits.h>
+#elif __MVS__ || defined(_WIN32)
+// <sysexits.h> does not exist on z/OS and Windows. The only value used in LLVM
+// is EX_IOERR, which is used to signal a special error condition (broken pipe).
+// Define the macro with its usual value from BSD systems, which is chosen to
+// not clash with more standard exit codes like 1.
+#define EX_IOERR 74
+#elif LLVM_ON_UNIX
+#error Exit code EX_IOERR not available
+#endif
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ExtensibleRTTI.h b/contrib/libs/llvm16/include/llvm/Support/ExtensibleRTTI.h
new file mode 100644
index 00000000000..952d95ef31a
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ExtensibleRTTI.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/ExtensibleRTTI.h - ExtensibleRTTI support --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+//
+// Defines an extensible RTTI mechanism designed to work with Casting.h.
+//
+// Extensible RTTI differs from LLVM's primary RTTI mechanism (see
+// llvm.org/docs/HowToSetUpLLVMStyleRTTI.html) by supporting open type
+// hierarchies, where new types can be added from outside libraries without
+// needing to change existing code. LLVM's primary RTTI mechanism should be
+// preferred where possible, but where open hierarchies are needed this system
+// can be used.
+//
+// The RTTIRoot class defines methods for comparing type ids. Implementations
+// of these methods can be injected into new classes using the RTTIExtends
+// class template.
+//
+// E.g.
+//
+// @code{.cpp}
+// class MyBaseClass : public RTTIExtends<MyBaseClass, RTTIRoot> {
+// public:
+// static char ID;
+// virtual void foo() = 0;
+// };
+//
+// class MyDerivedClass1 : public RTTIExtends<MyDerivedClass1, MyBaseClass> {
+// public:
+// static char ID;
+// void foo() override {}
+// };
+//
+// class MyDerivedClass2 : public RTTIExtends<MyDerivedClass2, MyBaseClass> {
+// public:
+// static char ID;
+// void foo() override {}
+// };
+//
+// char MyBaseClass::ID = 0;
+// char MyDerivedClass1::ID = 0;
+// char MyDerivedClass2:: ID = 0;
+//
+// void fn() {
+// std::unique_ptr<MyBaseClass> B = llvm::make_unique<MyDerivedClass1>();
+// llvm::outs() << isa<MyBaseClass>(B) << "\n"; // Outputs "1".
+// llvm::outs() << isa<MyDerivedClass1>(B) << "\n"; // Outputs "1".
+// llvm::outs() << isa<MyDerivedClass2>(B) << "\n"; // Outputs "0'.
+// }
+//
+// @endcode
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_EXTENSIBLERTTI_H
+#define LLVM_SUPPORT_EXTENSIBLERTTI_H
+
+namespace llvm {
+
+/// Base class for the extensible RTTI hierarchy.
+///
+/// This class defines virtual methods, dynamicClassID and isA, that enable
+/// type comparisons.
+class RTTIRoot {
+public:
+ virtual ~RTTIRoot() = default;
+
+ /// Returns the class ID for this type.
+ static const void *classID() { return &ID; }
+
+ /// Returns the class ID for the dynamic type of this RTTIRoot instance.
+ virtual const void *dynamicClassID() const = 0;
+
+ /// Returns true if this class's ID matches the given class ID.
+ virtual bool isA(const void *const ClassID) const {
+ return ClassID == classID();
+ }
+
+ /// Check whether this instance is a subclass of QueryT.
+ template <typename QueryT>
+ bool isA() const { return isA(QueryT::classID()); }
+
+private:
+ virtual void anchor();
+
+ static char ID;
+};
+
+/// Inheritance utility for extensible RTTI.
+///
+/// Supports single inheritance only: A class can only have one
+/// ExtensibleRTTI-parent (i.e. a parent for which the isa<> test will work),
+/// though it can have many non-ExtensibleRTTI parents.
+///
+/// RTTIExtents uses CRTP so the first template argument to RTTIExtends is the
+/// newly introduced type, and the *second* argument is the parent class.
+///
+/// class MyType : public RTTIExtends<MyType, RTTIRoot> {
+/// public:
+/// static char ID;
+/// };
+///
+/// class MyDerivedType : public RTTIExtends<MyDerivedType, MyType> {
+/// public:
+/// static char ID;
+/// };
+///
+template <typename ThisT, typename ParentT>
+class RTTIExtends : public ParentT {
+public:
+ // Inherit constructors from ParentT.
+ using ParentT::ParentT;
+
+ static const void *classID() { return &ThisT::ID; }
+
+ const void *dynamicClassID() const override { return &ThisT::ID; }
+
+ bool isA(const void *const ClassID) const override {
+ return ClassID == classID() || ParentT::isA(ClassID);
+ }
+
+ static bool classof(const RTTIRoot *R) { return R->isA<ThisT>(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_EXTENSIBLERTTI_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FileCollector.h b/contrib/libs/llvm16/include/llvm/Support/FileCollector.h
new file mode 100644
index 00000000000..7db57261517
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FileCollector.h
@@ -0,0 +1,157 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- FileCollector.h -----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FILECOLLECTOR_H
+#define LLVM_SUPPORT_FILECOLLECTOR_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include <mutex>
+#include <string>
+
+namespace llvm {
+class FileCollectorFileSystem;
+class Twine;
+
+class FileCollectorBase {
+public:
+ FileCollectorBase();
+ virtual ~FileCollectorBase();
+
+ void addFile(const Twine &file);
+ void addDirectory(const Twine &Dir);
+
+protected:
+ bool markAsSeen(StringRef Path) {
+ if (Path.empty())
+ return false;
+ return Seen.insert(Path).second;
+ }
+
+ virtual void addFileImpl(StringRef SrcPath) = 0;
+
+ virtual llvm::vfs::directory_iterator
+ addDirectoryImpl(const llvm::Twine &Dir,
+ IntrusiveRefCntPtr<vfs::FileSystem> FS,
+ std::error_code &EC) = 0;
+
+ /// Synchronizes access to internal data structures.
+ std::mutex Mutex;
+
+ /// Tracks already seen files so they can be skipped.
+ StringSet<> Seen;
+};
+
+/// Captures file system interaction and generates data to be later replayed
+/// with the RedirectingFileSystem.
+///
+/// For any file that gets accessed we eventually create:
+/// - a copy of the file inside Root
+/// - a record in RedirectingFileSystem mapping that maps:
+/// current real path -> path to the copy in Root
+///
+/// That intent is that later when the mapping is used by RedirectingFileSystem
+/// it simulates the state of FS that we collected.
+///
+/// We generate file copies and mapping lazily - see writeMapping and copyFiles.
+/// We don't try to capture the state of the file at the exact time when it's
+/// accessed. Files might get changed, deleted ... we record only the "final"
+/// state.
+///
+/// In order to preserve the relative topology of files we use their real paths
+/// as relative paths inside of the Root.
+class FileCollector : public FileCollectorBase {
+public:
+ /// Helper utility that encapsulates the logic for canonicalizing a virtual
+ /// path and a path to copy from.
+ class PathCanonicalizer {
+ public:
+ struct PathStorage {
+ SmallString<256> CopyFrom;
+ SmallString<256> VirtualPath;
+ };
+
+ /// Canonicalize a pair of virtual and real paths.
+ PathStorage canonicalize(StringRef SrcPath);
+
+ private:
+ /// Replace with a (mostly) real path, or don't modify. Resolves symlinks
+ /// in the directory, using \a CachedDirs to avoid redundant lookups, but
+ /// leaves the filename as a possible symlink.
+ void updateWithRealPath(SmallVectorImpl<char> &Path);
+
+ StringMap<std::string> CachedDirs;
+ };
+
+ /// \p Root is the directory where collected files are will be stored.
+ /// \p OverlayRoot is VFS mapping root.
+ /// \p Root directory gets created in copyFiles unless it already exists.
+ FileCollector(std::string Root, std::string OverlayRoot);
+
+ /// Write the yaml mapping (for the VFS) to the given file.
+ std::error_code writeMapping(StringRef MappingFile);
+
+ /// Copy the files into the root directory.
+ ///
+ /// When StopOnError is true (the default) we abort as soon as one file
+ /// cannot be copied. This is relatively common, for example when a file was
+ /// removed after it was added to the mapping.
+ std::error_code copyFiles(bool StopOnError = true);
+
+ /// Create a VFS that uses \p Collector to collect files accessed via \p
+ /// BaseFS.
+ static IntrusiveRefCntPtr<vfs::FileSystem>
+ createCollectorVFS(IntrusiveRefCntPtr<vfs::FileSystem> BaseFS,
+ std::shared_ptr<FileCollector> Collector);
+
+private:
+ friend FileCollectorFileSystem;
+
+ void addFileToMapping(StringRef VirtualPath, StringRef RealPath) {
+ if (sys::fs::is_directory(VirtualPath))
+ VFSWriter.addDirectoryMapping(VirtualPath, RealPath);
+ else
+ VFSWriter.addFileMapping(VirtualPath, RealPath);
+ }
+
+protected:
+ void addFileImpl(StringRef SrcPath) override;
+
+ llvm::vfs::directory_iterator
+ addDirectoryImpl(const llvm::Twine &Dir,
+ IntrusiveRefCntPtr<vfs::FileSystem> FS,
+ std::error_code &EC) override;
+
+ /// The directory where collected files are copied to in copyFiles().
+ const std::string Root;
+
+ /// The root directory where the VFS overlay lives.
+ const std::string OverlayRoot;
+
+ /// The yaml mapping writer.
+ vfs::YAMLVFSWriter VFSWriter;
+
+ /// Helper utility for canonicalizing paths.
+ PathCanonicalizer Canonicalizer;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_FILECOLLECTOR_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FileOutputBuffer.h b/contrib/libs/llvm16/include/llvm/Support/FileOutputBuffer.h
new file mode 100644
index 00000000000..f71785c09a6
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FileOutputBuffer.h
@@ -0,0 +1,97 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//=== FileOutputBuffer.h - File Output Buffer -------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility for creating a in-memory buffer that will be written to a file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FILEOUTPUTBUFFER_H
+#define LLVM_SUPPORT_FILEOUTPUTBUFFER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+/// FileOutputBuffer - This interface provides simple way to create an in-memory
+/// buffer which will be written to a file. During the lifetime of these
+/// objects, the content or existence of the specified file is undefined. That
+/// is, creating an OutputBuffer for a file may immediately remove the file.
+/// If the FileOutputBuffer is committed, the target file's content will become
+/// the buffer content at the time of the commit. If the FileOutputBuffer is
+/// not committed, the file will be deleted in the FileOutputBuffer destructor.
+class FileOutputBuffer {
+public:
+ enum {
+ /// Set the 'x' bit on the resulting file.
+ F_executable = 1,
+
+ /// Don't use mmap and instead write an in-memory buffer to a file when this
+ /// buffer is closed.
+ F_no_mmap = 2,
+ };
+
+ /// Factory method to create an OutputBuffer object which manages a read/write
+ /// buffer of the specified size. When committed, the buffer will be written
+ /// to the file at the specified path.
+ ///
+ /// When F_modify is specified and \p FilePath refers to an existing on-disk
+ /// file \p Size may be set to -1, in which case the entire file is used.
+ /// Otherwise, the file shrinks or grows as necessary based on the value of
+ /// \p Size. It is an error to specify F_modify and Size=-1 if \p FilePath
+ /// does not exist.
+ static Expected<std::unique_ptr<FileOutputBuffer>>
+ create(StringRef FilePath, size_t Size, unsigned Flags = 0);
+
+ /// Returns a pointer to the start of the buffer.
+ virtual uint8_t *getBufferStart() const = 0;
+
+ /// Returns a pointer to the end of the buffer.
+ virtual uint8_t *getBufferEnd() const = 0;
+
+ /// Returns size of the buffer.
+ virtual size_t getBufferSize() const = 0;
+
+ /// Returns path where file will show up if buffer is committed.
+ StringRef getPath() const { return FinalPath; }
+
+ /// Flushes the content of the buffer to its file and deallocates the
+ /// buffer. If commit() is not called before this object's destructor
+ /// is called, the file is deleted in the destructor. The optional parameter
+ /// is used if it turns out you want the file size to be smaller than
+ /// initially requested.
+ virtual Error commit() = 0;
+
+ /// If this object was previously committed, the destructor just deletes
+ /// this object. If this object was not committed, the destructor
+ /// deallocates the buffer and the target file is never written.
+ virtual ~FileOutputBuffer() = default;
+
+ /// This removes the temporary file (unless it already was committed)
+ /// but keeps the memory mapping alive.
+ virtual void discard() {}
+
+protected:
+ FileOutputBuffer(StringRef Path) : FinalPath(Path) {}
+
+ std::string FinalPath;
+};
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FileSystem.h b/contrib/libs/llvm16/include/llvm/Support/FileSystem.h
new file mode 100644
index 00000000000..0fe6fbd86da
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FileSystem.h
@@ -0,0 +1,1598 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/FileSystem.h - File System OS Concept -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::fs namespace. It is designed after
+// TR2/boost filesystem (v3), but modified to remove exception handling and the
+// path class.
+//
+// All functions return an error_code and their actual work via the last out
+// argument. The out argument is defined if and only if errc::success is
+// returned. A function may return any error code in the generic or system
+// category. However, they shall be equivalent to any error conditions listed
+// in each functions respective documentation if the condition applies. [ note:
+// this does not guarantee that error_code will be in the set of explicitly
+// listed codes, but it does guarantee that if any of the explicitly listed
+// errors occur, the correct error_code will be used ]. All functions may
+// return errc::not_enough_memory if there is not enough memory to complete the
+// operation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FILESYSTEM_H
+#define LLVM_SUPPORT_FILESYSTEM_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem/UniqueID.h"
+#include "llvm/Support/MD5.h"
+#include <cassert>
+#include <cstdint>
+#include <ctime>
+#include <memory>
+#include <stack>
+#include <string>
+#include <system_error>
+#include <vector>
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+namespace llvm {
+namespace sys {
+namespace fs {
+
+#if defined(_WIN32)
+// A Win32 HANDLE is a typedef of void*
+using file_t = void *;
+#else
+using file_t = int;
+#endif
+
+extern const file_t kInvalidFile;
+
+/// An enumeration for the file system's view of the type.
+enum class file_type {
+ status_error,
+ file_not_found,
+ regular_file,
+ directory_file,
+ symlink_file,
+ block_file,
+ character_file,
+ fifo_file,
+ socket_file,
+ type_unknown
+};
+
+/// space_info - Self explanatory.
+struct space_info {
+ uint64_t capacity;
+ uint64_t free;
+ uint64_t available;
+};
+
+enum perms {
+ no_perms = 0,
+ owner_read = 0400,
+ owner_write = 0200,
+ owner_exe = 0100,
+ owner_all = owner_read | owner_write | owner_exe,
+ group_read = 040,
+ group_write = 020,
+ group_exe = 010,
+ group_all = group_read | group_write | group_exe,
+ others_read = 04,
+ others_write = 02,
+ others_exe = 01,
+ others_all = others_read | others_write | others_exe,
+ all_read = owner_read | group_read | others_read,
+ all_write = owner_write | group_write | others_write,
+ all_exe = owner_exe | group_exe | others_exe,
+ all_all = owner_all | group_all | others_all,
+ set_uid_on_exe = 04000,
+ set_gid_on_exe = 02000,
+ sticky_bit = 01000,
+ all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
+ perms_not_known = 0xFFFF
+};
+
+// Helper functions so that you can use & and | to manipulate perms bits:
+inline perms operator|(perms l, perms r) {
+ return static_cast<perms>(static_cast<unsigned short>(l) |
+ static_cast<unsigned short>(r));
+}
+inline perms operator&(perms l, perms r) {
+ return static_cast<perms>(static_cast<unsigned short>(l) &
+ static_cast<unsigned short>(r));
+}
+inline perms &operator|=(perms &l, perms r) {
+ l = l | r;
+ return l;
+}
+inline perms &operator&=(perms &l, perms r) {
+ l = l & r;
+ return l;
+}
+inline perms operator~(perms x) {
+ // Avoid UB by explicitly truncating the (unsigned) ~ result.
+ return static_cast<perms>(
+ static_cast<unsigned short>(~static_cast<unsigned short>(x)));
+}
+
+/// Represents the result of a call to directory_iterator::status(). This is a
+/// subset of the information returned by a regular sys::fs::status() call, and
+/// represents the information provided by Windows FileFirstFile/FindNextFile.
+class basic_file_status {
+protected:
+ #if defined(LLVM_ON_UNIX)
+ time_t fs_st_atime = 0;
+ time_t fs_st_mtime = 0;
+ uint32_t fs_st_atime_nsec = 0;
+ uint32_t fs_st_mtime_nsec = 0;
+ uid_t fs_st_uid = 0;
+ gid_t fs_st_gid = 0;
+ off_t fs_st_size = 0;
+ #elif defined (_WIN32)
+ uint32_t LastAccessedTimeHigh = 0;
+ uint32_t LastAccessedTimeLow = 0;
+ uint32_t LastWriteTimeHigh = 0;
+ uint32_t LastWriteTimeLow = 0;
+ uint32_t FileSizeHigh = 0;
+ uint32_t FileSizeLow = 0;
+ #endif
+ file_type Type = file_type::status_error;
+ perms Perms = perms_not_known;
+
+public:
+ basic_file_status() = default;
+
+ explicit basic_file_status(file_type Type) : Type(Type) {}
+
+ #if defined(LLVM_ON_UNIX)
+ basic_file_status(file_type Type, perms Perms, time_t ATime,
+ uint32_t ATimeNSec, time_t MTime, uint32_t MTimeNSec,
+ uid_t UID, gid_t GID, off_t Size)
+ : fs_st_atime(ATime), fs_st_mtime(MTime),
+ fs_st_atime_nsec(ATimeNSec), fs_st_mtime_nsec(MTimeNSec),
+ fs_st_uid(UID), fs_st_gid(GID),
+ fs_st_size(Size), Type(Type), Perms(Perms) {}
+#elif defined(_WIN32)
+ basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
+ uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
+ uint32_t LastWriteTimeLow, uint32_t FileSizeHigh,
+ uint32_t FileSizeLow)
+ : LastAccessedTimeHigh(LastAccessTimeHigh),
+ LastAccessedTimeLow(LastAccessTimeLow),
+ LastWriteTimeHigh(LastWriteTimeHigh),
+ LastWriteTimeLow(LastWriteTimeLow), FileSizeHigh(FileSizeHigh),
+ FileSizeLow(FileSizeLow), Type(Type), Perms(Perms) {}
+ #endif
+
+ // getters
+ file_type type() const { return Type; }
+ perms permissions() const { return Perms; }
+
+ /// The file access time as reported from the underlying file system.
+ ///
+ /// Also see comments on \c getLastModificationTime() related to the precision
+ /// of the returned value.
+ TimePoint<> getLastAccessedTime() const;
+
+ /// The file modification time as reported from the underlying file system.
+ ///
+ /// The returned value allows for nanosecond precision but the actual
+ /// resolution is an implementation detail of the underlying file system.
+ /// There is no guarantee for what kind of resolution you can expect, the
+ /// resolution can differ across platforms and even across mountpoints on the
+ /// same machine.
+ TimePoint<> getLastModificationTime() const;
+
+ #if defined(LLVM_ON_UNIX)
+ uint32_t getUser() const { return fs_st_uid; }
+ uint32_t getGroup() const { return fs_st_gid; }
+ uint64_t getSize() const { return fs_st_size; }
+ #elif defined (_WIN32)
+ uint32_t getUser() const {
+ return 9999; // Not applicable to Windows, so...
+ }
+
+ uint32_t getGroup() const {
+ return 9999; // Not applicable to Windows, so...
+ }
+
+ uint64_t getSize() const {
+ return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
+ }
+ #endif
+
+ // setters
+ void type(file_type v) { Type = v; }
+ void permissions(perms p) { Perms = p; }
+};
+
+/// Represents the result of a call to sys::fs::status().
+class file_status : public basic_file_status {
+ friend bool equivalent(file_status A, file_status B);
+
+ #if defined(LLVM_ON_UNIX)
+ dev_t fs_st_dev = 0;
+ nlink_t fs_st_nlinks = 0;
+ ino_t fs_st_ino = 0;
+ #elif defined (_WIN32)
+ uint32_t NumLinks = 0;
+ uint32_t VolumeSerialNumber = 0;
+ uint32_t FileIndexHigh = 0;
+ uint32_t FileIndexLow = 0;
+ #endif
+
+public:
+ file_status() = default;
+
+ explicit file_status(file_type Type) : basic_file_status(Type) {}
+
+ #if defined(LLVM_ON_UNIX)
+ file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino,
+ time_t ATime, uint32_t ATimeNSec,
+ time_t MTime, uint32_t MTimeNSec,
+ uid_t UID, gid_t GID, off_t Size)
+ : basic_file_status(Type, Perms, ATime, ATimeNSec, MTime, MTimeNSec,
+ UID, GID, Size),
+ fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {}
+ #elif defined(_WIN32)
+ file_status(file_type Type, perms Perms, uint32_t LinkCount,
+ uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow,
+ uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow,
+ uint32_t VolumeSerialNumber, uint32_t FileSizeHigh,
+ uint32_t FileSizeLow, uint32_t FileIndexHigh,
+ uint32_t FileIndexLow)
+ : basic_file_status(Type, Perms, LastAccessTimeHigh, LastAccessTimeLow,
+ LastWriteTimeHigh, LastWriteTimeLow, FileSizeHigh,
+ FileSizeLow),
+ NumLinks(LinkCount), VolumeSerialNumber(VolumeSerialNumber),
+ FileIndexHigh(FileIndexHigh), FileIndexLow(FileIndexLow) {}
+ #endif
+
+ UniqueID getUniqueID() const;
+ uint32_t getLinkCount() const;
+};
+
+/// @}
+/// @name Physical Operators
+/// @{
+
+/// Make \a path an absolute path.
+///
+/// Makes \a path absolute using the \a current_directory if it is not already.
+/// An empty \a path will result in the \a current_directory.
+///
+/// /absolute/path => /absolute/path
+/// relative/../path => <current-directory>/relative/../path
+///
+/// @param path A path that is modified to be an absolute path.
+void make_absolute(const Twine &current_directory, SmallVectorImpl<char> &path);
+
+/// Make \a path an absolute path.
+///
+/// Makes \a path absolute using the current directory if it is not already. An
+/// empty \a path will result in the current directory.
+///
+/// /absolute/path => /absolute/path
+/// relative/../path => <current-directory>/relative/../path
+///
+/// @param path A path that is modified to be an absolute path.
+/// @returns errc::success if \a path has been made absolute, otherwise a
+/// platform-specific error_code.
+std::error_code make_absolute(SmallVectorImpl<char> &path);
+
+/// Create all the non-existent directories in path.
+///
+/// @param path Directories to create.
+/// @returns errc::success if is_directory(path), otherwise a platform
+/// specific error_code. If IgnoreExisting is false, also returns
+/// error if the directory already existed.
+std::error_code create_directories(const Twine &path,
+ bool IgnoreExisting = true,
+ perms Perms = owner_all | group_all);
+
+/// Create the directory in path.
+///
+/// @param path Directory to create.
+/// @returns errc::success if is_directory(path), otherwise a platform
+/// specific error_code. If IgnoreExisting is false, also returns
+/// error if the directory already existed.
+std::error_code create_directory(const Twine &path, bool IgnoreExisting = true,
+ perms Perms = owner_all | group_all);
+
+/// Create a link from \a from to \a to.
+///
+/// The link may be a soft or a hard link, depending on the platform. The caller
+/// may not assume which one. Currently on windows it creates a hard link since
+/// soft links require extra privileges. On unix, it creates a soft link since
+/// hard links don't work on SMB file systems.
+///
+/// @param to The path to hard link to.
+/// @param from The path to hard link from. This is created.
+/// @returns errc::success if the link was created, otherwise a platform
+/// specific error_code.
+std::error_code create_link(const Twine &to, const Twine &from);
+
+/// Create a hard link from \a from to \a to, or return an error.
+///
+/// @param to The path to hard link to.
+/// @param from The path to hard link from. This is created.
+/// @returns errc::success if the link was created, otherwise a platform
+/// specific error_code.
+std::error_code create_hard_link(const Twine &to, const Twine &from);
+
+/// Collapse all . and .. patterns, resolve all symlinks, and optionally
+/// expand ~ expressions to the user's home directory.
+///
+/// @param path The path to resolve.
+/// @param output The location to store the resolved path.
+/// @param expand_tilde If true, resolves ~ expressions to the user's home
+/// directory.
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output,
+ bool expand_tilde = false);
+
+/// Expands ~ expressions to the user's home directory. On Unix ~user
+/// directories are resolved as well.
+///
+/// @param path The path to resolve.
+void expand_tilde(const Twine &path, SmallVectorImpl<char> &output);
+
+/// Get the current path.
+///
+/// @param result Holds the current path on return.
+/// @returns errc::success if the current path has been stored in result,
+/// otherwise a platform-specific error_code.
+std::error_code current_path(SmallVectorImpl<char> &result);
+
+/// Set the current path.
+///
+/// @param path The path to set.
+/// @returns errc::success if the current path was successfully set,
+/// otherwise a platform-specific error_code.
+std::error_code set_current_path(const Twine &path);
+
+/// Remove path. Equivalent to POSIX remove().
+///
+/// @param path Input path.
+/// @returns errc::success if path has been removed or didn't exist, otherwise a
+/// platform-specific error code. If IgnoreNonExisting is false, also
+/// returns error if the file didn't exist.
+std::error_code remove(const Twine &path, bool IgnoreNonExisting = true);
+
+/// Recursively delete a directory.
+///
+/// @param path Input path.
+/// @returns errc::success if path has been removed or didn't exist, otherwise a
+/// platform-specific error code.
+std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true);
+
+/// Rename \a from to \a to.
+///
+/// Files are renamed as if by POSIX rename(), except that on Windows there may
+/// be a short interval of time during which the destination file does not
+/// exist.
+///
+/// @param from The path to rename from.
+/// @param to The path to rename to. This is created.
+std::error_code rename(const Twine &from, const Twine &to);
+
+/// Copy the contents of \a From to \a To.
+///
+/// @param From The path to copy from.
+/// @param To The path to copy to. This is created.
+std::error_code copy_file(const Twine &From, const Twine &To);
+
+/// Copy the contents of \a From to \a To.
+///
+/// @param From The path to copy from.
+/// @param ToFD The open file descriptor of the destination file.
+std::error_code copy_file(const Twine &From, int ToFD);
+
+/// Resize path to size. File is resized as if by POSIX truncate().
+///
+/// @param FD Input file descriptor.
+/// @param Size Size to resize to.
+/// @returns errc::success if \a path has been resized to \a size, otherwise a
+/// platform-specific error_code.
+std::error_code resize_file(int FD, uint64_t Size);
+
+/// Resize \p FD to \p Size before mapping \a mapped_file_region::readwrite. On
+/// non-Windows, this calls \a resize_file(). On Windows, this is a no-op,
+/// since the subsequent mapping (via \c CreateFileMapping) automatically
+/// extends the file.
+inline std::error_code resize_file_before_mapping_readwrite(int FD,
+ uint64_t Size) {
+#ifdef _WIN32
+ (void)FD;
+ (void)Size;
+ return std::error_code();
+#else
+ return resize_file(FD, Size);
+#endif
+}
+
+/// Compute an MD5 hash of a file's contents.
+///
+/// @param FD Input file descriptor.
+/// @returns An MD5Result with the hash computed, if successful, otherwise a
+/// std::error_code.
+ErrorOr<MD5::MD5Result> md5_contents(int FD);
+
+/// Version of compute_md5 that doesn't require an open file descriptor.
+ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path);
+
+/// @}
+/// @name Physical Observers
+/// @{
+
+/// Does file exist?
+///
+/// @param status A basic_file_status previously returned from stat.
+/// @returns True if the file represented by status exists, false if it does
+/// not.
+bool exists(const basic_file_status &status);
+
+enum class AccessMode { Exist, Write, Execute };
+
+/// Can the file be accessed?
+///
+/// @param Path Input path.
+/// @returns errc::success if the path can be accessed, otherwise a
+/// platform-specific error_code.
+std::error_code access(const Twine &Path, AccessMode Mode);
+
+/// Does file exist?
+///
+/// @param Path Input path.
+/// @returns True if it exists, false otherwise.
+inline bool exists(const Twine &Path) {
+ return !access(Path, AccessMode::Exist);
+}
+
+/// Can we execute this file?
+///
+/// @param Path Input path.
+/// @returns True if we can execute it, false otherwise.
+bool can_execute(const Twine &Path);
+
+/// Can we write this file?
+///
+/// @param Path Input path.
+/// @returns True if we can write to it, false otherwise.
+inline bool can_write(const Twine &Path) {
+ return !access(Path, AccessMode::Write);
+}
+
+/// Do file_status's represent the same thing?
+///
+/// @param A Input file_status.
+/// @param B Input file_status.
+///
+/// assert(status_known(A) || status_known(B));
+///
+/// @returns True if A and B both represent the same file system entity, false
+/// otherwise.
+bool equivalent(file_status A, file_status B);
+
+/// Do paths represent the same thing?
+///
+/// assert(status_known(A) || status_known(B));
+///
+/// @param A Input path A.
+/// @param B Input path B.
+/// @param result Set to true if stat(A) and stat(B) have the same device and
+/// inode (or equivalent).
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code equivalent(const Twine &A, const Twine &B, bool &result);
+
+/// Simpler version of equivalent for clients that don't need to
+/// differentiate between an error and false.
+inline bool equivalent(const Twine &A, const Twine &B) {
+ bool result;
+ return !equivalent(A, B, result) && result;
+}
+
+/// Is the file mounted on a local filesystem?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is on fixed media such as a hard disk,
+/// false if it is not.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform specific error_code.
+std::error_code is_local(const Twine &path, bool &result);
+
+/// Version of is_local accepting an open file descriptor.
+std::error_code is_local(int FD, bool &result);
+
+/// Simpler version of is_local for clients that don't need to
+/// differentiate between an error and false.
+inline bool is_local(const Twine &Path) {
+ bool Result;
+ return !is_local(Path, Result) && Result;
+}
+
+/// Simpler version of is_local accepting an open file descriptor for
+/// clients that don't need to differentiate between an error and false.
+inline bool is_local(int FD) {
+ bool Result;
+ return !is_local(FD, Result) && Result;
+}
+
+/// Does status represent a directory?
+///
+/// @param Path The path to get the type of.
+/// @param Follow For symbolic links, indicates whether to return the file type
+/// of the link itself, or of the target.
+/// @returns A value from the file_type enumeration indicating the type of file.
+file_type get_file_type(const Twine &Path, bool Follow = true);
+
+/// Does status represent a directory?
+///
+/// @param status A basic_file_status previously returned from status.
+/// @returns status.type() == file_type::directory_file.
+bool is_directory(const basic_file_status &status);
+
+/// Is path a directory?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is a directory (after following
+/// symlinks, false if it is not. Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code is_directory(const Twine &path, bool &result);
+
+/// Simpler version of is_directory for clients that don't need to
+/// differentiate between an error and false.
+inline bool is_directory(const Twine &Path) {
+ bool Result;
+ return !is_directory(Path, Result) && Result;
+}
+
+/// Does status represent a regular file?
+///
+/// @param status A basic_file_status previously returned from status.
+/// @returns status_known(status) && status.type() == file_type::regular_file.
+bool is_regular_file(const basic_file_status &status);
+
+/// Is path a regular file?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is a regular file (after following
+/// symlinks), false if it is not. Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code is_regular_file(const Twine &path, bool &result);
+
+/// Simpler version of is_regular_file for clients that don't need to
+/// differentiate between an error and false.
+inline bool is_regular_file(const Twine &Path) {
+ bool Result;
+ if (is_regular_file(Path, Result))
+ return false;
+ return Result;
+}
+
+/// Does status represent a symlink file?
+///
+/// @param status A basic_file_status previously returned from status.
+/// @returns status_known(status) && status.type() == file_type::symlink_file.
+bool is_symlink_file(const basic_file_status &status);
+
+/// Is path a symlink file?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is a symlink file, false if it is not.
+/// Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code is_symlink_file(const Twine &path, bool &result);
+
+/// Simpler version of is_symlink_file for clients that don't need to
+/// differentiate between an error and false.
+inline bool is_symlink_file(const Twine &Path) {
+ bool Result;
+ if (is_symlink_file(Path, Result))
+ return false;
+ return Result;
+}
+
+/// Does this status represent something that exists but is not a
+/// directory or regular file?
+///
+/// @param status A basic_file_status previously returned from status.
+/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
+bool is_other(const basic_file_status &status);
+
+/// Is path something that exists but is not a directory,
+/// regular file, or symlink?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path exists, but is not a directory, regular
+/// file, or a symlink, false if it does not. Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code is_other(const Twine &path, bool &result);
+
+/// Get file status as if by POSIX stat().
+///
+/// @param path Input path.
+/// @param result Set to the file status.
+/// @param follow When true, follows symlinks. Otherwise, the symlink itself is
+/// statted.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code status(const Twine &path, file_status &result,
+ bool follow = true);
+
+/// A version for when a file descriptor is already available.
+std::error_code status(int FD, file_status &Result);
+
+#ifdef _WIN32
+/// A version for when a file descriptor is already available.
+std::error_code status(file_t FD, file_status &Result);
+#endif
+
+/// Get file creation mode mask of the process.
+///
+/// @returns Mask reported by umask(2)
+/// @note There is no umask on Windows. This function returns 0 always
+/// on Windows. This function does not return an error_code because
+/// umask(2) never fails. It is not thread safe.
+unsigned getUmask();
+
+/// Set file permissions.
+///
+/// @param Path File to set permissions on.
+/// @param Permissions New file permissions.
+/// @returns errc::success if the permissions were successfully set, otherwise
+/// a platform-specific error_code.
+/// @note On Windows, all permissions except *_write are ignored. Using any of
+/// owner_write, group_write, or all_write will make the file writable.
+/// Otherwise, the file will be marked as read-only.
+std::error_code setPermissions(const Twine &Path, perms Permissions);
+
+/// Vesion of setPermissions accepting a file descriptor.
+/// TODO Delete the path based overload once we implement the FD based overload
+/// on Windows.
+std::error_code setPermissions(int FD, perms Permissions);
+
+/// Get file permissions.
+///
+/// @param Path File to get permissions from.
+/// @returns the permissions if they were successfully retrieved, otherwise a
+/// platform-specific error_code.
+/// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY
+/// attribute, all_all will be returned. Otherwise, all_read | all_exe
+/// will be returned.
+ErrorOr<perms> getPermissions(const Twine &Path);
+
+/// Get file size.
+///
+/// @param Path Input path.
+/// @param Result Set to the size of the file in \a Path.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+inline std::error_code file_size(const Twine &Path, uint64_t &Result) {
+ file_status Status;
+ std::error_code EC = status(Path, Status);
+ if (EC)
+ return EC;
+ Result = Status.getSize();
+ return std::error_code();
+}
+
+/// Set the file modification and access time.
+///
+/// @returns errc::success if the file times were successfully set, otherwise a
+/// platform-specific error_code or errc::function_not_supported on
+/// platforms where the functionality isn't available.
+std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime,
+ TimePoint<> ModificationTime);
+
+/// Simpler version that sets both file modification and access time to the same
+/// time.
+inline std::error_code setLastAccessAndModificationTime(int FD,
+ TimePoint<> Time) {
+ return setLastAccessAndModificationTime(FD, Time, Time);
+}
+
+/// Is status available?
+///
+/// @param s Input file status.
+/// @returns True if status() != status_error.
+bool status_known(const basic_file_status &s);
+
+/// Is status available?
+///
+/// @param path Input path.
+/// @param result Set to true if status() != status_error.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code status_known(const Twine &path, bool &result);
+
+enum CreationDisposition : unsigned {
+ /// CD_CreateAlways - When opening a file:
+ /// * If it already exists, truncate it.
+ /// * If it does not already exist, create a new file.
+ CD_CreateAlways = 0,
+
+ /// CD_CreateNew - When opening a file:
+ /// * If it already exists, fail.
+ /// * If it does not already exist, create a new file.
+ CD_CreateNew = 1,
+
+ /// CD_OpenExisting - When opening a file:
+ /// * If it already exists, open the file with the offset set to 0.
+ /// * If it does not already exist, fail.
+ CD_OpenExisting = 2,
+
+ /// CD_OpenAlways - When opening a file:
+ /// * If it already exists, open the file with the offset set to 0.
+ /// * If it does not already exist, create a new file.
+ CD_OpenAlways = 3,
+};
+
+enum FileAccess : unsigned {
+ FA_Read = 1,
+ FA_Write = 2,
+};
+
+enum OpenFlags : unsigned {
+ OF_None = 0,
+
+ /// The file should be opened in text mode on platforms like z/OS that make
+ /// this distinction.
+ OF_Text = 1,
+
+ /// The file should use a carriage linefeed '\r\n'. This flag should only be
+ /// used with OF_Text. Only makes a difference on Windows.
+ OF_CRLF = 2,
+
+ /// The file should be opened in text mode and use a carriage linefeed '\r\n'.
+ /// This flag has the same functionality as OF_Text on z/OS but adds a
+ /// carriage linefeed on Windows.
+ OF_TextWithCRLF = OF_Text | OF_CRLF,
+
+ /// The file should be opened in append mode.
+ OF_Append = 4,
+
+ /// The returned handle can be used for deleting the file. Only makes a
+ /// difference on windows.
+ OF_Delete = 8,
+
+ /// When a child process is launched, this file should remain open in the
+ /// child process.
+ OF_ChildInherit = 16,
+
+ /// Force files Atime to be updated on access. Only makes a difference on
+ /// Windows.
+ OF_UpdateAtime = 32,
+};
+
+/// Create a potentially unique file name but does not create it.
+///
+/// Generates a unique path suitable for a temporary file but does not
+/// open or create the file. The name is based on \a Model with '%'
+/// replaced by a random char in [0-9a-f]. If \a MakeAbsolute is true
+/// then the system's temp directory is prepended first. If \a MakeAbsolute
+/// is false the current directory will be used instead.
+///
+/// This function does not check if the file exists. If you want to be sure
+/// that the file does not yet exist, you should use use enough '%' characters
+/// in your model to ensure this. Each '%' gives 4-bits of entropy so you can
+/// use 32 of them to get 128 bits of entropy.
+///
+/// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s
+///
+/// @param Model Name to base unique path off of.
+/// @param ResultPath Set to the file's path.
+/// @param MakeAbsolute Whether to use the system temp directory.
+void createUniquePath(const Twine &Model, SmallVectorImpl<char> &ResultPath,
+ bool MakeAbsolute);
+
+/// Create a uniquely named file.
+///
+/// Generates a unique path suitable for a temporary file and then opens it as a
+/// file. The name is based on \a Model with '%' replaced by a random char in
+/// [0-9a-f]. If \a Model is not an absolute path, the temporary file will be
+/// created in the current directory.
+///
+/// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s
+///
+/// This is an atomic operation. Either the file is created and opened, or the
+/// file system is left untouched.
+///
+/// The intended use is for files that are to be kept, possibly after
+/// renaming them. For example, when running 'clang -c foo.o', the file can
+/// be first created as foo-abc123.o and then renamed.
+///
+/// @param Model Name to base unique path off of.
+/// @param ResultFD Set to the opened file's file descriptor.
+/// @param ResultPath Set to the opened file's absolute path.
+/// @param Flags Set to the opened file's flags.
+/// @param Mode Set to the opened file's permissions.
+/// @returns errc::success if Result{FD,Path} have been successfully set,
+/// otherwise a platform-specific error_code.
+std::error_code createUniqueFile(const Twine &Model, int &ResultFD,
+ SmallVectorImpl<char> &ResultPath,
+ OpenFlags Flags = OF_None,
+ unsigned Mode = all_read | all_write);
+
+/// Simpler version for clients that don't want an open file. An empty
+/// file will still be created.
+std::error_code createUniqueFile(const Twine &Model,
+ SmallVectorImpl<char> &ResultPath,
+ unsigned Mode = all_read | all_write);
+
+/// Represents a temporary file.
+///
+/// The temporary file must be eventually discarded or given a final name and
+/// kept.
+///
+/// The destructor doesn't implicitly discard because there is no way to
+/// properly handle errors in a destructor.
+class TempFile {
+ bool Done = false;
+ TempFile(StringRef Name, int FD);
+
+public:
+ /// This creates a temporary file with createUniqueFile and schedules it for
+ /// deletion with sys::RemoveFileOnSignal.
+ static Expected<TempFile> create(const Twine &Model,
+ unsigned Mode = all_read | all_write,
+ OpenFlags ExtraFlags = OF_None);
+ TempFile(TempFile &&Other);
+ TempFile &operator=(TempFile &&Other);
+
+ // Name of the temporary file.
+ std::string TmpName;
+
+ // The open file descriptor.
+ int FD = -1;
+
+#ifdef _WIN32
+ // Whether we need to manually remove the file on close.
+ bool RemoveOnClose = false;
+#endif
+
+ // Keep this with the given name.
+ Error keep(const Twine &Name);
+
+ // Keep this with the temporary name.
+ Error keep();
+
+ // Delete the file.
+ Error discard();
+
+ // This checks that keep or delete was called.
+ ~TempFile();
+};
+
+/// Create a file in the system temporary directory.
+///
+/// The filename is of the form prefix-random_chars.suffix. Since the directory
+/// is not know to the caller, Prefix and Suffix cannot have path separators.
+/// The files are created with mode 0600.
+///
+/// This should be used for things like a temporary .s that is removed after
+/// running the assembler.
+std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
+ int &ResultFD,
+ SmallVectorImpl<char> &ResultPath,
+ OpenFlags Flags = OF_None);
+
+/// Simpler version for clients that don't want an open file. An empty
+/// file will still be created.
+std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
+ SmallVectorImpl<char> &ResultPath,
+ OpenFlags Flags = OF_None);
+
+std::error_code createUniqueDirectory(const Twine &Prefix,
+ SmallVectorImpl<char> &ResultPath);
+
+/// Get a unique name, not currently exisiting in the filesystem. Subject
+/// to race conditions, prefer to use createUniqueFile instead.
+///
+/// Similar to createUniqueFile, but instead of creating a file only
+/// checks if it exists. This function is subject to race conditions, if you
+/// want to use the returned name to actually create a file, use
+/// createUniqueFile instead.
+std::error_code getPotentiallyUniqueFileName(const Twine &Model,
+ SmallVectorImpl<char> &ResultPath);
+
+/// Get a unique temporary file name, not currently exisiting in the
+/// filesystem. Subject to race conditions, prefer to use createTemporaryFile
+/// instead.
+///
+/// Similar to createTemporaryFile, but instead of creating a file only
+/// checks if it exists. This function is subject to race conditions, if you
+/// want to use the returned name to actually create a file, use
+/// createTemporaryFile instead.
+std::error_code
+getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
+ SmallVectorImpl<char> &ResultPath);
+
+inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
+ return OpenFlags(unsigned(A) | unsigned(B));
+}
+
+inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
+ A = A | B;
+ return A;
+}
+
+inline FileAccess operator|(FileAccess A, FileAccess B) {
+ return FileAccess(unsigned(A) | unsigned(B));
+}
+
+inline FileAccess &operator|=(FileAccess &A, FileAccess B) {
+ A = A | B;
+ return A;
+}
+
+/// @brief Opens a file with the specified creation disposition, access mode,
+/// and flags and returns a file descriptor.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+/// is stored in this location. Otherwise, this is set to -1.
+/// @param Disp Value specifying the existing-file behavior.
+/// @param Access Value specifying whether to open the file in read, write, or
+/// read-write mode.
+/// @param Flags Additional flags.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+std::error_code openFile(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp, FileAccess Access,
+ OpenFlags Flags, unsigned Mode = 0666);
+
+/// @brief Opens a file with the specified creation disposition, access mode,
+/// and flags and returns a platform-specific file object.
+///
+/// The caller is responsible for closing the file object once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Disp Value specifying the existing-file behavior.
+/// @param Access Value specifying whether to open the file in read, write, or
+/// read-write mode.
+/// @param Flags Additional flags.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp,
+ FileAccess Access, OpenFlags Flags,
+ unsigned Mode = 0666);
+
+/// Converts from a Posix file descriptor number to a native file handle.
+/// On Windows, this retreives the underlying handle. On non-Windows, this is a
+/// no-op.
+file_t convertFDToNativeFile(int FD);
+
+#ifndef _WIN32
+inline file_t convertFDToNativeFile(int FD) { return FD; }
+#endif
+
+/// Return an open handle to standard in. On Unix, this is typically FD 0.
+/// Returns kInvalidFile when the stream is closed.
+file_t getStdinHandle();
+
+/// Return an open handle to standard out. On Unix, this is typically FD 1.
+/// Returns kInvalidFile when the stream is closed.
+file_t getStdoutHandle();
+
+/// Return an open handle to standard error. On Unix, this is typically FD 2.
+/// Returns kInvalidFile when the stream is closed.
+file_t getStderrHandle();
+
+/// Reads \p Buf.size() bytes from \p FileHandle into \p Buf. Returns the number
+/// of bytes actually read. On Unix, this is equivalent to `return ::read(FD,
+/// Buf.data(), Buf.size())`, with error reporting. Returns 0 when reaching EOF.
+///
+/// @param FileHandle File to read from.
+/// @param Buf Buffer to read into.
+/// @returns The number of bytes read, or error.
+Expected<size_t> readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf);
+
+/// Default chunk size for \a readNativeFileToEOF().
+enum : size_t { DefaultReadChunkSize = 4 * 4096 };
+
+/// Reads from \p FileHandle until EOF, appending to \p Buffer in chunks of
+/// size \p ChunkSize.
+///
+/// This calls \a readNativeFile() in a loop. On Error, previous chunks that
+/// were read successfully are left in \p Buffer and returned.
+///
+/// Note: For reading the final chunk at EOF, \p Buffer's capacity needs extra
+/// storage of \p ChunkSize.
+///
+/// \param FileHandle File to read from.
+/// \param Buffer Where to put the file content.
+/// \param ChunkSize Size of chunks.
+/// \returns The error if EOF was not found.
+Error readNativeFileToEOF(file_t FileHandle, SmallVectorImpl<char> &Buffer,
+ ssize_t ChunkSize = DefaultReadChunkSize);
+
+/// Reads \p Buf.size() bytes from \p FileHandle at offset \p Offset into \p
+/// Buf. If 'pread' is available, this will use that, otherwise it will use
+/// 'lseek'. Returns the number of bytes actually read. Returns 0 when reaching
+/// EOF.
+///
+/// @param FileHandle File to read from.
+/// @param Buf Buffer to read into.
+/// @param Offset Offset into the file at which the read should occur.
+/// @returns The number of bytes read, or error.
+Expected<size_t> readNativeFileSlice(file_t FileHandle,
+ MutableArrayRef<char> Buf,
+ uint64_t Offset);
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+/// is stored in this location. Otherwise, this is set to -1.
+/// @param Flags Additional flags used to determine whether the file should be
+/// opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+inline std::error_code
+openFileForWrite(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp = CD_CreateAlways,
+ OpenFlags Flags = OF_None, unsigned Mode = 0666) {
+ return openFile(Name, ResultFD, Disp, FA_Write, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Flags Additional flags used to determine whether the file should be
+/// opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+/// otherwise an error object.
+inline Expected<file_t> openNativeFileForWrite(const Twine &Name,
+ CreationDisposition Disp,
+ OpenFlags Flags,
+ unsigned Mode = 0666) {
+ return openNativeFile(Name, Disp, FA_Write, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+/// is stored in this location. Otherwise, this is set to -1.
+/// @param Flags Additional flags used to determine whether the file should be
+/// opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+inline std::error_code openFileForReadWrite(const Twine &Name, int &ResultFD,
+ CreationDisposition Disp,
+ OpenFlags Flags,
+ unsigned Mode = 0666) {
+ return openFile(Name, ResultFD, Disp, FA_Write | FA_Read, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a write-only or read-write
+/// mode, returning its open file descriptor. If the file does not exist, it
+/// is created.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param Flags Additional flags used to determine whether the file should be
+/// opened in, for example, read-write or in write-only mode.
+/// @param Mode The access permissions of the file, represented in octal.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+/// otherwise an error object.
+inline Expected<file_t> openNativeFileForReadWrite(const Twine &Name,
+ CreationDisposition Disp,
+ OpenFlags Flags,
+ unsigned Mode = 0666) {
+ return openNativeFile(Name, Disp, FA_Write | FA_Read, Flags, Mode);
+}
+
+/// @brief Opens the file with the given name in a read-only mode, returning
+/// its open file descriptor.
+///
+/// The caller is responsible for closing the file descriptor once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param ResultFD If the file could be opened successfully, its descriptor
+/// is stored in this location. Otherwise, this is set to -1.
+/// @param RealPath If nonnull, extra work is done to determine the real path
+/// of the opened file, and that path is stored in this
+/// location.
+/// @returns errc::success if \a Name has been opened, otherwise a
+/// platform-specific error_code.
+std::error_code openFileForRead(const Twine &Name, int &ResultFD,
+ OpenFlags Flags = OF_None,
+ SmallVectorImpl<char> *RealPath = nullptr);
+
+/// @brief Opens the file with the given name in a read-only mode, returning
+/// its open file descriptor.
+///
+/// The caller is responsible for closing the freeing the file once they are
+/// finished with it.
+///
+/// @param Name The path of the file to open, relative or absolute.
+/// @param RealPath If nonnull, extra work is done to determine the real path
+/// of the opened file, and that path is stored in this
+/// location.
+/// @returns a platform-specific file descriptor if \a Name has been opened,
+/// otherwise an error object.
+Expected<file_t>
+openNativeFileForRead(const Twine &Name, OpenFlags Flags = OF_None,
+ SmallVectorImpl<char> *RealPath = nullptr);
+
+/// Try to locks the file during the specified time.
+///
+/// This function implements advisory locking on entire file. If it returns
+/// <em>errc::success</em>, the file is locked by the calling process. Until the
+/// process unlocks the file by calling \a unlockFile, all attempts to lock the
+/// same file will fail/block. The process that locked the file may assume that
+/// none of other processes read or write this file, provided that all processes
+/// lock the file prior to accessing its content.
+///
+/// @param FD The descriptor representing the file to lock.
+/// @param Timeout Time in milliseconds that the process should wait before
+/// reporting lock failure. Zero value means try to get lock only
+/// once.
+/// @returns errc::success if lock is successfully obtained,
+/// errc::no_lock_available if the file cannot be locked, or platform-specific
+/// error_code otherwise.
+///
+/// @note Care should be taken when using this function in a multithreaded
+/// context, as it may not prevent other threads in the same process from
+/// obtaining a lock on the same file, even if they are using a different file
+/// descriptor.
+std::error_code
+tryLockFile(int FD,
+ std::chrono::milliseconds Timeout = std::chrono::milliseconds(0));
+
+/// Lock the file.
+///
+/// This function acts as @ref tryLockFile but it waits infinitely.
+std::error_code lockFile(int FD);
+
+/// Unlock the file.
+///
+/// @param FD The descriptor representing the file to unlock.
+/// @returns errc::success if lock is successfully released or platform-specific
+/// error_code otherwise.
+std::error_code unlockFile(int FD);
+
+/// @brief Close the file object. This should be used instead of ::close for
+/// portability. On error, the caller should assume the file is closed, as is
+/// the case for Process::SafelyCloseFileDescriptor
+///
+/// @param F On input, this is the file to close. On output, the file is
+/// set to kInvalidFile.
+///
+/// @returns An error code if closing the file failed. Typically, an error here
+/// means that the filesystem may have failed to perform some buffered writes.
+std::error_code closeFile(file_t &F);
+
+#ifdef LLVM_ON_UNIX
+/// @brief Change ownership of a file.
+///
+/// @param Owner The owner of the file to change to.
+/// @param Group The group of the file to change to.
+/// @returns errc::success if successfully updated file ownership, otherwise an
+/// error code is returned.
+std::error_code changeFileOwnership(int FD, uint32_t Owner, uint32_t Group);
+#endif
+
+/// RAII class that facilitates file locking.
+class FileLocker {
+ int FD; ///< Locked file handle.
+ FileLocker(int FD) : FD(FD) {}
+ friend class llvm::raw_fd_ostream;
+
+public:
+ FileLocker(const FileLocker &L) = delete;
+ FileLocker(FileLocker &&L) : FD(L.FD) { L.FD = -1; }
+ ~FileLocker() {
+ if (FD != -1)
+ unlockFile(FD);
+ }
+ FileLocker &operator=(FileLocker &&L) {
+ FD = L.FD;
+ L.FD = -1;
+ return *this;
+ }
+ FileLocker &operator=(const FileLocker &L) = delete;
+ std::error_code unlock() {
+ if (FD != -1) {
+ std::error_code Result = unlockFile(FD);
+ FD = -1;
+ return Result;
+ }
+ return std::error_code();
+ }
+};
+
+std::error_code getUniqueID(const Twine Path, UniqueID &Result);
+
+/// Get disk space usage information.
+///
+/// Note: Users must be careful about "Time Of Check, Time Of Use" kind of bug.
+/// Note: Windows reports results according to the quota allocated to the user.
+///
+/// @param Path Input path.
+/// @returns a space_info structure filled with the capacity, free, and
+/// available space on the device \a Path is on. A platform specific error_code
+/// is returned on error.
+ErrorOr<space_info> disk_space(const Twine &Path);
+
+/// This class represents a memory mapped file. It is based on
+/// boost::iostreams::mapped_file.
+class mapped_file_region {
+public:
+ enum mapmode {
+ readonly, ///< May only access map via const_data as read only.
+ readwrite, ///< May access map via data and modify it. Written to path.
+ priv ///< May modify via data, but changes are lost on destruction.
+ };
+
+private:
+ /// Platform-specific mapping state.
+ size_t Size = 0;
+ void *Mapping = nullptr;
+#ifdef _WIN32
+ sys::fs::file_t FileHandle = nullptr;
+#endif
+ mapmode Mode = readonly;
+
+ void copyFrom(const mapped_file_region &Copied) {
+ Size = Copied.Size;
+ Mapping = Copied.Mapping;
+#ifdef _WIN32
+ FileHandle = Copied.FileHandle;
+#endif
+ Mode = Copied.Mode;
+ }
+
+ void moveFromImpl(mapped_file_region &Moved) {
+ copyFrom(Moved);
+ Moved.copyFrom(mapped_file_region());
+ }
+
+ void unmapImpl();
+ void dontNeedImpl();
+
+ std::error_code init(sys::fs::file_t FD, uint64_t Offset, mapmode Mode);
+
+public:
+ mapped_file_region() = default;
+ mapped_file_region(mapped_file_region &&Moved) { moveFromImpl(Moved); }
+ mapped_file_region &operator=(mapped_file_region &&Moved) {
+ unmap();
+ moveFromImpl(Moved);
+ return *this;
+ }
+
+ mapped_file_region(const mapped_file_region &) = delete;
+ mapped_file_region &operator=(const mapped_file_region &) = delete;
+
+ /// \param fd An open file descriptor to map. Does not take ownership of fd.
+ mapped_file_region(sys::fs::file_t fd, mapmode mode, size_t length, uint64_t offset,
+ std::error_code &ec);
+
+ ~mapped_file_region() { unmapImpl(); }
+
+ /// Check if this is a valid mapping.
+ explicit operator bool() const { return Mapping; }
+
+ /// Unmap.
+ void unmap() {
+ unmapImpl();
+ copyFrom(mapped_file_region());
+ }
+ void dontNeed() { dontNeedImpl(); }
+
+ size_t size() const;
+ char *data() const;
+
+ /// Get a const view of the data. Modifying this memory has undefined
+ /// behavior.
+ const char *const_data() const;
+
+ /// \returns The minimum alignment offset must be.
+ static int alignment();
+};
+
+/// Return the path to the main executable, given the value of argv[0] from
+/// program startup and the address of main itself. In extremis, this function
+/// may fail and return an empty path.
+std::string getMainExecutable(const char *argv0, void *MainExecAddr);
+
+/// @}
+/// @name Iterators
+/// @{
+
+/// directory_entry - A single entry in a directory.
+class directory_entry {
+ // FIXME: different platforms make different information available "for free"
+ // when traversing a directory. The design of this class wraps most of the
+ // information in basic_file_status, so on platforms where we can't populate
+ // that whole structure, callers end up paying for a stat().
+ // std::filesystem::directory_entry may be a better model.
+ std::string Path;
+ file_type Type = file_type::type_unknown; // Most platforms can provide this.
+ bool FollowSymlinks = true; // Affects the behavior of status().
+ basic_file_status Status; // If available.
+
+public:
+ explicit directory_entry(const Twine &Path, bool FollowSymlinks = true,
+ file_type Type = file_type::type_unknown,
+ basic_file_status Status = basic_file_status())
+ : Path(Path.str()), Type(Type), FollowSymlinks(FollowSymlinks),
+ Status(Status) {}
+
+ directory_entry() = default;
+
+ void replace_filename(const Twine &Filename, file_type Type,
+ basic_file_status Status = basic_file_status());
+
+ const std::string &path() const { return Path; }
+ // Get basic information about entry file (a subset of fs::status()).
+ // On most platforms this is a stat() call.
+ // On windows the information was already retrieved from the directory.
+ ErrorOr<basic_file_status> status() const;
+ // Get the type of this file.
+ // On most platforms (Linux/Mac/Windows/BSD), this was already retrieved.
+ // On some platforms (e.g. Solaris) this is a stat() call.
+ file_type type() const {
+ if (Type != file_type::type_unknown)
+ return Type;
+ auto S = status();
+ return S ? S->type() : file_type::type_unknown;
+ }
+
+ bool operator==(const directory_entry& RHS) const { return Path == RHS.Path; }
+ bool operator!=(const directory_entry& RHS) const { return !(*this == RHS); }
+ bool operator< (const directory_entry& RHS) const;
+ bool operator<=(const directory_entry& RHS) const;
+ bool operator> (const directory_entry& RHS) const;
+ bool operator>=(const directory_entry& RHS) const;
+};
+
+namespace detail {
+
+ struct DirIterState;
+
+ std::error_code directory_iterator_construct(DirIterState &, StringRef, bool);
+ std::error_code directory_iterator_increment(DirIterState &);
+ std::error_code directory_iterator_destruct(DirIterState &);
+
+ /// Keeps state for the directory_iterator.
+ struct DirIterState {
+ ~DirIterState() {
+ directory_iterator_destruct(*this);
+ }
+
+ intptr_t IterationHandle = 0;
+ directory_entry CurrentEntry;
+ };
+
+} // end namespace detail
+
+/// directory_iterator - Iterates through the entries in path. There is no
+/// operator++ because we need an error_code. If it's really needed we can make
+/// it call report_fatal_error on error.
+class directory_iterator {
+ std::shared_ptr<detail::DirIterState> State;
+ bool FollowSymlinks = true;
+
+public:
+ explicit directory_iterator(const Twine &path, std::error_code &ec,
+ bool follow_symlinks = true)
+ : FollowSymlinks(follow_symlinks) {
+ State = std::make_shared<detail::DirIterState>();
+ SmallString<128> path_storage;
+ ec = detail::directory_iterator_construct(
+ *State, path.toStringRef(path_storage), FollowSymlinks);
+ }
+
+ explicit directory_iterator(const directory_entry &de, std::error_code &ec,
+ bool follow_symlinks = true)
+ : FollowSymlinks(follow_symlinks) {
+ State = std::make_shared<detail::DirIterState>();
+ ec = detail::directory_iterator_construct(
+ *State, de.path(), FollowSymlinks);
+ }
+
+ /// Construct end iterator.
+ directory_iterator() = default;
+
+ // No operator++ because we need error_code.
+ directory_iterator &increment(std::error_code &ec) {
+ ec = directory_iterator_increment(*State);
+ return *this;
+ }
+
+ const directory_entry &operator*() const { return State->CurrentEntry; }
+ const directory_entry *operator->() const { return &State->CurrentEntry; }
+
+ bool operator==(const directory_iterator &RHS) const {
+ if (State == RHS.State)
+ return true;
+ if (!RHS.State)
+ return State->CurrentEntry == directory_entry();
+ if (!State)
+ return RHS.State->CurrentEntry == directory_entry();
+ return State->CurrentEntry == RHS.State->CurrentEntry;
+ }
+
+ bool operator!=(const directory_iterator &RHS) const {
+ return !(*this == RHS);
+ }
+};
+
+namespace detail {
+
+ /// Keeps state for the recursive_directory_iterator.
+ struct RecDirIterState {
+ std::stack<directory_iterator, std::vector<directory_iterator>> Stack;
+ uint16_t Level = 0;
+ bool HasNoPushRequest = false;
+ };
+
+} // end namespace detail
+
+/// recursive_directory_iterator - Same as directory_iterator except for it
+/// recurses down into child directories.
+class recursive_directory_iterator {
+ std::shared_ptr<detail::RecDirIterState> State;
+ bool Follow;
+
+public:
+ recursive_directory_iterator() = default;
+ explicit recursive_directory_iterator(const Twine &path, std::error_code &ec,
+ bool follow_symlinks = true)
+ : State(std::make_shared<detail::RecDirIterState>()),
+ Follow(follow_symlinks) {
+ State->Stack.push(directory_iterator(path, ec, Follow));
+ if (State->Stack.top() == directory_iterator())
+ State.reset();
+ }
+
+ // No operator++ because we need error_code.
+ recursive_directory_iterator &increment(std::error_code &ec) {
+ const directory_iterator end_itr = {};
+
+ if (State->HasNoPushRequest)
+ State->HasNoPushRequest = false;
+ else {
+ file_type type = State->Stack.top()->type();
+ if (type == file_type::symlink_file && Follow) {
+ // Resolve the symlink: is it a directory to recurse into?
+ ErrorOr<basic_file_status> status = State->Stack.top()->status();
+ if (status)
+ type = status->type();
+ // Otherwise broken symlink, and we'll continue.
+ }
+ if (type == file_type::directory_file) {
+ State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
+ if (State->Stack.top() != end_itr) {
+ ++State->Level;
+ return *this;
+ }
+ State->Stack.pop();
+ }
+ }
+
+ while (!State->Stack.empty()
+ && State->Stack.top().increment(ec) == end_itr) {
+ State->Stack.pop();
+ --State->Level;
+ }
+
+ // Check if we are done. If so, create an end iterator.
+ if (State->Stack.empty())
+ State.reset();
+
+ return *this;
+ }
+
+ const directory_entry &operator*() const { return *State->Stack.top(); }
+ const directory_entry *operator->() const { return &*State->Stack.top(); }
+
+ // observers
+ /// Gets the current level. Starting path is at level 0.
+ int level() const { return State->Level; }
+
+ /// Returns true if no_push has been called for this directory_entry.
+ bool no_push_request() const { return State->HasNoPushRequest; }
+
+ // modifiers
+ /// Goes up one level if Level > 0.
+ void pop() {
+ assert(State && "Cannot pop an end iterator!");
+ assert(State->Level > 0 && "Cannot pop an iterator with level < 1");
+
+ const directory_iterator end_itr = {};
+ std::error_code ec;
+ do {
+ if (ec)
+ report_fatal_error("Error incrementing directory iterator.");
+ State->Stack.pop();
+ --State->Level;
+ } while (!State->Stack.empty()
+ && State->Stack.top().increment(ec) == end_itr);
+
+ // Check if we are done. If so, create an end iterator.
+ if (State->Stack.empty())
+ State.reset();
+ }
+
+ /// Does not go down into the current directory_entry.
+ void no_push() { State->HasNoPushRequest = true; }
+
+ bool operator==(const recursive_directory_iterator &RHS) const {
+ return State == RHS.State;
+ }
+
+ bool operator!=(const recursive_directory_iterator &RHS) const {
+ return !(*this == RHS);
+ }
+};
+
+/// @}
+
+} // end namespace fs
+} // end namespace sys
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_FILESYSTEM_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FileSystem/UniqueID.h b/contrib/libs/llvm16/include/llvm/Support/FileSystem/UniqueID.h
new file mode 100644
index 00000000000..ef2458284e4
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FileSystem/UniqueID.h
@@ -0,0 +1,90 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/FileSystem/UniqueID.h - UniqueID for files --*- 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 is cut out of llvm/Support/FileSystem.h to allow UniqueID to be
+// reused without bloating the includes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H
+#define LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include <cstdint>
+#include <utility>
+
+namespace llvm {
+namespace sys {
+namespace fs {
+
+class UniqueID {
+ uint64_t Device;
+ uint64_t File;
+
+public:
+ UniqueID() = default;
+ UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {}
+
+ bool operator==(const UniqueID &Other) const {
+ return Device == Other.Device && File == Other.File;
+ }
+ bool operator!=(const UniqueID &Other) const { return !(*this == Other); }
+ bool operator<(const UniqueID &Other) const {
+ /// Don't use std::tie since it bloats the compile time of this header.
+ if (Device < Other.Device)
+ return true;
+ if (Other.Device < Device)
+ return false;
+ return File < Other.File;
+ }
+
+ uint64_t getDevice() const { return Device; }
+ uint64_t getFile() const { return File; }
+};
+
+} // end namespace fs
+} // end namespace sys
+
+// Support UniqueIDs as DenseMap keys.
+template <> struct DenseMapInfo<llvm::sys::fs::UniqueID> {
+ static inline llvm::sys::fs::UniqueID getEmptyKey() {
+ auto EmptyKey = DenseMapInfo<std::pair<uint64_t, uint64_t>>::getEmptyKey();
+ return {EmptyKey.first, EmptyKey.second};
+ }
+
+ static inline llvm::sys::fs::UniqueID getTombstoneKey() {
+ auto TombstoneKey =
+ DenseMapInfo<std::pair<uint64_t, uint64_t>>::getTombstoneKey();
+ return {TombstoneKey.first, TombstoneKey.second};
+ }
+
+ static hash_code getHashValue(const llvm::sys::fs::UniqueID &Tag) {
+ return hash_value(std::make_pair(Tag.getDevice(), Tag.getFile()));
+ }
+
+ static bool isEqual(const llvm::sys::fs::UniqueID &LHS,
+ const llvm::sys::fs::UniqueID &RHS) {
+ return LHS == RHS;
+ }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_FILESYSTEM_UNIQUEID_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FileUtilities.h b/contrib/libs/llvm16/include/llvm/Support/FileUtilities.h
new file mode 100644
index 00000000000..38efd554cd8
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FileUtilities.h
@@ -0,0 +1,148 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/FileUtilities.h - File System Utilities -----*- 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 defines a family of utility functions which are useful for doing
+// various things with files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FILEUTILITIES_H
+#define LLVM_SUPPORT_FILEUTILITIES_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+
+#include <system_error>
+
+namespace llvm {
+
+ /// DiffFilesWithTolerance - Compare the two files specified, returning 0 if
+ /// the files match, 1 if they are different, and 2 if there is a file error.
+ /// This function allows you to specify an absolute and relative FP error that
+ /// is allowed to exist. If you specify a string to fill in for the error
+ /// option, it will set the string to an error message if an error occurs, or
+ /// if the files are different.
+ ///
+ int DiffFilesWithTolerance(StringRef FileA,
+ StringRef FileB,
+ double AbsTol, double RelTol,
+ std::string *Error = nullptr);
+
+
+ /// FileRemover - This class is a simple object meant to be stack allocated.
+ /// If an exception is thrown from a region, the object removes the filename
+ /// specified (if deleteIt is true).
+ ///
+ class FileRemover {
+ SmallString<128> Filename;
+ bool DeleteIt;
+ public:
+ FileRemover() : DeleteIt(false) {}
+
+ explicit FileRemover(const Twine& filename, bool deleteIt = true)
+ : DeleteIt(deleteIt) {
+ filename.toVector(Filename);
+ }
+
+ ~FileRemover() {
+ if (DeleteIt) {
+ // Ignore problems deleting the file.
+ sys::fs::remove(Filename);
+ }
+ }
+
+ /// setFile - Give ownership of the file to the FileRemover so it will
+ /// be removed when the object is destroyed. If the FileRemover already
+ /// had ownership of a file, remove it first.
+ void setFile(const Twine& filename, bool deleteIt = true) {
+ if (DeleteIt) {
+ // Ignore problems deleting the file.
+ sys::fs::remove(Filename);
+ }
+
+ Filename.clear();
+ filename.toVector(Filename);
+ DeleteIt = deleteIt;
+ }
+
+ /// releaseFile - Take ownership of the file away from the FileRemover so it
+ /// will not be removed when the object is destroyed.
+ void releaseFile() { DeleteIt = false; }
+ };
+
+ enum class atomic_write_error {
+ failed_to_create_uniq_file = 0,
+ output_stream_error,
+ failed_to_rename_temp_file
+ };
+
+ class AtomicFileWriteError : public llvm::ErrorInfo<AtomicFileWriteError> {
+ public:
+ AtomicFileWriteError(atomic_write_error Error) : Error(Error) {}
+
+ void log(raw_ostream &OS) const override;
+
+ const atomic_write_error Error;
+ static char ID;
+
+ private:
+ // Users are not expected to use error_code.
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+ };
+
+ // atomic_write_error + whatever the Writer can return
+
+ /// Creates a unique file with name according to the given \p TempPathModel,
+ /// writes content of \p Buffer to the file and renames it to \p FinalPath.
+ ///
+ /// \returns \c AtomicFileWriteError in case of error.
+ llvm::Error writeFileAtomically(StringRef TempPathModel, StringRef FinalPath,
+ StringRef Buffer);
+
+ llvm::Error
+ writeFileAtomically(StringRef TempPathModel, StringRef FinalPath,
+ std::function<llvm::Error(llvm::raw_ostream &)> Writer);
+
+ /// FilePermssionsApplier helps to copy permissions from an input file to
+ /// an output one. It memorizes the status of the input file and can apply
+ /// permissions and dates to the output file.
+ class FilePermissionsApplier {
+ public:
+ static Expected<FilePermissionsApplier> create(StringRef InputFilename);
+
+ /// Apply stored permissions to the \p OutputFilename.
+ /// Copy LastAccess and ModificationTime if \p CopyDates is true.
+ /// Overwrite stored permissions if \p OverwritePermissions is specified.
+ Error
+ apply(StringRef OutputFilename, bool CopyDates = false,
+ std::optional<sys::fs::perms> OverwritePermissions = std::nullopt);
+
+ private:
+ FilePermissionsApplier(StringRef InputFilename, sys::fs::file_status Status)
+ : InputFilename(InputFilename), InputStatus(Status) {}
+
+ StringRef InputFilename;
+ sys::fs::file_status InputStatus;
+ };
+} // End llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Format.h b/contrib/libs/llvm16/include/llvm/Support/Format.h
new file mode 100644
index 00000000000..53ce73f478e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Format.h
@@ -0,0 +1,269 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- Format.h - Efficient printf-style formatting for streams -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the format() function, which can be used with other
+// LLVM subsystems to provide printf-style formatting. This gives all the power
+// and risk of printf. This can be used like this (with raw_ostreams as an
+// example):
+//
+// OS << "mynumber: " << format("%4.5f", 1234.412) << '\n';
+//
+// Or if you prefer:
+//
+// OS << format("mynumber: %4.5f\n", 1234.412);
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMAT_H
+#define LLVM_SUPPORT_FORMAT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+#include <cstdio>
+#include <tuple>
+#include <utility>
+
+namespace llvm {
+
+/// This is a helper class used for handling formatted output. It is the
+/// abstract base class of a templated derived class.
+class format_object_base {
+protected:
+ const char *Fmt;
+ ~format_object_base() = default; // Disallow polymorphic deletion.
+ format_object_base(const format_object_base &) = default;
+ virtual void home(); // Out of line virtual method.
+
+ /// Call snprintf() for this object, on the given buffer and size.
+ virtual int snprint(char *Buffer, unsigned BufferSize) const = 0;
+
+public:
+ format_object_base(const char *fmt) : Fmt(fmt) {}
+
+ /// Format the object into the specified buffer. On success, this returns
+ /// the length of the formatted string. If the buffer is too small, this
+ /// returns a length to retry with, which will be larger than BufferSize.
+ unsigned print(char *Buffer, unsigned BufferSize) const {
+ assert(BufferSize && "Invalid buffer size!");
+
+ // Print the string, leaving room for the terminating null.
+ int N = snprint(Buffer, BufferSize);
+
+ // VC++ and old GlibC return negative on overflow, just double the size.
+ if (N < 0)
+ return BufferSize * 2;
+
+ // Other implementations yield number of bytes needed, not including the
+ // final '\0'.
+ if (unsigned(N) >= BufferSize)
+ return N + 1;
+
+ // Otherwise N is the length of output (not including the final '\0').
+ return N;
+ }
+};
+
+/// These are templated helper classes used by the format function that
+/// capture the object to be formatted and the format string. When actually
+/// printed, this synthesizes the string into a temporary buffer provided and
+/// returns whether or not it is big enough.
+
+// Helper to validate that format() parameters are scalars or pointers.
+template <typename... Args> struct validate_format_parameters;
+template <typename Arg, typename... Args>
+struct validate_format_parameters<Arg, Args...> {
+ static_assert(std::is_scalar_v<Arg>,
+ "format can't be used with non fundamental / non pointer type");
+ validate_format_parameters() { validate_format_parameters<Args...>(); }
+};
+template <> struct validate_format_parameters<> {};
+
+template <typename... Ts>
+class format_object final : public format_object_base {
+ std::tuple<Ts...> Vals;
+
+ template <std::size_t... Is>
+ int snprint_tuple(char *Buffer, unsigned BufferSize,
+ std::index_sequence<Is...>) const {
+#ifdef _MSC_VER
+ return _snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...);
+#else
+ return snprintf(Buffer, BufferSize, Fmt, std::get<Is>(Vals)...);
+#endif
+ }
+
+public:
+ format_object(const char *fmt, const Ts &... vals)
+ : format_object_base(fmt), Vals(vals...) {
+ validate_format_parameters<Ts...>();
+ }
+
+ int snprint(char *Buffer, unsigned BufferSize) const override {
+ return snprint_tuple(Buffer, BufferSize, std::index_sequence_for<Ts...>());
+ }
+};
+
+/// These are helper functions used to produce formatted output. They use
+/// template type deduction to construct the appropriate instance of the
+/// format_object class to simplify their construction.
+///
+/// This is typically used like:
+/// \code
+/// OS << format("%0.4f", myfloat) << '\n';
+/// \endcode
+
+template <typename... Ts>
+inline format_object<Ts...> format(const char *Fmt, const Ts &... Vals) {
+ return format_object<Ts...>(Fmt, Vals...);
+}
+
+/// This is a helper class for left_justify, right_justify, and center_justify.
+class FormattedString {
+public:
+ enum Justification { JustifyNone, JustifyLeft, JustifyRight, JustifyCenter };
+ FormattedString(StringRef S, unsigned W, Justification J)
+ : Str(S), Width(W), Justify(J) {}
+
+private:
+ StringRef Str;
+ unsigned Width;
+ Justification Justify;
+ friend class raw_ostream;
+};
+
+/// left_justify - append spaces after string so total output is
+/// \p Width characters. If \p Str is larger that \p Width, full string
+/// is written with no padding.
+inline FormattedString left_justify(StringRef Str, unsigned Width) {
+ return FormattedString(Str, Width, FormattedString::JustifyLeft);
+}
+
+/// right_justify - add spaces before string so total output is
+/// \p Width characters. If \p Str is larger that \p Width, full string
+/// is written with no padding.
+inline FormattedString right_justify(StringRef Str, unsigned Width) {
+ return FormattedString(Str, Width, FormattedString::JustifyRight);
+}
+
+/// center_justify - add spaces before and after string so total output is
+/// \p Width characters. If \p Str is larger that \p Width, full string
+/// is written with no padding.
+inline FormattedString center_justify(StringRef Str, unsigned Width) {
+ return FormattedString(Str, Width, FormattedString::JustifyCenter);
+}
+
+/// This is a helper class used for format_hex() and format_decimal().
+class FormattedNumber {
+ uint64_t HexValue;
+ int64_t DecValue;
+ unsigned Width;
+ bool Hex;
+ bool Upper;
+ bool HexPrefix;
+ friend class raw_ostream;
+
+public:
+ FormattedNumber(uint64_t HV, int64_t DV, unsigned W, bool H, bool U,
+ bool Prefix)
+ : HexValue(HV), DecValue(DV), Width(W), Hex(H), Upper(U),
+ HexPrefix(Prefix) {}
+};
+
+/// format_hex - Output \p N as a fixed width hexadecimal. If number will not
+/// fit in width, full number is still printed. Examples:
+/// OS << format_hex(255, 4) => 0xff
+/// OS << format_hex(255, 4, true) => 0xFF
+/// OS << format_hex(255, 6) => 0x00ff
+/// OS << format_hex(255, 2) => 0xff
+inline FormattedNumber format_hex(uint64_t N, unsigned Width,
+ bool Upper = false) {
+ assert(Width <= 18 && "hex width must be <= 18");
+ return FormattedNumber(N, 0, Width, true, Upper, true);
+}
+
+/// format_hex_no_prefix - Output \p N as a fixed width hexadecimal. Does not
+/// prepend '0x' to the outputted string. If number will not fit in width,
+/// full number is still printed. Examples:
+/// OS << format_hex_no_prefix(255, 2) => ff
+/// OS << format_hex_no_prefix(255, 2, true) => FF
+/// OS << format_hex_no_prefix(255, 4) => 00ff
+/// OS << format_hex_no_prefix(255, 1) => ff
+inline FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width,
+ bool Upper = false) {
+ assert(Width <= 16 && "hex width must be <= 16");
+ return FormattedNumber(N, 0, Width, true, Upper, false);
+}
+
+/// format_decimal - Output \p N as a right justified, fixed-width decimal. If
+/// number will not fit in width, full number is still printed. Examples:
+/// OS << format_decimal(0, 5) => " 0"
+/// OS << format_decimal(255, 5) => " 255"
+/// OS << format_decimal(-1, 3) => " -1"
+/// OS << format_decimal(12345, 3) => "12345"
+inline FormattedNumber format_decimal(int64_t N, unsigned Width) {
+ return FormattedNumber(0, N, Width, false, false, false);
+}
+
+class FormattedBytes {
+ ArrayRef<uint8_t> Bytes;
+
+ // If not None, display offsets for each line relative to starting value.
+ std::optional<uint64_t> FirstByteOffset;
+ uint32_t IndentLevel; // Number of characters to indent each line.
+ uint32_t NumPerLine; // Number of bytes to show per line.
+ uint8_t ByteGroupSize; // How many hex bytes are grouped without spaces
+ bool Upper; // Show offset and hex bytes as upper case.
+ bool ASCII; // Show the ASCII bytes for the hex bytes to the right.
+ friend class raw_ostream;
+
+public:
+ FormattedBytes(ArrayRef<uint8_t> B, uint32_t IL, std::optional<uint64_t> O,
+ uint32_t NPL, uint8_t BGS, bool U, bool A)
+ : Bytes(B), FirstByteOffset(O), IndentLevel(IL), NumPerLine(NPL),
+ ByteGroupSize(BGS), Upper(U), ASCII(A) {
+
+ if (ByteGroupSize > NumPerLine)
+ ByteGroupSize = NumPerLine;
+ }
+};
+
+inline FormattedBytes
+format_bytes(ArrayRef<uint8_t> Bytes,
+ std::optional<uint64_t> FirstByteOffset = std::nullopt,
+ uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
+ uint32_t IndentLevel = 0, bool Upper = false) {
+ return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
+ ByteGroupSize, Upper, false);
+}
+
+inline FormattedBytes
+format_bytes_with_ascii(ArrayRef<uint8_t> Bytes,
+ std::optional<uint64_t> FirstByteOffset = std::nullopt,
+ uint32_t NumPerLine = 16, uint8_t ByteGroupSize = 4,
+ uint32_t IndentLevel = 0, bool Upper = false) {
+ return FormattedBytes(Bytes, IndentLevel, FirstByteOffset, NumPerLine,
+ ByteGroupSize, Upper, true);
+}
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FormatAdapters.h b/contrib/libs/llvm16/include/llvm/Support/FormatAdapters.h
new file mode 100644
index 00000000000..df8d719a451
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FormatAdapters.h
@@ -0,0 +1,120 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- FormatAdapters.h - Formatters for common LLVM types -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATADAPTERS_H
+#define LLVM_SUPPORT_FORMATADAPTERS_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatCommon.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+template <typename T> class FormatAdapter : public detail::format_adapter {
+protected:
+ explicit FormatAdapter(T &&Item) : Item(std::forward<T>(Item)) {}
+
+ T Item;
+};
+
+namespace detail {
+template <typename T> class AlignAdapter final : public FormatAdapter<T> {
+ AlignStyle Where;
+ size_t Amount;
+ char Fill;
+
+public:
+ AlignAdapter(T &&Item, AlignStyle Where, size_t Amount, char Fill)
+ : FormatAdapter<T>(std::forward<T>(Item)), Where(Where), Amount(Amount),
+ Fill(Fill) {}
+
+ void format(llvm::raw_ostream &Stream, StringRef Style) override {
+ auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item));
+ FmtAlign(Adapter, Where, Amount, Fill).format(Stream, Style);
+ }
+};
+
+template <typename T> class PadAdapter final : public FormatAdapter<T> {
+ size_t Left;
+ size_t Right;
+
+public:
+ PadAdapter(T &&Item, size_t Left, size_t Right)
+ : FormatAdapter<T>(std::forward<T>(Item)), Left(Left), Right(Right) {}
+
+ void format(llvm::raw_ostream &Stream, StringRef Style) override {
+ auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item));
+ Stream.indent(Left);
+ Adapter.format(Stream, Style);
+ Stream.indent(Right);
+ }
+};
+
+template <typename T> class RepeatAdapter final : public FormatAdapter<T> {
+ size_t Count;
+
+public:
+ RepeatAdapter(T &&Item, size_t Count)
+ : FormatAdapter<T>(std::forward<T>(Item)), Count(Count) {}
+
+ void format(llvm::raw_ostream &Stream, StringRef Style) override {
+ auto Adapter = detail::build_format_adapter(std::forward<T>(this->Item));
+ for (size_t I = 0; I < Count; ++I) {
+ Adapter.format(Stream, Style);
+ }
+ }
+};
+
+class ErrorAdapter : public FormatAdapter<Error> {
+public:
+ ErrorAdapter(Error &&Item) : FormatAdapter(std::move(Item)) {}
+ ErrorAdapter(ErrorAdapter &&) = default;
+ ~ErrorAdapter() { consumeError(std::move(Item)); }
+ void format(llvm::raw_ostream &Stream, StringRef Style) override {
+ Stream << Item;
+ }
+};
+}
+
+template <typename T>
+detail::AlignAdapter<T> fmt_align(T &&Item, AlignStyle Where, size_t Amount,
+ char Fill = ' ') {
+ return detail::AlignAdapter<T>(std::forward<T>(Item), Where, Amount, Fill);
+}
+
+template <typename T>
+detail::PadAdapter<T> fmt_pad(T &&Item, size_t Left, size_t Right) {
+ return detail::PadAdapter<T>(std::forward<T>(Item), Left, Right);
+}
+
+template <typename T>
+detail::RepeatAdapter<T> fmt_repeat(T &&Item, size_t Count) {
+ return detail::RepeatAdapter<T>(std::forward<T>(Item), Count);
+}
+
+// llvm::Error values must be consumed before being destroyed.
+// Wrapping an error in fmt_consume explicitly indicates that the formatv_object
+// should take ownership and consume it.
+inline detail::ErrorAdapter fmt_consume(Error &&Item) {
+ return detail::ErrorAdapter(std::move(Item));
+}
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FormatCommon.h b/contrib/libs/llvm16/include/llvm/Support/FormatCommon.h
new file mode 100644
index 00000000000..705905ed6de
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FormatCommon.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- FormatCommon.h - Formatters for common LLVM types --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATCOMMON_H
+#define LLVM_SUPPORT_FORMATCOMMON_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+enum class AlignStyle { Left, Center, Right };
+
+struct FmtAlign {
+ detail::format_adapter &Adapter;
+ AlignStyle Where;
+ size_t Amount;
+ char Fill;
+
+ FmtAlign(detail::format_adapter &Adapter, AlignStyle Where, size_t Amount,
+ char Fill = ' ')
+ : Adapter(Adapter), Where(Where), Amount(Amount), Fill(Fill) {}
+
+ void format(raw_ostream &S, StringRef Options) {
+ // If we don't need to align, we can format straight into the underlying
+ // stream. Otherwise we have to go through an intermediate stream first
+ // in order to calculate how long the output is so we can align it.
+ // TODO: Make the format method return the number of bytes written, that
+ // way we can also skip the intermediate stream for left-aligned output.
+ if (Amount == 0) {
+ Adapter.format(S, Options);
+ return;
+ }
+ SmallString<64> Item;
+ raw_svector_ostream Stream(Item);
+
+ Adapter.format(Stream, Options);
+ if (Amount <= Item.size()) {
+ S << Item;
+ return;
+ }
+
+ size_t PadAmount = Amount - Item.size();
+ switch (Where) {
+ case AlignStyle::Left:
+ S << Item;
+ fill(S, PadAmount);
+ break;
+ case AlignStyle::Center: {
+ size_t X = PadAmount / 2;
+ fill(S, X);
+ S << Item;
+ fill(S, PadAmount - X);
+ break;
+ }
+ default:
+ fill(S, PadAmount);
+ S << Item;
+ break;
+ }
+ }
+
+private:
+ void fill(llvm::raw_ostream &S, uint32_t Count) {
+ for (uint32_t I = 0; I < Count; ++I)
+ S << Fill;
+ }
+};
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FormatProviders.h b/contrib/libs/llvm16/include/llvm/Support/FormatProviders.h
new file mode 100644
index 00000000000..f50f355bb6e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FormatProviders.h
@@ -0,0 +1,430 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- FormatProviders.h - Formatters for common LLVM types -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements format providers for many common LLVM types, for example
+// allowing precision and width specifiers for scalar and string types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATPROVIDERS_H
+#define LLVM_SUPPORT_FORMATPROVIDERS_H
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/Support/NativeFormatting.h"
+
+#include <array>
+#include <optional>
+#include <type_traits>
+
+namespace llvm {
+namespace detail {
+template <typename T>
+struct use_integral_formatter
+ : public std::integral_constant<
+ bool, is_one_of<T, uint8_t, int16_t, uint16_t, int32_t, uint32_t,
+ int64_t, uint64_t, int, unsigned, long, unsigned long,
+ long long, unsigned long long>::value> {};
+
+template <typename T>
+struct use_char_formatter
+ : public std::integral_constant<bool, std::is_same<T, char>::value> {};
+
+template <typename T>
+struct is_cstring
+ : public std::integral_constant<bool,
+ is_one_of<T, char *, const char *>::value> {
+};
+
+template <typename T>
+struct use_string_formatter
+ : public std::integral_constant<bool,
+ std::is_convertible<T, llvm::StringRef>::value> {};
+
+template <typename T>
+struct use_pointer_formatter
+ : public std::integral_constant<bool, std::is_pointer<T>::value &&
+ !is_cstring<T>::value> {};
+
+template <typename T>
+struct use_double_formatter
+ : public std::integral_constant<bool, std::is_floating_point<T>::value> {};
+
+class HelperFunctions {
+protected:
+ static std::optional<size_t> parseNumericPrecision(StringRef Str) {
+ size_t Prec;
+ std::optional<size_t> Result;
+ if (Str.empty())
+ Result = std::nullopt;
+ else if (Str.getAsInteger(10, Prec)) {
+ assert(false && "Invalid precision specifier");
+ Result = std::nullopt;
+ } else {
+ assert(Prec < 100 && "Precision out of range");
+ Result = std::min<size_t>(99u, Prec);
+ }
+ return Result;
+ }
+
+ static bool consumeHexStyle(StringRef &Str, HexPrintStyle &Style) {
+ if (!Str.startswith_insensitive("x"))
+ return false;
+
+ if (Str.consume_front("x-"))
+ Style = HexPrintStyle::Lower;
+ else if (Str.consume_front("X-"))
+ Style = HexPrintStyle::Upper;
+ else if (Str.consume_front("x+") || Str.consume_front("x"))
+ Style = HexPrintStyle::PrefixLower;
+ else if (Str.consume_front("X+") || Str.consume_front("X"))
+ Style = HexPrintStyle::PrefixUpper;
+ return true;
+ }
+
+ static size_t consumeNumHexDigits(StringRef &Str, HexPrintStyle Style,
+ size_t Default) {
+ Str.consumeInteger(10, Default);
+ if (isPrefixedHexStyle(Style))
+ Default += 2;
+ return Default;
+ }
+};
+}
+
+/// Implementation of format_provider<T> for integral arithmetic types.
+///
+/// The options string of an integral type has the grammar:
+///
+/// integer_options :: [style][digits]
+/// style :: <see table below>
+/// digits :: <non-negative integer> 0-99
+///
+/// ==========================================================================
+/// | style | Meaning | Example | Digits Meaning |
+/// --------------------------------------------------------------------------
+/// | | | Input | Output | |
+/// ==========================================================================
+/// | x- | Hex no prefix, lower | 42 | 2a | Minimum # digits |
+/// | X- | Hex no prefix, upper | 42 | 2A | Minimum # digits |
+/// | x+ / x | Hex + prefix, lower | 42 | 0x2a | Minimum # digits |
+/// | X+ / X | Hex + prefix, upper | 42 | 0x2A | Minimum # digits |
+/// | N / n | Digit grouped number | 123456 | 123,456 | Ignored |
+/// | D / d | Integer | 100000 | 100000 | Ignored |
+/// | (empty) | Same as D / d | | | |
+/// ==========================================================================
+///
+
+template <typename T>
+struct format_provider<
+ T, std::enable_if_t<detail::use_integral_formatter<T>::value>>
+ : public detail::HelperFunctions {
+private:
+public:
+ static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
+ HexPrintStyle HS;
+ size_t Digits = 0;
+ if (consumeHexStyle(Style, HS)) {
+ Digits = consumeNumHexDigits(Style, HS, 0);
+ write_hex(Stream, V, HS, Digits);
+ return;
+ }
+
+ IntegerStyle IS = IntegerStyle::Integer;
+ if (Style.consume_front("N") || Style.consume_front("n"))
+ IS = IntegerStyle::Number;
+ else if (Style.consume_front("D") || Style.consume_front("d"))
+ IS = IntegerStyle::Integer;
+
+ Style.consumeInteger(10, Digits);
+ assert(Style.empty() && "Invalid integral format style!");
+ write_integer(Stream, V, Digits, IS);
+ }
+};
+
+/// Implementation of format_provider<T> for integral pointer types.
+///
+/// The options string of a pointer type has the grammar:
+///
+/// pointer_options :: [style][precision]
+/// style :: <see table below>
+/// digits :: <non-negative integer> 0-sizeof(void*)
+///
+/// ==========================================================================
+/// | S | Meaning | Example |
+/// --------------------------------------------------------------------------
+/// | | | Input | Output |
+/// ==========================================================================
+/// | x- | Hex no prefix, lower | 0xDEADBEEF | deadbeef |
+/// | X- | Hex no prefix, upper | 0xDEADBEEF | DEADBEEF |
+/// | x+ / x | Hex + prefix, lower | 0xDEADBEEF | 0xdeadbeef |
+/// | X+ / X | Hex + prefix, upper | 0xDEADBEEF | 0xDEADBEEF |
+/// | (empty) | Same as X+ / X | | |
+/// ==========================================================================
+///
+/// The default precision is the number of nibbles in a machine word, and in all
+/// cases indicates the minimum number of nibbles to print.
+template <typename T>
+struct format_provider<
+ T, std::enable_if_t<detail::use_pointer_formatter<T>::value>>
+ : public detail::HelperFunctions {
+private:
+public:
+ static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
+ HexPrintStyle HS = HexPrintStyle::PrefixUpper;
+ consumeHexStyle(Style, HS);
+ size_t Digits = consumeNumHexDigits(Style, HS, sizeof(void *) * 2);
+ write_hex(Stream, reinterpret_cast<std::uintptr_t>(V), HS, Digits);
+ }
+};
+
+/// Implementation of format_provider<T> for c-style strings and string
+/// objects such as std::string and llvm::StringRef.
+///
+/// The options string of a string type has the grammar:
+///
+/// string_options :: [length]
+///
+/// where `length` is an optional integer specifying the maximum number of
+/// characters in the string to print. If `length` is omitted, the string is
+/// printed up to the null terminator.
+
+template <typename T>
+struct format_provider<
+ T, std::enable_if_t<detail::use_string_formatter<T>::value>> {
+ static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
+ size_t N = StringRef::npos;
+ if (!Style.empty() && Style.getAsInteger(10, N)) {
+ assert(false && "Style is not a valid integer");
+ }
+ llvm::StringRef S = V;
+ Stream << S.substr(0, N);
+ }
+};
+
+/// Implementation of format_provider<T> for llvm::Twine.
+///
+/// This follows the same rules as the string formatter.
+
+template <> struct format_provider<Twine> {
+ static void format(const Twine &V, llvm::raw_ostream &Stream,
+ StringRef Style) {
+ format_provider<std::string>::format(V.str(), Stream, Style);
+ }
+};
+
+/// Implementation of format_provider<T> for characters.
+///
+/// The options string of a character type has the grammar:
+///
+/// char_options :: (empty) | [integer_options]
+///
+/// If `char_options` is empty, the character is displayed as an ASCII
+/// character. Otherwise, it is treated as an integer options string.
+///
+template <typename T>
+struct format_provider<T,
+ std::enable_if_t<detail::use_char_formatter<T>::value>> {
+ static void format(const char &V, llvm::raw_ostream &Stream,
+ StringRef Style) {
+ if (Style.empty())
+ Stream << V;
+ else {
+ int X = static_cast<int>(V);
+ format_provider<int>::format(X, Stream, Style);
+ }
+ }
+};
+
+/// Implementation of format_provider<T> for type `bool`
+///
+/// The options string of a boolean type has the grammar:
+///
+/// bool_options :: "" | "Y" | "y" | "D" | "d" | "T" | "t"
+///
+/// ==================================
+/// | C | Meaning |
+/// ==================================
+/// | Y | YES / NO |
+/// | y | yes / no |
+/// | D / d | Integer 0 or 1 |
+/// | T | TRUE / FALSE |
+/// | t | true / false |
+/// | (empty) | Equivalent to 't' |
+/// ==================================
+template <> struct format_provider<bool> {
+ static void format(const bool &B, llvm::raw_ostream &Stream,
+ StringRef Style) {
+ Stream << StringSwitch<const char *>(Style)
+ .Case("Y", B ? "YES" : "NO")
+ .Case("y", B ? "yes" : "no")
+ .CaseLower("D", B ? "1" : "0")
+ .Case("T", B ? "TRUE" : "FALSE")
+ .Cases("t", "", B ? "true" : "false")
+ .Default(B ? "1" : "0");
+ }
+};
+
+/// Implementation of format_provider<T> for floating point types.
+///
+/// The options string of a floating point type has the format:
+///
+/// float_options :: [style][precision]
+/// style :: <see table below>
+/// precision :: <non-negative integer> 0-99
+///
+/// =====================================================
+/// | style | Meaning | Example |
+/// -----------------------------------------------------
+/// | | | Input | Output |
+/// =====================================================
+/// | P / p | Percentage | 0.05 | 5.00% |
+/// | F / f | Fixed point | 1.0 | 1.00 |
+/// | E | Exponential with E | 100000 | 1.0E+05 |
+/// | e | Exponential with e | 100000 | 1.0e+05 |
+/// | (empty) | Same as F / f | | |
+/// =====================================================
+///
+/// The default precision is 6 for exponential (E / e) and 2 for everything
+/// else.
+
+template <typename T>
+struct format_provider<T,
+ std::enable_if_t<detail::use_double_formatter<T>::value>>
+ : public detail::HelperFunctions {
+ static void format(const T &V, llvm::raw_ostream &Stream, StringRef Style) {
+ FloatStyle S;
+ if (Style.consume_front("P") || Style.consume_front("p"))
+ S = FloatStyle::Percent;
+ else if (Style.consume_front("F") || Style.consume_front("f"))
+ S = FloatStyle::Fixed;
+ else if (Style.consume_front("E"))
+ S = FloatStyle::ExponentUpper;
+ else if (Style.consume_front("e"))
+ S = FloatStyle::Exponent;
+ else
+ S = FloatStyle::Fixed;
+
+ std::optional<size_t> Precision = parseNumericPrecision(Style);
+ if (!Precision)
+ Precision = getDefaultPrecision(S);
+
+ write_double(Stream, static_cast<double>(V), S, Precision);
+ }
+};
+
+namespace detail {
+template <typename IterT>
+using IterValue = typename std::iterator_traits<IterT>::value_type;
+
+template <typename IterT>
+struct range_item_has_provider
+ : public std::integral_constant<
+ bool, !uses_missing_provider<IterValue<IterT>>::value> {};
+}
+
+/// Implementation of format_provider<T> for ranges.
+///
+/// This will print an arbitrary range as a delimited sequence of items.
+///
+/// The options string of a range type has the grammar:
+///
+/// range_style ::= [separator] [element_style]
+/// separator ::= "$" delimeted_expr
+/// element_style ::= "@" delimeted_expr
+/// delimeted_expr ::= "[" expr "]" | "(" expr ")" | "<" expr ">"
+/// expr ::= <any string not containing delimeter>
+///
+/// where the separator expression is the string to insert between consecutive
+/// items in the range and the argument expression is the Style specification to
+/// be used when formatting the underlying type. The default separator if
+/// unspecified is ' ' (space). The syntax of the argument expression follows
+/// whatever grammar is dictated by the format provider or format adapter used
+/// to format the value type.
+///
+/// Note that attempting to format an `iterator_range<T>` where no format
+/// provider can be found for T will result in a compile error.
+///
+
+template <typename IterT> class format_provider<llvm::iterator_range<IterT>> {
+ using value = typename std::iterator_traits<IterT>::value_type;
+
+ static StringRef consumeOneOption(StringRef &Style, char Indicator,
+ StringRef Default) {
+ if (Style.empty())
+ return Default;
+ if (Style.front() != Indicator)
+ return Default;
+ Style = Style.drop_front();
+ if (Style.empty()) {
+ assert(false && "Invalid range style");
+ return Default;
+ }
+
+ for (const char *D : std::array<const char *, 3>{"[]", "<>", "()"}) {
+ if (Style.front() != D[0])
+ continue;
+ size_t End = Style.find_first_of(D[1]);
+ if (End == StringRef::npos) {
+ assert(false && "Missing range option end delimeter!");
+ return Default;
+ }
+ StringRef Result = Style.slice(1, End);
+ Style = Style.drop_front(End + 1);
+ return Result;
+ }
+ assert(false && "Invalid range style!");
+ return Default;
+ }
+
+ static std::pair<StringRef, StringRef> parseOptions(StringRef Style) {
+ StringRef Sep = consumeOneOption(Style, '$', ", ");
+ StringRef Args = consumeOneOption(Style, '@', "");
+ assert(Style.empty() && "Unexpected text in range option string!");
+ return std::make_pair(Sep, Args);
+ }
+
+public:
+ static_assert(detail::range_item_has_provider<IterT>::value,
+ "Range value_type does not have a format provider!");
+ static void format(const llvm::iterator_range<IterT> &V,
+ llvm::raw_ostream &Stream, StringRef Style) {
+ StringRef Sep;
+ StringRef ArgStyle;
+ std::tie(Sep, ArgStyle) = parseOptions(Style);
+ auto Begin = V.begin();
+ auto End = V.end();
+ if (Begin != End) {
+ auto Adapter = detail::build_format_adapter(*Begin);
+ Adapter.format(Stream, ArgStyle);
+ ++Begin;
+ }
+ while (Begin != End) {
+ Stream << Sep;
+ auto Adapter = detail::build_format_adapter(*Begin);
+ Adapter.format(Stream, ArgStyle);
+ ++Begin;
+ }
+ }
+};
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FormatVariadic.h b/contrib/libs/llvm16/include/llvm/Support/FormatVariadic.h
new file mode 100644
index 00000000000..2be48f15c1b
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FormatVariadic.h
@@ -0,0 +1,273 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- FormatVariadic.h - Efficient type-safe string formatting --*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the formatv() function which can be used with other LLVM
+// subsystems to provide printf-like formatting, but with improved safety and
+// flexibility. The result of `formatv` is an object which can be streamed to
+// a raw_ostream or converted to a std::string or llvm::SmallString.
+//
+// // Convert to std::string.
+// std::string S = formatv("{0} {1}", 1234.412, "test").str();
+//
+// // Convert to llvm::SmallString
+// SmallString<8> S = formatv("{0} {1}", 1234.412, "test").sstr<8>();
+//
+// // Stream to an existing raw_ostream.
+// OS << formatv("{0} {1}", 1234.412, "test");
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATVARIADIC_H
+#define LLVM_SUPPORT_FORMATVARIADIC_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FormatCommon.h"
+#include "llvm/Support/FormatProviders.h"
+#include "llvm/Support/FormatVariadicDetails.h"
+#include "llvm/Support/raw_ostream.h"
+#include <array>
+#include <cstddef>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <utility>
+
+namespace llvm {
+
+enum class ReplacementType { Empty, Format, Literal };
+
+struct ReplacementItem {
+ ReplacementItem() = default;
+ explicit ReplacementItem(StringRef Literal)
+ : Type(ReplacementType::Literal), Spec(Literal) {}
+ ReplacementItem(StringRef Spec, size_t Index, size_t Align, AlignStyle Where,
+ char Pad, StringRef Options)
+ : Type(ReplacementType::Format), Spec(Spec), Index(Index), Align(Align),
+ Where(Where), Pad(Pad), Options(Options) {}
+
+ ReplacementType Type = ReplacementType::Empty;
+ StringRef Spec;
+ size_t Index = 0;
+ size_t Align = 0;
+ AlignStyle Where = AlignStyle::Right;
+ char Pad = 0;
+ StringRef Options;
+};
+
+class formatv_object_base {
+protected:
+ StringRef Fmt;
+ ArrayRef<detail::format_adapter *> Adapters;
+
+ static bool consumeFieldLayout(StringRef &Spec, AlignStyle &Where,
+ size_t &Align, char &Pad);
+
+ static std::pair<ReplacementItem, StringRef>
+ splitLiteralAndReplacement(StringRef Fmt);
+
+ formatv_object_base(StringRef Fmt,
+ ArrayRef<detail::format_adapter *> Adapters)
+ : Fmt(Fmt), Adapters(Adapters) {}
+
+ formatv_object_base(formatv_object_base const &rhs) = delete;
+ formatv_object_base(formatv_object_base &&rhs) = default;
+
+public:
+ void format(raw_ostream &S) const {
+ for (auto &R : parseFormatString(Fmt)) {
+ if (R.Type == ReplacementType::Empty)
+ continue;
+ if (R.Type == ReplacementType::Literal) {
+ S << R.Spec;
+ continue;
+ }
+ if (R.Index >= Adapters.size()) {
+ S << R.Spec;
+ continue;
+ }
+
+ auto *W = Adapters[R.Index];
+
+ FmtAlign Align(*W, R.Where, R.Align, R.Pad);
+ Align.format(S, R.Options);
+ }
+ }
+ static SmallVector<ReplacementItem, 2> parseFormatString(StringRef Fmt);
+
+ static std::optional<ReplacementItem> parseReplacementItem(StringRef Spec);
+
+ std::string str() const {
+ std::string Result;
+ raw_string_ostream Stream(Result);
+ Stream << *this;
+ Stream.flush();
+ return Result;
+ }
+
+ template <unsigned N> SmallString<N> sstr() const {
+ SmallString<N> Result;
+ raw_svector_ostream Stream(Result);
+ Stream << *this;
+ return Result;
+ }
+
+ template <unsigned N> operator SmallString<N>() const { return sstr<N>(); }
+
+ operator std::string() const { return str(); }
+};
+
+template <typename Tuple> class formatv_object : public formatv_object_base {
+ // Storage for the parameter adapters. Since the base class erases the type
+ // of the parameters, we have to own the storage for the parameters here, and
+ // have the base class store type-erased pointers into this tuple.
+ Tuple Parameters;
+ std::array<detail::format_adapter *, std::tuple_size<Tuple>::value>
+ ParameterPointers;
+
+ // The parameters are stored in a std::tuple, which does not provide runtime
+ // indexing capabilities. In order to enable runtime indexing, we use this
+ // structure to put the parameters into a std::array. Since the parameters
+ // are not all the same type, we use some type-erasure by wrapping the
+ // parameters in a template class that derives from a non-template superclass.
+ // Essentially, we are converting a std::tuple<Derived<Ts...>> to a
+ // std::array<Base*>.
+ struct create_adapters {
+ template <typename... Ts>
+ std::array<detail::format_adapter *, std::tuple_size<Tuple>::value>
+ operator()(Ts &... Items) {
+ return {{&Items...}};
+ }
+ };
+
+public:
+ formatv_object(StringRef Fmt, Tuple &&Params)
+ : formatv_object_base(Fmt, ParameterPointers),
+ Parameters(std::move(Params)) {
+ ParameterPointers = std::apply(create_adapters(), Parameters);
+ }
+
+ formatv_object(formatv_object const &rhs) = delete;
+
+ formatv_object(formatv_object &&rhs)
+ : formatv_object_base(std::move(rhs)),
+ Parameters(std::move(rhs.Parameters)) {
+ ParameterPointers = std::apply(create_adapters(), Parameters);
+ Adapters = ParameterPointers;
+ }
+};
+
+// Format text given a format string and replacement parameters.
+//
+// ===General Description===
+//
+// Formats textual output. `Fmt` is a string consisting of one or more
+// replacement sequences with the following grammar:
+//
+// rep_field ::= "{" index ["," layout] [":" format] "}"
+// index ::= <non-negative integer>
+// layout ::= [[[char]loc]width]
+// format ::= <any string not containing "{" or "}">
+// char ::= <any character except "{" or "}">
+// loc ::= "-" | "=" | "+"
+// width ::= <positive integer>
+//
+// index - A non-negative integer specifying the index of the item in the
+// parameter pack to print. Any other value is invalid.
+// layout - A string controlling how the field is laid out within the available
+// space.
+// format - A type-dependent string used to provide additional options to
+// the formatting operation. Refer to the documentation of the
+// various individual format providers for per-type options.
+// char - The padding character. Defaults to ' ' (space). Only valid if
+// `loc` is also specified.
+// loc - Where to print the formatted text within the field. Only valid if
+// `width` is also specified.
+// '-' : The field is left aligned within the available space.
+// '=' : The field is centered within the available space.
+// '+' : The field is right aligned within the available space (this
+// is the default).
+// width - The width of the field within which to print the formatted text.
+// If this is less than the required length then the `char` and `loc`
+// fields are ignored, and the field is printed with no leading or
+// trailing padding. If this is greater than the required length,
+// then the text is output according to the value of `loc`, and padded
+// as appropriate on the left and/or right by `char`.
+//
+// ===Special Characters===
+//
+// The characters '{' and '}' are reserved and cannot appear anywhere within a
+// replacement sequence. Outside of a replacement sequence, in order to print
+// a literal '{' it must be doubled as "{{".
+//
+// ===Parameter Indexing===
+//
+// `index` specifies the index of the parameter in the parameter pack to format
+// into the output. Note that it is possible to refer to the same parameter
+// index multiple times in a given format string. This makes it possible to
+// output the same value multiple times without passing it multiple times to the
+// function. For example:
+//
+// formatv("{0} {1} {0}", "a", "bb")
+//
+// would yield the string "abba". This can be convenient when it is expensive
+// to compute the value of the parameter, and you would otherwise have had to
+// save it to a temporary.
+//
+// ===Formatter Search===
+//
+// For a given parameter of type T, the following steps are executed in order
+// until a match is found:
+//
+// 1. If the parameter is of class type, and inherits from format_adapter,
+// Then format() is invoked on it to produce the formatted output. The
+// implementation should write the formatted text into `Stream`.
+// 2. If there is a suitable template specialization of format_provider<>
+// for type T containing a method whose signature is:
+// void format(const T &Obj, raw_ostream &Stream, StringRef Options)
+// Then this method is invoked as described in Step 1.
+// 3. If an appropriate operator<< for raw_ostream exists, it will be used.
+// For this to work, (raw_ostream& << const T&) must return raw_ostream&.
+//
+// If a match cannot be found through either of the above methods, a compiler
+// error is generated.
+//
+// ===Invalid Format String Handling===
+//
+// In the case of a format string which does not match the grammar described
+// above, the output is undefined. With asserts enabled, LLVM will trigger an
+// assertion. Otherwise, it will try to do something reasonable, but in general
+// the details of what that is are undefined.
+//
+template <typename... Ts>
+inline auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object<decltype(
+ std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...))> {
+ using ParamTuple = decltype(
+ std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...));
+ return formatv_object<ParamTuple>(
+ Fmt,
+ std::make_tuple(detail::build_format_adapter(std::forward<Ts>(Vals))...));
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_FORMATVARIADIC_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FormatVariadicDetails.h b/contrib/libs/llvm16/include/llvm/Support/FormatVariadicDetails.h
new file mode 100644
index 00000000000..b2a794bf16d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FormatVariadicDetails.h
@@ -0,0 +1,174 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- FormatVariadicDetails.h - Helpers for FormatVariadic.h ----*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATVARIADICDETAILS_H
+#define LLVM_SUPPORT_FORMATVARIADICDETAILS_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <type_traits>
+
+namespace llvm {
+template <typename T, typename Enable = void> struct format_provider {};
+class Error;
+
+namespace detail {
+class format_adapter {
+ virtual void anchor();
+
+protected:
+ virtual ~format_adapter() = default;
+
+public:
+ virtual void format(raw_ostream &S, StringRef Options) = 0;
+};
+
+template <typename T> class provider_format_adapter : public format_adapter {
+ T Item;
+
+public:
+ explicit provider_format_adapter(T &&Item) : Item(std::forward<T>(Item)) {}
+
+ void format(llvm::raw_ostream &S, StringRef Options) override {
+ format_provider<std::decay_t<T>>::format(Item, S, Options);
+ }
+};
+
+template <typename T>
+class stream_operator_format_adapter : public format_adapter {
+ T Item;
+
+public:
+ explicit stream_operator_format_adapter(T &&Item)
+ : Item(std::forward<T>(Item)) {}
+
+ void format(llvm::raw_ostream &S, StringRef) override { S << Item; }
+};
+
+template <typename T> class missing_format_adapter;
+
+// Test if format_provider<T> is defined on T and contains a member function
+// with the signature:
+// static void format(const T&, raw_stream &, StringRef);
+//
+template <class T> class has_FormatProvider {
+public:
+ using Decayed = std::decay_t<T>;
+ typedef void (*Signature_format)(const Decayed &, llvm::raw_ostream &,
+ StringRef);
+
+ template <typename U>
+ static char test(SameType<Signature_format, &U::format> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value =
+ (sizeof(test<llvm::format_provider<Decayed>>(nullptr)) == 1);
+};
+
+// Test if raw_ostream& << T -> raw_ostream& is findable via ADL.
+template <class T> class has_StreamOperator {
+public:
+ using ConstRefT = const std::decay_t<T> &;
+
+ template <typename U>
+ static char test(
+ std::enable_if_t<std::is_same<decltype(std::declval<llvm::raw_ostream &>()
+ << std::declval<U>()),
+ llvm::raw_ostream &>::value,
+ int *>);
+
+ template <typename U> static double test(...);
+
+ static bool const value = (sizeof(test<ConstRefT>(nullptr)) == 1);
+};
+
+// Simple template that decides whether a type T should use the member-function
+// based format() invocation.
+template <typename T>
+struct uses_format_member
+ : public std::integral_constant<
+ bool,
+ std::is_base_of<format_adapter, std::remove_reference_t<T>>::value> {
+};
+
+// Simple template that decides whether a type T should use the format_provider
+// based format() invocation. The member function takes priority, so this test
+// will only be true if there is not ALSO a format member.
+template <typename T>
+struct uses_format_provider
+ : public std::integral_constant<
+ bool, !uses_format_member<T>::value && has_FormatProvider<T>::value> {
+};
+
+// Simple template that decides whether a type T should use the operator<<
+// based format() invocation. This takes last priority.
+template <typename T>
+struct uses_stream_operator
+ : public std::integral_constant<bool, !uses_format_member<T>::value &&
+ !uses_format_provider<T>::value &&
+ has_StreamOperator<T>::value> {};
+
+// Simple template that decides whether a type T has neither a member-function
+// nor format_provider based implementation that it can use. Mostly used so
+// that the compiler spits out a nice diagnostic when a type with no format
+// implementation can be located.
+template <typename T>
+struct uses_missing_provider
+ : public std::integral_constant<bool, !uses_format_member<T>::value &&
+ !uses_format_provider<T>::value &&
+ !uses_stream_operator<T>::value> {
+};
+
+template <typename T>
+std::enable_if_t<uses_format_member<T>::value, T>
+build_format_adapter(T &&Item) {
+ return std::forward<T>(Item);
+}
+
+template <typename T>
+std::enable_if_t<uses_format_provider<T>::value, provider_format_adapter<T>>
+build_format_adapter(T &&Item) {
+ return provider_format_adapter<T>(std::forward<T>(Item));
+}
+
+template <typename T>
+std::enable_if_t<uses_stream_operator<T>::value,
+ stream_operator_format_adapter<T>>
+build_format_adapter(T &&Item) {
+ // If the caller passed an Error by value, then stream_operator_format_adapter
+ // would be responsible for consuming it.
+ // Make the caller opt into this by calling fmt_consume().
+ static_assert(
+ !std::is_same<llvm::Error, std::remove_cv_t<T>>::value,
+ "llvm::Error-by-value must be wrapped in fmt_consume() for formatv");
+ return stream_operator_format_adapter<T>(std::forward<T>(Item));
+}
+
+template <typename T>
+std::enable_if_t<uses_missing_provider<T>::value, missing_format_adapter<T>>
+build_format_adapter(T &&) {
+ return missing_format_adapter<T>();
+}
+}
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/FormattedStream.h b/contrib/libs/llvm16/include/llvm/Support/FormattedStream.h
new file mode 100644
index 00000000000..bb60c575e86
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/FormattedStream.h
@@ -0,0 +1,196 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/FormattedStream.h - Formatted streams ------*- 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 raw_ostream implementations for streams to do
+// things like pretty-print comments.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_FORMATTEDSTREAM_H
+#define LLVM_SUPPORT_FORMATTEDSTREAM_H
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+namespace llvm {
+
+/// formatted_raw_ostream - A raw_ostream that wraps another one and keeps track
+/// of line and column position, allowing padding out to specific column
+/// boundaries and querying the number of lines written to the stream. This
+/// assumes that the contents of the stream is valid UTF-8 encoded text. This
+/// doesn't attempt to handle everything Unicode can do (combining characters,
+/// right-to-left markers, etc), but should cover the cases likely to appear in
+/// source code or diagnostic messages.
+class formatted_raw_ostream : public raw_ostream {
+ /// TheStream - The real stream we output to. We set it to be
+ /// unbuffered, since we're already doing our own buffering.
+ ///
+ raw_ostream *TheStream;
+
+ /// Position - The current output column and line of the data that's
+ /// been flushed and the portion of the buffer that's been
+ /// scanned. The line and column scheme is zero-based.
+ ///
+ std::pair<unsigned, unsigned> Position;
+
+ /// Scanned - This points to one past the last character in the
+ /// buffer we've scanned.
+ ///
+ const char *Scanned;
+
+ /// PartialUTF8Char - Either empty or a prefix of a UTF-8 code unit sequence
+ /// for a Unicode scalar value which should be prepended to the buffer for the
+ /// next call to ComputePosition. This is needed when the buffer is flushed
+ /// when it ends part-way through the UTF-8 encoding of a Unicode scalar
+ /// value, so that we can compute the display width of the character once we
+ /// have the rest of it.
+ SmallString<4> PartialUTF8Char;
+
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ /// current_pos - Return the current position within the stream,
+ /// not counting the bytes currently in the buffer.
+ uint64_t current_pos() const override {
+ // Our current position in the stream is all the contents which have been
+ // written to the underlying stream (*not* the current position of the
+ // underlying stream).
+ return TheStream->tell();
+ }
+
+ /// ComputePosition - Examine the given output buffer and figure out the new
+ /// position after output. This is safe to call multiple times on the same
+ /// buffer, as it records the most recently scanned character and resumes from
+ /// there when the buffer has not been flushed.
+ void ComputePosition(const char *Ptr, size_t size);
+
+ /// UpdatePosition - scan the characters in [Ptr, Ptr+Size), and update the
+ /// line and column numbers. Unlike ComputePosition, this must be called
+ /// exactly once on each region of the buffer.
+ void UpdatePosition(const char *Ptr, size_t Size);
+
+ void setStream(raw_ostream &Stream) {
+ releaseStream();
+
+ TheStream = &Stream;
+
+ // This formatted_raw_ostream inherits from raw_ostream, so it'll do its
+ // own buffering, and it doesn't need or want TheStream to do another
+ // layer of buffering underneath. Resize the buffer to what TheStream
+ // had been using, and tell TheStream not to do its own buffering.
+ if (size_t BufferSize = TheStream->GetBufferSize())
+ SetBufferSize(BufferSize);
+ else
+ SetUnbuffered();
+ TheStream->SetUnbuffered();
+
+ Scanned = nullptr;
+ }
+
+public:
+ /// formatted_raw_ostream - Open the specified file for
+ /// writing. If an error occurs, information about the error is
+ /// put into ErrorInfo, and the stream should be immediately
+ /// destroyed; the string will be empty if no error occurred.
+ ///
+ /// As a side effect, the given Stream is set to be Unbuffered.
+ /// This is because formatted_raw_ostream does its own buffering,
+ /// so it doesn't want another layer of buffering to be happening
+ /// underneath it.
+ ///
+ formatted_raw_ostream(raw_ostream &Stream)
+ : TheStream(nullptr), Position(0, 0) {
+ setStream(Stream);
+ }
+ explicit formatted_raw_ostream() : TheStream(nullptr), Position(0, 0) {
+ Scanned = nullptr;
+ }
+
+ ~formatted_raw_ostream() override {
+ flush();
+ releaseStream();
+ }
+
+ /// PadToColumn - Align the output to some column number. If the current
+ /// column is already equal to or more than NewCol, PadToColumn inserts one
+ /// space.
+ ///
+ /// \param NewCol - The column to move to.
+ formatted_raw_ostream &PadToColumn(unsigned NewCol);
+
+ unsigned getColumn() {
+ // Calculate current position, taking buffer contents into account.
+ ComputePosition(getBufferStart(), GetNumBytesInBuffer());
+ return Position.first;
+ }
+
+ unsigned getLine() {
+ // Calculate current position, taking buffer contents into account.
+ ComputePosition(getBufferStart(), GetNumBytesInBuffer());
+ return Position.second;
+ }
+
+ raw_ostream &resetColor() override {
+ TheStream->resetColor();
+ return *this;
+ }
+
+ raw_ostream &reverseColor() override {
+ TheStream->reverseColor();
+ return *this;
+ }
+
+ raw_ostream &changeColor(enum Colors Color, bool Bold, bool BG) override {
+ TheStream->changeColor(Color, Bold, BG);
+ return *this;
+ }
+
+ bool is_displayed() const override {
+ return TheStream->is_displayed();
+ }
+
+private:
+ void releaseStream() {
+ // Transfer the buffer settings from this raw_ostream back to the underlying
+ // stream.
+ if (!TheStream)
+ return;
+ if (size_t BufferSize = GetBufferSize())
+ TheStream->SetBufferSize(BufferSize);
+ else
+ TheStream->SetUnbuffered();
+ }
+};
+
+/// fouts() - This returns a reference to a formatted_raw_ostream for
+/// standard output. Use it like: fouts() << "foo" << "bar";
+formatted_raw_ostream &fouts();
+
+/// ferrs() - This returns a reference to a formatted_raw_ostream for
+/// standard error. Use it like: ferrs() << "foo" << "bar";
+formatted_raw_ostream &ferrs();
+
+/// fdbgs() - This returns a reference to a formatted_raw_ostream for
+/// debug output. Use it like: fdbgs() << "foo" << "bar";
+formatted_raw_ostream &fdbgs();
+
+} // end llvm namespace
+
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/GenericDomTree.h b/contrib/libs/llvm16/include/llvm/Support/GenericDomTree.h
new file mode 100644
index 00000000000..94bedc6914a
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/GenericDomTree.h
@@ -0,0 +1,977 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- GenericDomTree.h - Generic dominator trees for graphs ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines a set of templates that efficiently compute a dominator
+/// tree over a generic graph. This is used typically in LLVM for fast
+/// dominance queries on the CFG, but is fully generic w.r.t. the underlying
+/// graph types.
+///
+/// Unlike ADT/* graph algorithms, generic dominator tree has more requirements
+/// on the graph's NodeRef. The NodeRef should be a pointer and,
+/// either NodeRef->getParent() must return the parent node that is also a
+/// pointer or DomTreeNodeTraits needs to be specialized.
+///
+/// FIXME: Maybe GenericDomTree needs a TreeTraits, instead of GraphTraits.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_GENERICDOMTREE_H
+#define LLVM_SUPPORT_GENERICDOMTREE_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/CFGDiff.h"
+#include "llvm/Support/CFGUpdate.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+template <typename NodeT, bool IsPostDom>
+class DominatorTreeBase;
+
+namespace DomTreeBuilder {
+template <typename DomTreeT>
+struct SemiNCAInfo;
+} // namespace DomTreeBuilder
+
+/// Base class for the actual dominator tree node.
+template <class NodeT> class DomTreeNodeBase {
+ friend class PostDominatorTree;
+ friend class DominatorTreeBase<NodeT, false>;
+ friend class DominatorTreeBase<NodeT, true>;
+ friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase<NodeT, false>>;
+ friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase<NodeT, true>>;
+
+ NodeT *TheBB;
+ DomTreeNodeBase *IDom;
+ unsigned Level;
+ SmallVector<DomTreeNodeBase *, 4> Children;
+ mutable unsigned DFSNumIn = ~0;
+ mutable unsigned DFSNumOut = ~0;
+
+ public:
+ DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom)
+ : TheBB(BB), IDom(iDom), Level(IDom ? IDom->Level + 1 : 0) {}
+
+ using iterator = typename SmallVector<DomTreeNodeBase *, 4>::iterator;
+ using const_iterator =
+ typename SmallVector<DomTreeNodeBase *, 4>::const_iterator;
+
+ iterator begin() { return Children.begin(); }
+ iterator end() { return Children.end(); }
+ const_iterator begin() const { return Children.begin(); }
+ const_iterator end() const { return Children.end(); }
+
+ DomTreeNodeBase *const &back() const { return Children.back(); }
+ DomTreeNodeBase *&back() { return Children.back(); }
+
+ iterator_range<iterator> children() { return make_range(begin(), end()); }
+ iterator_range<const_iterator> children() const {
+ return make_range(begin(), end());
+ }
+
+ NodeT *getBlock() const { return TheBB; }
+ DomTreeNodeBase *getIDom() const { return IDom; }
+ unsigned getLevel() const { return Level; }
+
+ std::unique_ptr<DomTreeNodeBase> addChild(
+ std::unique_ptr<DomTreeNodeBase> C) {
+ Children.push_back(C.get());
+ return C;
+ }
+
+ bool isLeaf() const { return Children.empty(); }
+ size_t getNumChildren() const { return Children.size(); }
+
+ void clearAllChildren() { Children.clear(); }
+
+ bool compare(const DomTreeNodeBase *Other) const {
+ if (getNumChildren() != Other->getNumChildren())
+ return true;
+
+ if (Level != Other->Level) return true;
+
+ SmallPtrSet<const NodeT *, 4> OtherChildren;
+ for (const DomTreeNodeBase *I : *Other) {
+ const NodeT *Nd = I->getBlock();
+ OtherChildren.insert(Nd);
+ }
+
+ for (const DomTreeNodeBase *I : *this) {
+ const NodeT *N = I->getBlock();
+ if (OtherChildren.count(N) == 0)
+ return true;
+ }
+ return false;
+ }
+
+ void setIDom(DomTreeNodeBase *NewIDom) {
+ assert(IDom && "No immediate dominator?");
+ if (IDom == NewIDom) return;
+
+ auto I = find(IDom->Children, this);
+ assert(I != IDom->Children.end() &&
+ "Not in immediate dominator children set!");
+ // I am no longer your child...
+ IDom->Children.erase(I);
+
+ // Switch to new dominator
+ IDom = NewIDom;
+ IDom->Children.push_back(this);
+
+ UpdateLevel();
+ }
+
+ /// getDFSNumIn/getDFSNumOut - These return the DFS visitation order for nodes
+ /// in the dominator tree. They are only guaranteed valid if
+ /// updateDFSNumbers() has been called.
+ unsigned getDFSNumIn() const { return DFSNumIn; }
+ unsigned getDFSNumOut() const { return DFSNumOut; }
+
+private:
+ // Return true if this node is dominated by other. Use this only if DFS info
+ // is valid.
+ bool DominatedBy(const DomTreeNodeBase *other) const {
+ return this->DFSNumIn >= other->DFSNumIn &&
+ this->DFSNumOut <= other->DFSNumOut;
+ }
+
+ void UpdateLevel() {
+ assert(IDom);
+ if (Level == IDom->Level + 1) return;
+
+ SmallVector<DomTreeNodeBase *, 64> WorkStack = {this};
+
+ while (!WorkStack.empty()) {
+ DomTreeNodeBase *Current = WorkStack.pop_back_val();
+ Current->Level = Current->IDom->Level + 1;
+
+ for (DomTreeNodeBase *C : *Current) {
+ assert(C->IDom);
+ if (C->Level != C->IDom->Level + 1) WorkStack.push_back(C);
+ }
+ }
+ }
+};
+
+template <class NodeT>
+raw_ostream &operator<<(raw_ostream &O, const DomTreeNodeBase<NodeT> *Node) {
+ if (Node->getBlock())
+ Node->getBlock()->printAsOperand(O, false);
+ else
+ O << " <<exit node>>";
+
+ O << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "} ["
+ << Node->getLevel() << "]\n";
+
+ return O;
+}
+
+template <class NodeT>
+void PrintDomTree(const DomTreeNodeBase<NodeT> *N, raw_ostream &O,
+ unsigned Lev) {
+ O.indent(2 * Lev) << "[" << Lev << "] " << N;
+ for (typename DomTreeNodeBase<NodeT>::const_iterator I = N->begin(),
+ E = N->end();
+ I != E; ++I)
+ PrintDomTree<NodeT>(*I, O, Lev + 1);
+}
+
+namespace DomTreeBuilder {
+// The routines below are provided in a separate header but referenced here.
+template <typename DomTreeT>
+void Calculate(DomTreeT &DT);
+
+template <typename DomTreeT>
+void CalculateWithUpdates(DomTreeT &DT,
+ ArrayRef<typename DomTreeT::UpdateType> Updates);
+
+template <typename DomTreeT>
+void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
+ typename DomTreeT::NodePtr To);
+
+template <typename DomTreeT>
+void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
+ typename DomTreeT::NodePtr To);
+
+template <typename DomTreeT>
+void ApplyUpdates(DomTreeT &DT,
+ GraphDiff<typename DomTreeT::NodePtr,
+ DomTreeT::IsPostDominator> &PreViewCFG,
+ GraphDiff<typename DomTreeT::NodePtr,
+ DomTreeT::IsPostDominator> *PostViewCFG);
+
+template <typename DomTreeT>
+bool Verify(const DomTreeT &DT, typename DomTreeT::VerificationLevel VL);
+} // namespace DomTreeBuilder
+
+/// Default DomTreeNode traits for NodeT. The default implementation assume a
+/// Function-like NodeT. Can be specialized to support different node types.
+template <typename NodeT> struct DomTreeNodeTraits {
+ using NodeType = NodeT;
+ using NodePtr = NodeT *;
+ using ParentPtr = decltype(std::declval<NodePtr>()->getParent());
+ static_assert(std::is_pointer<ParentPtr>::value,
+ "Currently NodeT's parent must be a pointer type");
+ using ParentType = std::remove_pointer_t<ParentPtr>;
+
+ static NodeT *getEntryNode(ParentPtr Parent) { return &Parent->front(); }
+ static ParentPtr getParent(NodePtr BB) { return BB->getParent(); }
+};
+
+/// Core dominator tree base class.
+///
+/// This class is a generic template over graph nodes. It is instantiated for
+/// various graphs in the LLVM IR or in the code generator.
+template <typename NodeT, bool IsPostDom>
+class DominatorTreeBase {
+ public:
+ static_assert(std::is_pointer<typename GraphTraits<NodeT *>::NodeRef>::value,
+ "Currently DominatorTreeBase supports only pointer nodes");
+ using NodeTrait = DomTreeNodeTraits<NodeT>;
+ using NodeType = typename NodeTrait::NodeType;
+ using NodePtr = typename NodeTrait::NodePtr;
+ using ParentPtr = typename NodeTrait::ParentPtr;
+ static_assert(std::is_pointer<ParentPtr>::value,
+ "Currently NodeT's parent must be a pointer type");
+ using ParentType = std::remove_pointer_t<ParentPtr>;
+ static constexpr bool IsPostDominator = IsPostDom;
+
+ using UpdateType = cfg::Update<NodePtr>;
+ using UpdateKind = cfg::UpdateKind;
+ static constexpr UpdateKind Insert = UpdateKind::Insert;
+ static constexpr UpdateKind Delete = UpdateKind::Delete;
+
+ enum class VerificationLevel { Fast, Basic, Full };
+
+protected:
+ // Dominators always have a single root, postdominators can have more.
+ SmallVector<NodeT *, IsPostDom ? 4 : 1> Roots;
+
+ using DomTreeNodeMapType =
+ DenseMap<NodeT *, std::unique_ptr<DomTreeNodeBase<NodeT>>>;
+ DomTreeNodeMapType DomTreeNodes;
+ DomTreeNodeBase<NodeT> *RootNode = nullptr;
+ ParentPtr Parent = nullptr;
+
+ mutable bool DFSInfoValid = false;
+ mutable unsigned int SlowQueries = 0;
+
+ friend struct DomTreeBuilder::SemiNCAInfo<DominatorTreeBase>;
+
+ public:
+ DominatorTreeBase() = default;
+
+ DominatorTreeBase(DominatorTreeBase &&Arg)
+ : Roots(std::move(Arg.Roots)),
+ DomTreeNodes(std::move(Arg.DomTreeNodes)),
+ RootNode(Arg.RootNode),
+ Parent(Arg.Parent),
+ DFSInfoValid(Arg.DFSInfoValid),
+ SlowQueries(Arg.SlowQueries) {
+ Arg.wipe();
+ }
+
+ DominatorTreeBase &operator=(DominatorTreeBase &&RHS) {
+ Roots = std::move(RHS.Roots);
+ DomTreeNodes = std::move(RHS.DomTreeNodes);
+ RootNode = RHS.RootNode;
+ Parent = RHS.Parent;
+ DFSInfoValid = RHS.DFSInfoValid;
+ SlowQueries = RHS.SlowQueries;
+ RHS.wipe();
+ return *this;
+ }
+
+ DominatorTreeBase(const DominatorTreeBase &) = delete;
+ DominatorTreeBase &operator=(const DominatorTreeBase &) = delete;
+
+ /// Iteration over roots.
+ ///
+ /// This may include multiple blocks if we are computing post dominators.
+ /// For forward dominators, this will always be a single block (the entry
+ /// block).
+ using root_iterator = typename SmallVectorImpl<NodeT *>::iterator;
+ using const_root_iterator = typename SmallVectorImpl<NodeT *>::const_iterator;
+
+ root_iterator root_begin() { return Roots.begin(); }
+ const_root_iterator root_begin() const { return Roots.begin(); }
+ root_iterator root_end() { return Roots.end(); }
+ const_root_iterator root_end() const { return Roots.end(); }
+
+ size_t root_size() const { return Roots.size(); }
+
+ iterator_range<root_iterator> roots() {
+ return make_range(root_begin(), root_end());
+ }
+ iterator_range<const_root_iterator> roots() const {
+ return make_range(root_begin(), root_end());
+ }
+
+ /// isPostDominator - Returns true if analysis based of postdoms
+ ///
+ bool isPostDominator() const { return IsPostDominator; }
+
+ /// compare - Return false if the other dominator tree base matches this
+ /// dominator tree base. Otherwise return true.
+ bool compare(const DominatorTreeBase &Other) const {
+ if (Parent != Other.Parent) return true;
+
+ if (Roots.size() != Other.Roots.size())
+ return true;
+
+ if (!std::is_permutation(Roots.begin(), Roots.end(), Other.Roots.begin()))
+ return true;
+
+ const DomTreeNodeMapType &OtherDomTreeNodes = Other.DomTreeNodes;
+ if (DomTreeNodes.size() != OtherDomTreeNodes.size())
+ return true;
+
+ for (const auto &DomTreeNode : DomTreeNodes) {
+ NodeT *BB = DomTreeNode.first;
+ typename DomTreeNodeMapType::const_iterator OI =
+ OtherDomTreeNodes.find(BB);
+ if (OI == OtherDomTreeNodes.end())
+ return true;
+
+ DomTreeNodeBase<NodeT> &MyNd = *DomTreeNode.second;
+ DomTreeNodeBase<NodeT> &OtherNd = *OI->second;
+
+ if (MyNd.compare(&OtherNd))
+ return true;
+ }
+
+ return false;
+ }
+
+ /// getNode - return the (Post)DominatorTree node for the specified basic
+ /// block. This is the same as using operator[] on this class. The result
+ /// may (but is not required to) be null for a forward (backwards)
+ /// statically unreachable block.
+ DomTreeNodeBase<NodeT> *getNode(const NodeT *BB) const {
+ auto I = DomTreeNodes.find(BB);
+ if (I != DomTreeNodes.end())
+ return I->second.get();
+ return nullptr;
+ }
+
+ /// See getNode.
+ DomTreeNodeBase<NodeT> *operator[](const NodeT *BB) const {
+ return getNode(BB);
+ }
+
+ /// getRootNode - This returns the entry node for the CFG of the function. If
+ /// this tree represents the post-dominance relations for a function, however,
+ /// this root may be a node with the block == NULL. This is the case when
+ /// there are multiple exit nodes from a particular function. Consumers of
+ /// post-dominance information must be capable of dealing with this
+ /// possibility.
+ ///
+ DomTreeNodeBase<NodeT> *getRootNode() { return RootNode; }
+ const DomTreeNodeBase<NodeT> *getRootNode() const { return RootNode; }
+
+ /// Get all nodes dominated by R, including R itself.
+ void getDescendants(NodeT *R, SmallVectorImpl<NodeT *> &Result) const {
+ Result.clear();
+ const DomTreeNodeBase<NodeT> *RN = getNode(R);
+ if (!RN)
+ return; // If R is unreachable, it will not be present in the DOM tree.
+ SmallVector<const DomTreeNodeBase<NodeT> *, 8> WL;
+ WL.push_back(RN);
+
+ while (!WL.empty()) {
+ const DomTreeNodeBase<NodeT> *N = WL.pop_back_val();
+ Result.push_back(N->getBlock());
+ WL.append(N->begin(), N->end());
+ }
+ }
+
+ /// properlyDominates - Returns true iff A dominates B and A != B.
+ /// Note that this is not a constant time operation!
+ ///
+ bool properlyDominates(const DomTreeNodeBase<NodeT> *A,
+ const DomTreeNodeBase<NodeT> *B) const {
+ if (!A || !B)
+ return false;
+ if (A == B)
+ return false;
+ return dominates(A, B);
+ }
+
+ bool properlyDominates(const NodeT *A, const NodeT *B) const;
+
+ /// isReachableFromEntry - Return true if A is dominated by the entry
+ /// block of the function containing it.
+ bool isReachableFromEntry(const NodeT *A) const {
+ assert(!this->isPostDominator() &&
+ "This is not implemented for post dominators");
+ return isReachableFromEntry(getNode(const_cast<NodeT *>(A)));
+ }
+
+ bool isReachableFromEntry(const DomTreeNodeBase<NodeT> *A) const { return A; }
+
+ /// dominates - Returns true iff A dominates B. Note that this is not a
+ /// constant time operation!
+ ///
+ bool dominates(const DomTreeNodeBase<NodeT> *A,
+ const DomTreeNodeBase<NodeT> *B) const {
+ // A node trivially dominates itself.
+ if (B == A)
+ return true;
+
+ // An unreachable node is dominated by anything.
+ if (!isReachableFromEntry(B))
+ return true;
+
+ // And dominates nothing.
+ if (!isReachableFromEntry(A))
+ return false;
+
+ if (B->getIDom() == A) return true;
+
+ if (A->getIDom() == B) return false;
+
+ // A can only dominate B if it is higher in the tree.
+ if (A->getLevel() >= B->getLevel()) return false;
+
+ // Compare the result of the tree walk and the dfs numbers, if expensive
+ // checks are enabled.
+#ifdef EXPENSIVE_CHECKS
+ assert((!DFSInfoValid ||
+ (dominatedBySlowTreeWalk(A, B) == B->DominatedBy(A))) &&
+ "Tree walk disagrees with dfs numbers!");
+#endif
+
+ if (DFSInfoValid)
+ return B->DominatedBy(A);
+
+ // If we end up with too many slow queries, just update the
+ // DFS numbers on the theory that we are going to keep querying.
+ SlowQueries++;
+ if (SlowQueries > 32) {
+ updateDFSNumbers();
+ return B->DominatedBy(A);
+ }
+
+ return dominatedBySlowTreeWalk(A, B);
+ }
+
+ bool dominates(const NodeT *A, const NodeT *B) const;
+
+ NodeT *getRoot() const {
+ assert(this->Roots.size() == 1 && "Should always have entry node!");
+ return this->Roots[0];
+ }
+
+ /// Find nearest common dominator basic block for basic block A and B. A and B
+ /// must have tree nodes.
+ NodeT *findNearestCommonDominator(NodeT *A, NodeT *B) const {
+ assert(A && B && "Pointers are not valid");
+ assert(NodeTrait::getParent(A) == NodeTrait::getParent(B) &&
+ "Two blocks are not in same function");
+
+ // If either A or B is a entry block then it is nearest common dominator
+ // (for forward-dominators).
+ if (!isPostDominator()) {
+ NodeT &Entry =
+ *DomTreeNodeTraits<NodeT>::getEntryNode(NodeTrait::getParent(A));
+ if (A == &Entry || B == &Entry)
+ return &Entry;
+ }
+
+ DomTreeNodeBase<NodeT> *NodeA = getNode(A);
+ DomTreeNodeBase<NodeT> *NodeB = getNode(B);
+ assert(NodeA && "A must be in the tree");
+ assert(NodeB && "B must be in the tree");
+
+ // Use level information to go up the tree until the levels match. Then
+ // continue going up til we arrive at the same node.
+ while (NodeA != NodeB) {
+ if (NodeA->getLevel() < NodeB->getLevel()) std::swap(NodeA, NodeB);
+
+ NodeA = NodeA->IDom;
+ }
+
+ return NodeA->getBlock();
+ }
+
+ const NodeT *findNearestCommonDominator(const NodeT *A,
+ const NodeT *B) const {
+ // Cast away the const qualifiers here. This is ok since
+ // const is re-introduced on the return type.
+ return findNearestCommonDominator(const_cast<NodeT *>(A),
+ const_cast<NodeT *>(B));
+ }
+
+ bool isVirtualRoot(const DomTreeNodeBase<NodeT> *A) const {
+ return isPostDominator() && !A->getBlock();
+ }
+
+ //===--------------------------------------------------------------------===//
+ // API to update (Post)DominatorTree information based on modifications to
+ // the CFG...
+
+ /// Inform the dominator tree about a sequence of CFG edge insertions and
+ /// deletions and perform a batch update on the tree.
+ ///
+ /// This function should be used when there were multiple CFG updates after
+ /// the last dominator tree update. It takes care of performing the updates
+ /// in sync with the CFG and optimizes away the redundant operations that
+ /// cancel each other.
+ /// The functions expects the sequence of updates to be balanced. Eg.:
+ /// - {{Insert, A, B}, {Delete, A, B}, {Insert, A, B}} is fine, because
+ /// logically it results in a single insertions.
+ /// - {{Insert, A, B}, {Insert, A, B}} is invalid, because it doesn't make
+ /// sense to insert the same edge twice.
+ ///
+ /// What's more, the functions assumes that it's safe to ask every node in the
+ /// CFG about its children and inverse children. This implies that deletions
+ /// of CFG edges must not delete the CFG nodes before calling this function.
+ ///
+ /// The applyUpdates function can reorder the updates and remove redundant
+ /// ones internally (as long as it is done in a deterministic fashion). The
+ /// batch updater is also able to detect sequences of zero and exactly one
+ /// update -- it's optimized to do less work in these cases.
+ ///
+ /// Note that for postdominators it automatically takes care of applying
+ /// updates on reverse edges internally (so there's no need to swap the
+ /// From and To pointers when constructing DominatorTree::UpdateType).
+ /// The type of updates is the same for DomTreeBase<T> and PostDomTreeBase<T>
+ /// with the same template parameter T.
+ ///
+ /// \param Updates An ordered sequence of updates to perform. The current CFG
+ /// and the reverse of these updates provides the pre-view of the CFG.
+ ///
+ void applyUpdates(ArrayRef<UpdateType> Updates) {
+ GraphDiff<NodePtr, IsPostDominator> PreViewCFG(
+ Updates, /*ReverseApplyUpdates=*/true);
+ DomTreeBuilder::ApplyUpdates(*this, PreViewCFG, nullptr);
+ }
+
+ /// \param Updates An ordered sequence of updates to perform. The current CFG
+ /// and the reverse of these updates provides the pre-view of the CFG.
+ /// \param PostViewUpdates An ordered sequence of update to perform in order
+ /// to obtain a post-view of the CFG. The DT will be updated assuming the
+ /// obtained PostViewCFG is the desired end state.
+ void applyUpdates(ArrayRef<UpdateType> Updates,
+ ArrayRef<UpdateType> PostViewUpdates) {
+ if (Updates.empty()) {
+ GraphDiff<NodePtr, IsPostDom> PostViewCFG(PostViewUpdates);
+ DomTreeBuilder::ApplyUpdates(*this, PostViewCFG, &PostViewCFG);
+ } else {
+ // PreViewCFG needs to merge Updates and PostViewCFG. The updates in
+ // Updates need to be reversed, and match the direction in PostViewCFG.
+ // The PostViewCFG is created with updates reversed (equivalent to changes
+ // made to the CFG), so the PreViewCFG needs all the updates reverse
+ // applied.
+ SmallVector<UpdateType> AllUpdates(Updates.begin(), Updates.end());
+ append_range(AllUpdates, PostViewUpdates);
+ GraphDiff<NodePtr, IsPostDom> PreViewCFG(AllUpdates,
+ /*ReverseApplyUpdates=*/true);
+ GraphDiff<NodePtr, IsPostDom> PostViewCFG(PostViewUpdates);
+ DomTreeBuilder::ApplyUpdates(*this, PreViewCFG, &PostViewCFG);
+ }
+ }
+
+ /// Inform the dominator tree about a CFG edge insertion and update the tree.
+ ///
+ /// This function has to be called just before or just after making the update
+ /// on the actual CFG. There cannot be any other updates that the dominator
+ /// tree doesn't know about.
+ ///
+ /// Note that for postdominators it automatically takes care of inserting
+ /// a reverse edge internally (so there's no need to swap the parameters).
+ ///
+ void insertEdge(NodeT *From, NodeT *To) {
+ assert(From);
+ assert(To);
+ assert(NodeTrait::getParent(From) == Parent);
+ assert(NodeTrait::getParent(To) == Parent);
+ DomTreeBuilder::InsertEdge(*this, From, To);
+ }
+
+ /// Inform the dominator tree about a CFG edge deletion and update the tree.
+ ///
+ /// This function has to be called just after making the update on the actual
+ /// CFG. An internal functions checks if the edge doesn't exist in the CFG in
+ /// DEBUG mode. There cannot be any other updates that the
+ /// dominator tree doesn't know about.
+ ///
+ /// Note that for postdominators it automatically takes care of deleting
+ /// a reverse edge internally (so there's no need to swap the parameters).
+ ///
+ void deleteEdge(NodeT *From, NodeT *To) {
+ assert(From);
+ assert(To);
+ assert(NodeTrait::getParent(From) == Parent);
+ assert(NodeTrait::getParent(To) == Parent);
+ DomTreeBuilder::DeleteEdge(*this, From, To);
+ }
+
+ /// Add a new node to the dominator tree information.
+ ///
+ /// This creates a new node as a child of DomBB dominator node, linking it
+ /// into the children list of the immediate dominator.
+ ///
+ /// \param BB New node in CFG.
+ /// \param DomBB CFG node that is dominator for BB.
+ /// \returns New dominator tree node that represents new CFG node.
+ ///
+ DomTreeNodeBase<NodeT> *addNewBlock(NodeT *BB, NodeT *DomBB) {
+ assert(getNode(BB) == nullptr && "Block already in dominator tree!");
+ DomTreeNodeBase<NodeT> *IDomNode = getNode(DomBB);
+ assert(IDomNode && "Not immediate dominator specified for block!");
+ DFSInfoValid = false;
+ return createChild(BB, IDomNode);
+ }
+
+ /// Add a new node to the forward dominator tree and make it a new root.
+ ///
+ /// \param BB New node in CFG.
+ /// \returns New dominator tree node that represents new CFG node.
+ ///
+ DomTreeNodeBase<NodeT> *setNewRoot(NodeT *BB) {
+ assert(getNode(BB) == nullptr && "Block already in dominator tree!");
+ assert(!this->isPostDominator() &&
+ "Cannot change root of post-dominator tree");
+ DFSInfoValid = false;
+ DomTreeNodeBase<NodeT> *NewNode = createNode(BB);
+ if (Roots.empty()) {
+ addRoot(BB);
+ } else {
+ assert(Roots.size() == 1);
+ NodeT *OldRoot = Roots.front();
+ auto &OldNode = DomTreeNodes[OldRoot];
+ OldNode = NewNode->addChild(std::move(DomTreeNodes[OldRoot]));
+ OldNode->IDom = NewNode;
+ OldNode->UpdateLevel();
+ Roots[0] = BB;
+ }
+ return RootNode = NewNode;
+ }
+
+ /// changeImmediateDominator - This method is used to update the dominator
+ /// tree information when a node's immediate dominator changes.
+ ///
+ void changeImmediateDominator(DomTreeNodeBase<NodeT> *N,
+ DomTreeNodeBase<NodeT> *NewIDom) {
+ assert(N && NewIDom && "Cannot change null node pointers!");
+ DFSInfoValid = false;
+ N->setIDom(NewIDom);
+ }
+
+ void changeImmediateDominator(NodeT *BB, NodeT *NewBB) {
+ changeImmediateDominator(getNode(BB), getNode(NewBB));
+ }
+
+ /// eraseNode - Removes a node from the dominator tree. Block must not
+ /// dominate any other blocks. Removes node from its immediate dominator's
+ /// children list. Deletes dominator node associated with basic block BB.
+ void eraseNode(NodeT *BB) {
+ DomTreeNodeBase<NodeT> *Node = getNode(BB);
+ assert(Node && "Removing node that isn't in dominator tree.");
+ assert(Node->isLeaf() && "Node is not a leaf node.");
+
+ DFSInfoValid = false;
+
+ // Remove node from immediate dominator's children list.
+ DomTreeNodeBase<NodeT> *IDom = Node->getIDom();
+ if (IDom) {
+ const auto I = find(IDom->Children, Node);
+ assert(I != IDom->Children.end() &&
+ "Not in immediate dominator children set!");
+ // I am no longer your child...
+ IDom->Children.erase(I);
+ }
+
+ DomTreeNodes.erase(BB);
+
+ if (!IsPostDom) return;
+
+ // Remember to update PostDominatorTree roots.
+ auto RIt = llvm::find(Roots, BB);
+ if (RIt != Roots.end()) {
+ std::swap(*RIt, Roots.back());
+ Roots.pop_back();
+ }
+ }
+
+ /// splitBlock - BB is split and now it has one successor. Update dominator
+ /// tree to reflect this change.
+ void splitBlock(NodeT *NewBB) {
+ if (IsPostDominator)
+ Split<Inverse<NodeT *>>(NewBB);
+ else
+ Split<NodeT *>(NewBB);
+ }
+
+ /// print - Convert to human readable form
+ ///
+ void print(raw_ostream &O) const {
+ O << "=============================--------------------------------\n";
+ if (IsPostDominator)
+ O << "Inorder PostDominator Tree: ";
+ else
+ O << "Inorder Dominator Tree: ";
+ if (!DFSInfoValid)
+ O << "DFSNumbers invalid: " << SlowQueries << " slow queries.";
+ O << "\n";
+
+ // The postdom tree can have a null root if there are no returns.
+ if (getRootNode()) PrintDomTree<NodeT>(getRootNode(), O, 1);
+ O << "Roots: ";
+ for (const NodePtr Block : Roots) {
+ Block->printAsOperand(O, false);
+ O << " ";
+ }
+ O << "\n";
+ }
+
+public:
+ /// updateDFSNumbers - Assign In and Out numbers to the nodes while walking
+ /// dominator tree in dfs order.
+ void updateDFSNumbers() const {
+ if (DFSInfoValid) {
+ SlowQueries = 0;
+ return;
+ }
+
+ SmallVector<std::pair<const DomTreeNodeBase<NodeT> *,
+ typename DomTreeNodeBase<NodeT>::const_iterator>,
+ 32> WorkStack;
+
+ const DomTreeNodeBase<NodeT> *ThisRoot = getRootNode();
+ assert((!Parent || ThisRoot) && "Empty constructed DomTree");
+ if (!ThisRoot)
+ return;
+
+ // Both dominators and postdominators have a single root node. In the case
+ // case of PostDominatorTree, this node is a virtual root.
+ WorkStack.push_back({ThisRoot, ThisRoot->begin()});
+
+ unsigned DFSNum = 0;
+ ThisRoot->DFSNumIn = DFSNum++;
+
+ while (!WorkStack.empty()) {
+ const DomTreeNodeBase<NodeT> *Node = WorkStack.back().first;
+ const auto ChildIt = WorkStack.back().second;
+
+ // If we visited all of the children of this node, "recurse" back up the
+ // stack setting the DFOutNum.
+ if (ChildIt == Node->end()) {
+ Node->DFSNumOut = DFSNum++;
+ WorkStack.pop_back();
+ } else {
+ // Otherwise, recursively visit this child.
+ const DomTreeNodeBase<NodeT> *Child = *ChildIt;
+ ++WorkStack.back().second;
+
+ WorkStack.push_back({Child, Child->begin()});
+ Child->DFSNumIn = DFSNum++;
+ }
+ }
+
+ SlowQueries = 0;
+ DFSInfoValid = true;
+ }
+
+ /// recalculate - compute a dominator tree for the given function
+ void recalculate(ParentType &Func) {
+ Parent = &Func;
+ DomTreeBuilder::Calculate(*this);
+ }
+
+ void recalculate(ParentType &Func, ArrayRef<UpdateType> Updates) {
+ Parent = &Func;
+ DomTreeBuilder::CalculateWithUpdates(*this, Updates);
+ }
+
+ /// verify - checks if the tree is correct. There are 3 level of verification:
+ /// - Full -- verifies if the tree is correct by making sure all the
+ /// properties (including the parent and the sibling property)
+ /// hold.
+ /// Takes O(N^3) time.
+ ///
+ /// - Basic -- checks if the tree is correct, but compares it to a freshly
+ /// constructed tree instead of checking the sibling property.
+ /// Takes O(N^2) time.
+ ///
+ /// - Fast -- checks basic tree structure and compares it with a freshly
+ /// constructed tree.
+ /// Takes O(N^2) time worst case, but is faster in practise (same
+ /// as tree construction).
+ bool verify(VerificationLevel VL = VerificationLevel::Full) const {
+ return DomTreeBuilder::Verify(*this, VL);
+ }
+
+ void reset() {
+ DomTreeNodes.clear();
+ Roots.clear();
+ RootNode = nullptr;
+ Parent = nullptr;
+ DFSInfoValid = false;
+ SlowQueries = 0;
+ }
+
+protected:
+ void addRoot(NodeT *BB) { this->Roots.push_back(BB); }
+
+ DomTreeNodeBase<NodeT> *createChild(NodeT *BB, DomTreeNodeBase<NodeT> *IDom) {
+ return (DomTreeNodes[BB] = IDom->addChild(
+ std::make_unique<DomTreeNodeBase<NodeT>>(BB, IDom)))
+ .get();
+ }
+
+ DomTreeNodeBase<NodeT> *createNode(NodeT *BB) {
+ return (DomTreeNodes[BB] =
+ std::make_unique<DomTreeNodeBase<NodeT>>(BB, nullptr))
+ .get();
+ }
+
+ // NewBB is split and now it has one successor. Update dominator tree to
+ // reflect this change.
+ template <class N>
+ void Split(typename GraphTraits<N>::NodeRef NewBB) {
+ using GraphT = GraphTraits<N>;
+ using NodeRef = typename GraphT::NodeRef;
+ assert(std::distance(GraphT::child_begin(NewBB),
+ GraphT::child_end(NewBB)) == 1 &&
+ "NewBB should have a single successor!");
+ NodeRef NewBBSucc = *GraphT::child_begin(NewBB);
+
+ SmallVector<NodeRef, 4> PredBlocks(children<Inverse<N>>(NewBB));
+
+ assert(!PredBlocks.empty() && "No predblocks?");
+
+ bool NewBBDominatesNewBBSucc = true;
+ for (auto *Pred : children<Inverse<N>>(NewBBSucc)) {
+ if (Pred != NewBB && !dominates(NewBBSucc, Pred) &&
+ isReachableFromEntry(Pred)) {
+ NewBBDominatesNewBBSucc = false;
+ break;
+ }
+ }
+
+ // Find NewBB's immediate dominator and create new dominator tree node for
+ // NewBB.
+ NodeT *NewBBIDom = nullptr;
+ unsigned i = 0;
+ for (i = 0; i < PredBlocks.size(); ++i)
+ if (isReachableFromEntry(PredBlocks[i])) {
+ NewBBIDom = PredBlocks[i];
+ break;
+ }
+
+ // It's possible that none of the predecessors of NewBB are reachable;
+ // in that case, NewBB itself is unreachable, so nothing needs to be
+ // changed.
+ if (!NewBBIDom) return;
+
+ for (i = i + 1; i < PredBlocks.size(); ++i) {
+ if (isReachableFromEntry(PredBlocks[i]))
+ NewBBIDom = findNearestCommonDominator(NewBBIDom, PredBlocks[i]);
+ }
+
+ // Create the new dominator tree node... and set the idom of NewBB.
+ DomTreeNodeBase<NodeT> *NewBBNode = addNewBlock(NewBB, NewBBIDom);
+
+ // If NewBB strictly dominates other blocks, then it is now the immediate
+ // dominator of NewBBSucc. Update the dominator tree as appropriate.
+ if (NewBBDominatesNewBBSucc) {
+ DomTreeNodeBase<NodeT> *NewBBSuccNode = getNode(NewBBSucc);
+ changeImmediateDominator(NewBBSuccNode, NewBBNode);
+ }
+ }
+
+ private:
+ bool dominatedBySlowTreeWalk(const DomTreeNodeBase<NodeT> *A,
+ const DomTreeNodeBase<NodeT> *B) const {
+ assert(A != B);
+ assert(isReachableFromEntry(B));
+ assert(isReachableFromEntry(A));
+
+ const unsigned ALevel = A->getLevel();
+ const DomTreeNodeBase<NodeT> *IDom;
+
+ // Don't walk nodes above A's subtree. When we reach A's level, we must
+ // either find A or be in some other subtree not dominated by A.
+ while ((IDom = B->getIDom()) != nullptr && IDom->getLevel() >= ALevel)
+ B = IDom; // Walk up the tree
+
+ return B == A;
+ }
+
+ /// Wipe this tree's state without releasing any resources.
+ ///
+ /// This is essentially a post-move helper only. It leaves the object in an
+ /// assignable and destroyable state, but otherwise invalid.
+ void wipe() {
+ DomTreeNodes.clear();
+ RootNode = nullptr;
+ Parent = nullptr;
+ }
+};
+
+template <typename T>
+using DomTreeBase = DominatorTreeBase<T, false>;
+
+template <typename T>
+using PostDomTreeBase = DominatorTreeBase<T, true>;
+
+// These two functions are declared out of line as a workaround for building
+// with old (< r147295) versions of clang because of pr11642.
+template <typename NodeT, bool IsPostDom>
+bool DominatorTreeBase<NodeT, IsPostDom>::dominates(const NodeT *A,
+ const NodeT *B) const {
+ if (A == B)
+ return true;
+
+ // Cast away the const qualifiers here. This is ok since
+ // this function doesn't actually return the values returned
+ // from getNode.
+ return dominates(getNode(const_cast<NodeT *>(A)),
+ getNode(const_cast<NodeT *>(B)));
+}
+template <typename NodeT, bool IsPostDom>
+bool DominatorTreeBase<NodeT, IsPostDom>::properlyDominates(
+ const NodeT *A, const NodeT *B) const {
+ if (A == B)
+ return false;
+
+ // Cast away the const qualifiers here. This is ok since
+ // this function doesn't actually return the values returned
+ // from getNode.
+ return dominates(getNode(const_cast<NodeT *>(A)),
+ getNode(const_cast<NodeT *>(B)));
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_GENERICDOMTREE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/GenericDomTreeConstruction.h b/contrib/libs/llvm16/include/llvm/Support/GenericDomTreeConstruction.h
new file mode 100644
index 00000000000..d5a3a14ee2c
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/GenericDomTreeConstruction.h
@@ -0,0 +1,1641 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- GenericDomTreeConstruction.h - Dominator Calculation ------*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// Generic dominator tree construction - this file provides routines to
+/// construct immediate dominator information for a flow-graph based on the
+/// Semi-NCA algorithm described in this dissertation:
+///
+/// [1] Linear-Time Algorithms for Dominators and Related Problems
+/// Loukas Georgiadis, Princeton University, November 2005, pp. 21-23:
+/// ftp://ftp.cs.princeton.edu/reports/2005/737.pdf
+///
+/// Semi-NCA algorithm runs in O(n^2) worst-case time but usually slightly
+/// faster than Simple Lengauer-Tarjan in practice.
+///
+/// O(n^2) worst cases happen when the computation of nearest common ancestors
+/// requires O(n) average time, which is very unlikely in real world. If this
+/// ever turns out to be an issue, consider implementing a hybrid algorithm
+/// that uses SLT to perform full constructions and SemiNCA for incremental
+/// updates.
+///
+/// The file uses the Depth Based Search algorithm to perform incremental
+/// updates (insertion and deletions). The implemented algorithm is based on
+/// this publication:
+///
+/// [2] An Experimental Study of Dynamic Dominators
+/// Loukas Georgiadis, et al., April 12 2016, pp. 5-7, 9-10:
+/// https://arxiv.org/pdf/1604.02711.pdf
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
+#define LLVM_SUPPORT_GENERICDOMTREECONSTRUCTION_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/GenericDomTree.h"
+#include <optional>
+#include <queue>
+
+#define DEBUG_TYPE "dom-tree-builder"
+
+namespace llvm {
+namespace DomTreeBuilder {
+
+template <typename DomTreeT>
+struct SemiNCAInfo {
+ using NodePtr = typename DomTreeT::NodePtr;
+ using NodeT = typename DomTreeT::NodeType;
+ using TreeNodePtr = DomTreeNodeBase<NodeT> *;
+ using RootsT = decltype(DomTreeT::Roots);
+ static constexpr bool IsPostDom = DomTreeT::IsPostDominator;
+ using GraphDiffT = GraphDiff<NodePtr, IsPostDom>;
+
+ // Information record used by Semi-NCA during tree construction.
+ struct InfoRec {
+ unsigned DFSNum = 0;
+ unsigned Parent = 0;
+ unsigned Semi = 0;
+ NodePtr Label = nullptr;
+ NodePtr IDom = nullptr;
+ SmallVector<NodePtr, 2> ReverseChildren;
+ };
+
+ // Number to node mapping is 1-based. Initialize the mapping to start with
+ // a dummy element.
+ std::vector<NodePtr> NumToNode = {nullptr};
+ DenseMap<NodePtr, InfoRec> NodeToInfo;
+
+ using UpdateT = typename DomTreeT::UpdateType;
+ using UpdateKind = typename DomTreeT::UpdateKind;
+ struct BatchUpdateInfo {
+ // Note: Updates inside PreViewCFG are already legalized.
+ BatchUpdateInfo(GraphDiffT &PreViewCFG, GraphDiffT *PostViewCFG = nullptr)
+ : PreViewCFG(PreViewCFG), PostViewCFG(PostViewCFG),
+ NumLegalized(PreViewCFG.getNumLegalizedUpdates()) {}
+
+ // Remembers if the whole tree was recalculated at some point during the
+ // current batch update.
+ bool IsRecalculated = false;
+ GraphDiffT &PreViewCFG;
+ GraphDiffT *PostViewCFG;
+ const size_t NumLegalized;
+ };
+
+ BatchUpdateInfo *BatchUpdates;
+ using BatchUpdatePtr = BatchUpdateInfo *;
+
+ // If BUI is a nullptr, then there's no batch update in progress.
+ SemiNCAInfo(BatchUpdatePtr BUI) : BatchUpdates(BUI) {}
+
+ void clear() {
+ NumToNode = {nullptr}; // Restore to initial state with a dummy start node.
+ NodeToInfo.clear();
+ // Don't reset the pointer to BatchUpdateInfo here -- if there's an update
+ // in progress, we need this information to continue it.
+ }
+
+ template <bool Inversed>
+ static SmallVector<NodePtr, 8> getChildren(NodePtr N, BatchUpdatePtr BUI) {
+ if (BUI)
+ return BUI->PreViewCFG.template getChildren<Inversed>(N);
+ return getChildren<Inversed>(N);
+ }
+
+ template <bool Inversed>
+ static SmallVector<NodePtr, 8> getChildren(NodePtr N) {
+ using DirectedNodeT =
+ std::conditional_t<Inversed, Inverse<NodePtr>, NodePtr>;
+ auto R = children<DirectedNodeT>(N);
+ SmallVector<NodePtr, 8> Res(detail::reverse_if<!Inversed>(R));
+
+ // Remove nullptr children for clang.
+ llvm::erase_value(Res, nullptr);
+ return Res;
+ }
+
+ NodePtr getIDom(NodePtr BB) const {
+ auto InfoIt = NodeToInfo.find(BB);
+ if (InfoIt == NodeToInfo.end()) return nullptr;
+
+ return InfoIt->second.IDom;
+ }
+
+ TreeNodePtr getNodeForBlock(NodePtr BB, DomTreeT &DT) {
+ if (TreeNodePtr Node = DT.getNode(BB)) return Node;
+
+ // Haven't calculated this node yet? Get or calculate the node for the
+ // immediate dominator.
+ NodePtr IDom = getIDom(BB);
+
+ assert(IDom || DT.DomTreeNodes[nullptr]);
+ TreeNodePtr IDomNode = getNodeForBlock(IDom, DT);
+
+ // Add a new tree node for this NodeT, and link it as a child of
+ // IDomNode
+ return DT.createChild(BB, IDomNode);
+ }
+
+ static bool AlwaysDescend(NodePtr, NodePtr) { return true; }
+
+ struct BlockNamePrinter {
+ NodePtr N;
+
+ BlockNamePrinter(NodePtr Block) : N(Block) {}
+ BlockNamePrinter(TreeNodePtr TN) : N(TN ? TN->getBlock() : nullptr) {}
+
+ friend raw_ostream &operator<<(raw_ostream &O, const BlockNamePrinter &BP) {
+ if (!BP.N)
+ O << "nullptr";
+ else
+ BP.N->printAsOperand(O, false);
+
+ return O;
+ }
+ };
+
+ using NodeOrderMap = DenseMap<NodePtr, unsigned>;
+
+ // Custom DFS implementation which can skip nodes based on a provided
+ // predicate. It also collects ReverseChildren so that we don't have to spend
+ // time getting predecessors in SemiNCA.
+ //
+ // If IsReverse is set to true, the DFS walk will be performed backwards
+ // relative to IsPostDom -- using reverse edges for dominators and forward
+ // edges for postdominators.
+ //
+ // If SuccOrder is specified then in this order the DFS traverses the children
+ // otherwise the order is implied by the results of getChildren().
+ template <bool IsReverse = false, typename DescendCondition>
+ unsigned runDFS(NodePtr V, unsigned LastNum, DescendCondition Condition,
+ unsigned AttachToNum,
+ const NodeOrderMap *SuccOrder = nullptr) {
+ assert(V);
+ SmallVector<NodePtr, 64> WorkList = {V};
+ if (NodeToInfo.count(V) != 0) NodeToInfo[V].Parent = AttachToNum;
+
+ while (!WorkList.empty()) {
+ const NodePtr BB = WorkList.pop_back_val();
+ auto &BBInfo = NodeToInfo[BB];
+
+ // Visited nodes always have positive DFS numbers.
+ if (BBInfo.DFSNum != 0) continue;
+ BBInfo.DFSNum = BBInfo.Semi = ++LastNum;
+ BBInfo.Label = BB;
+ NumToNode.push_back(BB);
+
+ constexpr bool Direction = IsReverse != IsPostDom; // XOR.
+ auto Successors = getChildren<Direction>(BB, BatchUpdates);
+ if (SuccOrder && Successors.size() > 1)
+ llvm::sort(
+ Successors.begin(), Successors.end(), [=](NodePtr A, NodePtr B) {
+ return SuccOrder->find(A)->second < SuccOrder->find(B)->second;
+ });
+
+ for (const NodePtr Succ : Successors) {
+ const auto SIT = NodeToInfo.find(Succ);
+ // Don't visit nodes more than once but remember to collect
+ // ReverseChildren.
+ if (SIT != NodeToInfo.end() && SIT->second.DFSNum != 0) {
+ if (Succ != BB) SIT->second.ReverseChildren.push_back(BB);
+ continue;
+ }
+
+ if (!Condition(BB, Succ)) continue;
+
+ // It's fine to add Succ to the map, because we know that it will be
+ // visited later.
+ auto &SuccInfo = NodeToInfo[Succ];
+ WorkList.push_back(Succ);
+ SuccInfo.Parent = LastNum;
+ SuccInfo.ReverseChildren.push_back(BB);
+ }
+ }
+
+ return LastNum;
+ }
+
+ // V is a predecessor of W. eval() returns V if V < W, otherwise the minimum
+ // of sdom(U), where U > W and there is a virtual forest path from U to V. The
+ // virtual forest consists of linked edges of processed vertices.
+ //
+ // We can follow Parent pointers (virtual forest edges) to determine the
+ // ancestor U with minimum sdom(U). But it is slow and thus we employ the path
+ // compression technique to speed up to O(m*log(n)). Theoretically the virtual
+ // forest can be organized as balanced trees to achieve almost linear
+ // O(m*alpha(m,n)) running time. But it requires two auxiliary arrays (Size
+ // and Child) and is unlikely to be faster than the simple implementation.
+ //
+ // For each vertex V, its Label points to the vertex with the minimal sdom(U)
+ // (Semi) in its path from V (included) to NodeToInfo[V].Parent (excluded).
+ NodePtr eval(NodePtr V, unsigned LastLinked,
+ SmallVectorImpl<InfoRec *> &Stack) {
+ InfoRec *VInfo = &NodeToInfo[V];
+ if (VInfo->Parent < LastLinked)
+ return VInfo->Label;
+
+ // Store ancestors except the last (root of a virtual tree) into a stack.
+ assert(Stack.empty());
+ do {
+ Stack.push_back(VInfo);
+ VInfo = &NodeToInfo[NumToNode[VInfo->Parent]];
+ } while (VInfo->Parent >= LastLinked);
+
+ // Path compression. Point each vertex's Parent to the root and update its
+ // Label if any of its ancestors (PInfo->Label) has a smaller Semi.
+ const InfoRec *PInfo = VInfo;
+ const InfoRec *PLabelInfo = &NodeToInfo[PInfo->Label];
+ do {
+ VInfo = Stack.pop_back_val();
+ VInfo->Parent = PInfo->Parent;
+ const InfoRec *VLabelInfo = &NodeToInfo[VInfo->Label];
+ if (PLabelInfo->Semi < VLabelInfo->Semi)
+ VInfo->Label = PInfo->Label;
+ else
+ PLabelInfo = VLabelInfo;
+ PInfo = VInfo;
+ } while (!Stack.empty());
+ return VInfo->Label;
+ }
+
+ // This function requires DFS to be run before calling it.
+ void runSemiNCA(DomTreeT &DT, const unsigned MinLevel = 0) {
+ const unsigned NextDFSNum(NumToNode.size());
+ // Initialize IDoms to spanning tree parents.
+ for (unsigned i = 1; i < NextDFSNum; ++i) {
+ const NodePtr V = NumToNode[i];
+ auto &VInfo = NodeToInfo[V];
+ VInfo.IDom = NumToNode[VInfo.Parent];
+ }
+
+ // Step #1: Calculate the semidominators of all vertices.
+ SmallVector<InfoRec *, 32> EvalStack;
+ for (unsigned i = NextDFSNum - 1; i >= 2; --i) {
+ NodePtr W = NumToNode[i];
+ auto &WInfo = NodeToInfo[W];
+
+ // Initialize the semi dominator to point to the parent node.
+ WInfo.Semi = WInfo.Parent;
+ for (const auto &N : WInfo.ReverseChildren) {
+ if (NodeToInfo.count(N) == 0) // Skip unreachable predecessors.
+ continue;
+
+ const TreeNodePtr TN = DT.getNode(N);
+ // Skip predecessors whose level is above the subtree we are processing.
+ if (TN && TN->getLevel() < MinLevel)
+ continue;
+
+ unsigned SemiU = NodeToInfo[eval(N, i + 1, EvalStack)].Semi;
+ if (SemiU < WInfo.Semi) WInfo.Semi = SemiU;
+ }
+ }
+
+ // Step #2: Explicitly define the immediate dominator of each vertex.
+ // IDom[i] = NCA(SDom[i], SpanningTreeParent(i)).
+ // Note that the parents were stored in IDoms and later got invalidated
+ // during path compression in Eval.
+ for (unsigned i = 2; i < NextDFSNum; ++i) {
+ const NodePtr W = NumToNode[i];
+ auto &WInfo = NodeToInfo[W];
+ const unsigned SDomNum = NodeToInfo[NumToNode[WInfo.Semi]].DFSNum;
+ NodePtr WIDomCandidate = WInfo.IDom;
+ while (NodeToInfo[WIDomCandidate].DFSNum > SDomNum)
+ WIDomCandidate = NodeToInfo[WIDomCandidate].IDom;
+
+ WInfo.IDom = WIDomCandidate;
+ }
+ }
+
+ // PostDominatorTree always has a virtual root that represents a virtual CFG
+ // node that serves as a single exit from the function. All the other exits
+ // (CFG nodes with terminators and nodes in infinite loops are logically
+ // connected to this virtual CFG exit node).
+ // This functions maps a nullptr CFG node to the virtual root tree node.
+ void addVirtualRoot() {
+ assert(IsPostDom && "Only postdominators have a virtual root");
+ assert(NumToNode.size() == 1 && "SNCAInfo must be freshly constructed");
+
+ auto &BBInfo = NodeToInfo[nullptr];
+ BBInfo.DFSNum = BBInfo.Semi = 1;
+ BBInfo.Label = nullptr;
+
+ NumToNode.push_back(nullptr); // NumToNode[1] = nullptr;
+ }
+
+ // For postdominators, nodes with no forward successors are trivial roots that
+ // are always selected as tree roots. Roots with forward successors correspond
+ // to CFG nodes within infinite loops.
+ static bool HasForwardSuccessors(const NodePtr N, BatchUpdatePtr BUI) {
+ assert(N && "N must be a valid node");
+ return !getChildren<false>(N, BUI).empty();
+ }
+
+ static NodePtr GetEntryNode(const DomTreeT &DT) {
+ assert(DT.Parent && "Parent not set");
+ return GraphTraits<typename DomTreeT::ParentPtr>::getEntryNode(DT.Parent);
+ }
+
+ // Finds all roots without relaying on the set of roots already stored in the
+ // tree.
+ // We define roots to be some non-redundant set of the CFG nodes
+ static RootsT FindRoots(const DomTreeT &DT, BatchUpdatePtr BUI) {
+ assert(DT.Parent && "Parent pointer is not set");
+ RootsT Roots;
+
+ // For dominators, function entry CFG node is always a tree root node.
+ if (!IsPostDom) {
+ Roots.push_back(GetEntryNode(DT));
+ return Roots;
+ }
+
+ SemiNCAInfo SNCA(BUI);
+
+ // PostDominatorTree always has a virtual root.
+ SNCA.addVirtualRoot();
+ unsigned Num = 1;
+
+ LLVM_DEBUG(dbgs() << "\t\tLooking for trivial roots\n");
+
+ // Step #1: Find all the trivial roots that are going to will definitely
+ // remain tree roots.
+ unsigned Total = 0;
+ // It may happen that there are some new nodes in the CFG that are result of
+ // the ongoing batch update, but we cannot really pretend that they don't
+ // exist -- we won't see any outgoing or incoming edges to them, so it's
+ // fine to discover them here, as they would end up appearing in the CFG at
+ // some point anyway.
+ for (const NodePtr N : nodes(DT.Parent)) {
+ ++Total;
+ // If it has no *successors*, it is definitely a root.
+ if (!HasForwardSuccessors(N, BUI)) {
+ Roots.push_back(N);
+ // Run DFS not to walk this part of CFG later.
+ Num = SNCA.runDFS(N, Num, AlwaysDescend, 1);
+ LLVM_DEBUG(dbgs() << "Found a new trivial root: " << BlockNamePrinter(N)
+ << "\n");
+ LLVM_DEBUG(dbgs() << "Last visited node: "
+ << BlockNamePrinter(SNCA.NumToNode[Num]) << "\n");
+ }
+ }
+
+ LLVM_DEBUG(dbgs() << "\t\tLooking for non-trivial roots\n");
+
+ // Step #2: Find all non-trivial root candidates. Those are CFG nodes that
+ // are reverse-unreachable were not visited by previous DFS walks (i.e. CFG
+ // nodes in infinite loops).
+ bool HasNonTrivialRoots = false;
+ // Accounting for the virtual exit, see if we had any reverse-unreachable
+ // nodes.
+ if (Total + 1 != Num) {
+ HasNonTrivialRoots = true;
+
+ // SuccOrder is the order of blocks in the function. It is needed to make
+ // the calculation of the FurthestAway node and the whole PostDomTree
+ // immune to swap successors transformation (e.g. canonicalizing branch
+ // predicates). SuccOrder is initialized lazily only for successors of
+ // reverse unreachable nodes.
+ std::optional<NodeOrderMap> SuccOrder;
+ auto InitSuccOrderOnce = [&]() {
+ SuccOrder = NodeOrderMap();
+ for (const auto Node : nodes(DT.Parent))
+ if (SNCA.NodeToInfo.count(Node) == 0)
+ for (const auto Succ : getChildren<false>(Node, SNCA.BatchUpdates))
+ SuccOrder->try_emplace(Succ, 0);
+
+ // Add mapping for all entries of SuccOrder.
+ unsigned NodeNum = 0;
+ for (const auto Node : nodes(DT.Parent)) {
+ ++NodeNum;
+ auto Order = SuccOrder->find(Node);
+ if (Order != SuccOrder->end()) {
+ assert(Order->second == 0);
+ Order->second = NodeNum;
+ }
+ }
+ };
+
+ // Make another DFS pass over all other nodes to find the
+ // reverse-unreachable blocks, and find the furthest paths we'll be able
+ // to make.
+ // Note that this looks N^2, but it's really 2N worst case, if every node
+ // is unreachable. This is because we are still going to only visit each
+ // unreachable node once, we may just visit it in two directions,
+ // depending on how lucky we get.
+ for (const NodePtr I : nodes(DT.Parent)) {
+ if (SNCA.NodeToInfo.count(I) == 0) {
+ LLVM_DEBUG(dbgs()
+ << "\t\t\tVisiting node " << BlockNamePrinter(I) << "\n");
+ // Find the furthest away we can get by following successors, then
+ // follow them in reverse. This gives us some reasonable answer about
+ // the post-dom tree inside any infinite loop. In particular, it
+ // guarantees we get to the farthest away point along *some*
+ // path. This also matches the GCC's behavior.
+ // If we really wanted a totally complete picture of dominance inside
+ // this infinite loop, we could do it with SCC-like algorithms to find
+ // the lowest and highest points in the infinite loop. In theory, it
+ // would be nice to give the canonical backedge for the loop, but it's
+ // expensive and does not always lead to a minimal set of roots.
+ LLVM_DEBUG(dbgs() << "\t\t\tRunning forward DFS\n");
+
+ if (!SuccOrder)
+ InitSuccOrderOnce();
+ assert(SuccOrder);
+
+ const unsigned NewNum =
+ SNCA.runDFS<true>(I, Num, AlwaysDescend, Num, &*SuccOrder);
+ const NodePtr FurthestAway = SNCA.NumToNode[NewNum];
+ LLVM_DEBUG(dbgs() << "\t\t\tFound a new furthest away node "
+ << "(non-trivial root): "
+ << BlockNamePrinter(FurthestAway) << "\n");
+ Roots.push_back(FurthestAway);
+ LLVM_DEBUG(dbgs() << "\t\t\tPrev DFSNum: " << Num << ", new DFSNum: "
+ << NewNum << "\n\t\t\tRemoving DFS info\n");
+ for (unsigned i = NewNum; i > Num; --i) {
+ const NodePtr N = SNCA.NumToNode[i];
+ LLVM_DEBUG(dbgs() << "\t\t\t\tRemoving DFS info for "
+ << BlockNamePrinter(N) << "\n");
+ SNCA.NodeToInfo.erase(N);
+ SNCA.NumToNode.pop_back();
+ }
+ const unsigned PrevNum = Num;
+ LLVM_DEBUG(dbgs() << "\t\t\tRunning reverse DFS\n");
+ Num = SNCA.runDFS(FurthestAway, Num, AlwaysDescend, 1);
+ for (unsigned i = PrevNum + 1; i <= Num; ++i)
+ LLVM_DEBUG(dbgs() << "\t\t\t\tfound node "
+ << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
+ }
+ }
+ }
+
+ LLVM_DEBUG(dbgs() << "Total: " << Total << ", Num: " << Num << "\n");
+ LLVM_DEBUG(dbgs() << "Discovered CFG nodes:\n");
+ LLVM_DEBUG(for (size_t i = 0; i <= Num; ++i) dbgs()
+ << i << ": " << BlockNamePrinter(SNCA.NumToNode[i]) << "\n");
+
+ assert((Total + 1 == Num) && "Everything should have been visited");
+
+ // Step #3: If we found some non-trivial roots, make them non-redundant.
+ if (HasNonTrivialRoots) RemoveRedundantRoots(DT, BUI, Roots);
+
+ LLVM_DEBUG(dbgs() << "Found roots: ");
+ LLVM_DEBUG(for (auto *Root
+ : Roots) dbgs()
+ << BlockNamePrinter(Root) << " ");
+ LLVM_DEBUG(dbgs() << "\n");
+
+ return Roots;
+ }
+
+ // This function only makes sense for postdominators.
+ // We define roots to be some set of CFG nodes where (reverse) DFS walks have
+ // to start in order to visit all the CFG nodes (including the
+ // reverse-unreachable ones).
+ // When the search for non-trivial roots is done it may happen that some of
+ // the non-trivial roots are reverse-reachable from other non-trivial roots,
+ // which makes them redundant. This function removes them from the set of
+ // input roots.
+ static void RemoveRedundantRoots(const DomTreeT &DT, BatchUpdatePtr BUI,
+ RootsT &Roots) {
+ assert(IsPostDom && "This function is for postdominators only");
+ LLVM_DEBUG(dbgs() << "Removing redundant roots\n");
+
+ SemiNCAInfo SNCA(BUI);
+
+ for (unsigned i = 0; i < Roots.size(); ++i) {
+ auto &Root = Roots[i];
+ // Trivial roots are always non-redundant.
+ if (!HasForwardSuccessors(Root, BUI)) continue;
+ LLVM_DEBUG(dbgs() << "\tChecking if " << BlockNamePrinter(Root)
+ << " remains a root\n");
+ SNCA.clear();
+ // Do a forward walk looking for the other roots.
+ const unsigned Num = SNCA.runDFS<true>(Root, 0, AlwaysDescend, 0);
+ // Skip the start node and begin from the second one (note that DFS uses
+ // 1-based indexing).
+ for (unsigned x = 2; x <= Num; ++x) {
+ const NodePtr N = SNCA.NumToNode[x];
+ // If we wound another root in a (forward) DFS walk, remove the current
+ // root from the set of roots, as it is reverse-reachable from the other
+ // one.
+ if (llvm::is_contained(Roots, N)) {
+ LLVM_DEBUG(dbgs() << "\tForward DFS walk found another root "
+ << BlockNamePrinter(N) << "\n\tRemoving root "
+ << BlockNamePrinter(Root) << "\n");
+ std::swap(Root, Roots.back());
+ Roots.pop_back();
+
+ // Root at the back takes the current root's place.
+ // Start the next loop iteration with the same index.
+ --i;
+ break;
+ }
+ }
+ }
+ }
+
+ template <typename DescendCondition>
+ void doFullDFSWalk(const DomTreeT &DT, DescendCondition DC) {
+ if (!IsPostDom) {
+ assert(DT.Roots.size() == 1 && "Dominators should have a singe root");
+ runDFS(DT.Roots[0], 0, DC, 0);
+ return;
+ }
+
+ addVirtualRoot();
+ unsigned Num = 1;
+ for (const NodePtr Root : DT.Roots) Num = runDFS(Root, Num, DC, 0);
+ }
+
+ static void CalculateFromScratch(DomTreeT &DT, BatchUpdatePtr BUI) {
+ auto *Parent = DT.Parent;
+ DT.reset();
+ DT.Parent = Parent;
+ // If the update is using the actual CFG, BUI is null. If it's using a view,
+ // BUI is non-null and the PreCFGView is used. When calculating from
+ // scratch, make the PreViewCFG equal to the PostCFGView, so Post is used.
+ BatchUpdatePtr PostViewBUI = nullptr;
+ if (BUI && BUI->PostViewCFG) {
+ BUI->PreViewCFG = *BUI->PostViewCFG;
+ PostViewBUI = BUI;
+ }
+ // This is rebuilding the whole tree, not incrementally, but PostViewBUI is
+ // used in case the caller needs a DT update with a CFGView.
+ SemiNCAInfo SNCA(PostViewBUI);
+
+ // Step #0: Number blocks in depth-first order and initialize variables used
+ // in later stages of the algorithm.
+ DT.Roots = FindRoots(DT, PostViewBUI);
+ SNCA.doFullDFSWalk(DT, AlwaysDescend);
+
+ SNCA.runSemiNCA(DT);
+ if (BUI) {
+ BUI->IsRecalculated = true;
+ LLVM_DEBUG(
+ dbgs() << "DomTree recalculated, skipping future batch updates\n");
+ }
+
+ if (DT.Roots.empty()) return;
+
+ // Add a node for the root. If the tree is a PostDominatorTree it will be
+ // the virtual exit (denoted by (BasicBlock *) nullptr) which postdominates
+ // all real exits (including multiple exit blocks, infinite loops).
+ NodePtr Root = IsPostDom ? nullptr : DT.Roots[0];
+
+ DT.RootNode = DT.createNode(Root);
+ SNCA.attachNewSubtree(DT, DT.RootNode);
+ }
+
+ void attachNewSubtree(DomTreeT& DT, const TreeNodePtr AttachTo) {
+ // Attach the first unreachable block to AttachTo.
+ NodeToInfo[NumToNode[1]].IDom = AttachTo->getBlock();
+ // Loop over all of the discovered blocks in the function...
+ for (size_t i = 1, e = NumToNode.size(); i != e; ++i) {
+ NodePtr W = NumToNode[i];
+
+ // Don't replace this with 'count', the insertion side effect is important
+ if (DT.DomTreeNodes[W]) continue; // Haven't calculated this node yet?
+
+ NodePtr ImmDom = getIDom(W);
+
+ // Get or calculate the node for the immediate dominator.
+ TreeNodePtr IDomNode = getNodeForBlock(ImmDom, DT);
+
+ // Add a new tree node for this BasicBlock, and link it as a child of
+ // IDomNode.
+ DT.createChild(W, IDomNode);
+ }
+ }
+
+ void reattachExistingSubtree(DomTreeT &DT, const TreeNodePtr AttachTo) {
+ NodeToInfo[NumToNode[1]].IDom = AttachTo->getBlock();
+ for (size_t i = 1, e = NumToNode.size(); i != e; ++i) {
+ const NodePtr N = NumToNode[i];
+ const TreeNodePtr TN = DT.getNode(N);
+ assert(TN);
+ const TreeNodePtr NewIDom = DT.getNode(NodeToInfo[N].IDom);
+ TN->setIDom(NewIDom);
+ }
+ }
+
+ // Helper struct used during edge insertions.
+ struct InsertionInfo {
+ struct Compare {
+ bool operator()(TreeNodePtr LHS, TreeNodePtr RHS) const {
+ return LHS->getLevel() < RHS->getLevel();
+ }
+ };
+
+ // Bucket queue of tree nodes ordered by descending level. For simplicity,
+ // we use a priority_queue here.
+ std::priority_queue<TreeNodePtr, SmallVector<TreeNodePtr, 8>,
+ Compare>
+ Bucket;
+ SmallDenseSet<TreeNodePtr, 8> Visited;
+ SmallVector<TreeNodePtr, 8> Affected;
+#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
+ SmallVector<TreeNodePtr, 8> VisitedUnaffected;
+#endif
+ };
+
+ static void InsertEdge(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const NodePtr From, const NodePtr To) {
+ assert((From || IsPostDom) &&
+ "From has to be a valid CFG node or a virtual root");
+ assert(To && "Cannot be a nullptr");
+ LLVM_DEBUG(dbgs() << "Inserting edge " << BlockNamePrinter(From) << " -> "
+ << BlockNamePrinter(To) << "\n");
+ TreeNodePtr FromTN = DT.getNode(From);
+
+ if (!FromTN) {
+ // Ignore edges from unreachable nodes for (forward) dominators.
+ if (!IsPostDom) return;
+
+ // The unreachable node becomes a new root -- a tree node for it.
+ TreeNodePtr VirtualRoot = DT.getNode(nullptr);
+ FromTN = DT.createChild(From, VirtualRoot);
+ DT.Roots.push_back(From);
+ }
+
+ DT.DFSInfoValid = false;
+
+ const TreeNodePtr ToTN = DT.getNode(To);
+ if (!ToTN)
+ InsertUnreachable(DT, BUI, FromTN, To);
+ else
+ InsertReachable(DT, BUI, FromTN, ToTN);
+ }
+
+ // Determines if some existing root becomes reverse-reachable after the
+ // insertion. Rebuilds the whole tree if that situation happens.
+ static bool UpdateRootsBeforeInsertion(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr From,
+ const TreeNodePtr To) {
+ assert(IsPostDom && "This function is only for postdominators");
+ // Destination node is not attached to the virtual root, so it cannot be a
+ // root.
+ if (!DT.isVirtualRoot(To->getIDom())) return false;
+
+ if (!llvm::is_contained(DT.Roots, To->getBlock()))
+ return false; // To is not a root, nothing to update.
+
+ LLVM_DEBUG(dbgs() << "\t\tAfter the insertion, " << BlockNamePrinter(To)
+ << " is no longer a root\n\t\tRebuilding the tree!!!\n");
+
+ CalculateFromScratch(DT, BUI);
+ return true;
+ }
+
+ static bool isPermutation(const SmallVectorImpl<NodePtr> &A,
+ const SmallVectorImpl<NodePtr> &B) {
+ if (A.size() != B.size())
+ return false;
+ SmallPtrSet<NodePtr, 4> Set(A.begin(), A.end());
+ for (NodePtr N : B)
+ if (Set.count(N) == 0)
+ return false;
+ return true;
+ }
+
+ // Updates the set of roots after insertion or deletion. This ensures that
+ // roots are the same when after a series of updates and when the tree would
+ // be built from scratch.
+ static void UpdateRootsAfterUpdate(DomTreeT &DT, const BatchUpdatePtr BUI) {
+ assert(IsPostDom && "This function is only for postdominators");
+
+ // The tree has only trivial roots -- nothing to update.
+ if (llvm::none_of(DT.Roots, [BUI](const NodePtr N) {
+ return HasForwardSuccessors(N, BUI);
+ }))
+ return;
+
+ // Recalculate the set of roots.
+ RootsT Roots = FindRoots(DT, BUI);
+ if (!isPermutation(DT.Roots, Roots)) {
+ // The roots chosen in the CFG have changed. This is because the
+ // incremental algorithm does not really know or use the set of roots and
+ // can make a different (implicit) decision about which node within an
+ // infinite loop becomes a root.
+
+ LLVM_DEBUG(dbgs() << "Roots are different in updated trees\n"
+ << "The entire tree needs to be rebuilt\n");
+ // It may be possible to update the tree without recalculating it, but
+ // we do not know yet how to do it, and it happens rarely in practice.
+ CalculateFromScratch(DT, BUI);
+ }
+ }
+
+ // Handles insertion to a node already in the dominator tree.
+ static void InsertReachable(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr From, const TreeNodePtr To) {
+ LLVM_DEBUG(dbgs() << "\tReachable " << BlockNamePrinter(From->getBlock())
+ << " -> " << BlockNamePrinter(To->getBlock()) << "\n");
+ if (IsPostDom && UpdateRootsBeforeInsertion(DT, BUI, From, To)) return;
+ // DT.findNCD expects both pointers to be valid. When From is a virtual
+ // root, then its CFG block pointer is a nullptr, so we have to 'compute'
+ // the NCD manually.
+ const NodePtr NCDBlock =
+ (From->getBlock() && To->getBlock())
+ ? DT.findNearestCommonDominator(From->getBlock(), To->getBlock())
+ : nullptr;
+ assert(NCDBlock || DT.isPostDominator());
+ const TreeNodePtr NCD = DT.getNode(NCDBlock);
+ assert(NCD);
+
+ LLVM_DEBUG(dbgs() << "\t\tNCA == " << BlockNamePrinter(NCD) << "\n");
+ const unsigned NCDLevel = NCD->getLevel();
+
+ // Based on Lemma 2.5 from [2], after insertion of (From,To), v is affected
+ // iff depth(NCD)+1 < depth(v) && a path P from To to v exists where every
+ // w on P s.t. depth(v) <= depth(w)
+ //
+ // This reduces to a widest path problem (maximizing the depth of the
+ // minimum vertex in the path) which can be solved by a modified version of
+ // Dijkstra with a bucket queue (named depth-based search in [2]).
+
+ // To is in the path, so depth(NCD)+1 < depth(v) <= depth(To). Nothing
+ // affected if this does not hold.
+ if (NCDLevel + 1 >= To->getLevel())
+ return;
+
+ InsertionInfo II;
+ SmallVector<TreeNodePtr, 8> UnaffectedOnCurrentLevel;
+ II.Bucket.push(To);
+ II.Visited.insert(To);
+
+ while (!II.Bucket.empty()) {
+ TreeNodePtr TN = II.Bucket.top();
+ II.Bucket.pop();
+ II.Affected.push_back(TN);
+
+ const unsigned CurrentLevel = TN->getLevel();
+ LLVM_DEBUG(dbgs() << "Mark " << BlockNamePrinter(TN) <<
+ "as affected, CurrentLevel " << CurrentLevel << "\n");
+
+ assert(TN->getBlock() && II.Visited.count(TN) && "Preconditions!");
+
+ while (true) {
+ // Unlike regular Dijkstra, we have an inner loop to expand more
+ // vertices. The first iteration is for the (affected) vertex popped
+ // from II.Bucket and the rest are for vertices in
+ // UnaffectedOnCurrentLevel, which may eventually expand to affected
+ // vertices.
+ //
+ // Invariant: there is an optimal path from `To` to TN with the minimum
+ // depth being CurrentLevel.
+ for (const NodePtr Succ : getChildren<IsPostDom>(TN->getBlock(), BUI)) {
+ const TreeNodePtr SuccTN = DT.getNode(Succ);
+ assert(SuccTN &&
+ "Unreachable successor found at reachable insertion");
+ const unsigned SuccLevel = SuccTN->getLevel();
+
+ LLVM_DEBUG(dbgs() << "\tSuccessor " << BlockNamePrinter(Succ)
+ << ", level = " << SuccLevel << "\n");
+
+ // There is an optimal path from `To` to Succ with the minimum depth
+ // being min(CurrentLevel, SuccLevel).
+ //
+ // If depth(NCD)+1 < depth(Succ) is not satisfied, Succ is unaffected
+ // and no affected vertex may be reached by a path passing through it.
+ // Stop here. Also, Succ may be visited by other predecessors but the
+ // first visit has the optimal path. Stop if Succ has been visited.
+ if (SuccLevel <= NCDLevel + 1 || !II.Visited.insert(SuccTN).second)
+ continue;
+
+ if (SuccLevel > CurrentLevel) {
+ // Succ is unaffected but it may (transitively) expand to affected
+ // vertices. Store it in UnaffectedOnCurrentLevel.
+ LLVM_DEBUG(dbgs() << "\t\tMarking visited not affected "
+ << BlockNamePrinter(Succ) << "\n");
+ UnaffectedOnCurrentLevel.push_back(SuccTN);
+#ifndef NDEBUG
+ II.VisitedUnaffected.push_back(SuccTN);
+#endif
+ } else {
+ // The condition is satisfied (Succ is affected). Add Succ to the
+ // bucket queue.
+ LLVM_DEBUG(dbgs() << "\t\tAdd " << BlockNamePrinter(Succ)
+ << " to a Bucket\n");
+ II.Bucket.push(SuccTN);
+ }
+ }
+
+ if (UnaffectedOnCurrentLevel.empty())
+ break;
+ TN = UnaffectedOnCurrentLevel.pop_back_val();
+ LLVM_DEBUG(dbgs() << " Next: " << BlockNamePrinter(TN) << "\n");
+ }
+ }
+
+ // Finish by updating immediate dominators and levels.
+ UpdateInsertion(DT, BUI, NCD, II);
+ }
+
+ // Updates immediate dominators and levels after insertion.
+ static void UpdateInsertion(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr NCD, InsertionInfo &II) {
+ LLVM_DEBUG(dbgs() << "Updating NCD = " << BlockNamePrinter(NCD) << "\n");
+
+ for (const TreeNodePtr TN : II.Affected) {
+ LLVM_DEBUG(dbgs() << "\tIDom(" << BlockNamePrinter(TN)
+ << ") = " << BlockNamePrinter(NCD) << "\n");
+ TN->setIDom(NCD);
+ }
+
+#if defined(LLVM_ENABLE_ABI_BREAKING_CHECKS) && !defined(NDEBUG)
+ for (const TreeNodePtr TN : II.VisitedUnaffected)
+ assert(TN->getLevel() == TN->getIDom()->getLevel() + 1 &&
+ "TN should have been updated by an affected ancestor");
+#endif
+
+ if (IsPostDom) UpdateRootsAfterUpdate(DT, BUI);
+ }
+
+ // Handles insertion to previously unreachable nodes.
+ static void InsertUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr From, const NodePtr To) {
+ LLVM_DEBUG(dbgs() << "Inserting " << BlockNamePrinter(From)
+ << " -> (unreachable) " << BlockNamePrinter(To) << "\n");
+
+ // Collect discovered edges to already reachable nodes.
+ SmallVector<std::pair<NodePtr, TreeNodePtr>, 8> DiscoveredEdgesToReachable;
+ // Discover and connect nodes that became reachable with the insertion.
+ ComputeUnreachableDominators(DT, BUI, To, From, DiscoveredEdgesToReachable);
+
+ LLVM_DEBUG(dbgs() << "Inserted " << BlockNamePrinter(From)
+ << " -> (prev unreachable) " << BlockNamePrinter(To)
+ << "\n");
+
+ // Used the discovered edges and inset discovered connecting (incoming)
+ // edges.
+ for (const auto &Edge : DiscoveredEdgesToReachable) {
+ LLVM_DEBUG(dbgs() << "\tInserting discovered connecting edge "
+ << BlockNamePrinter(Edge.first) << " -> "
+ << BlockNamePrinter(Edge.second) << "\n");
+ InsertReachable(DT, BUI, DT.getNode(Edge.first), Edge.second);
+ }
+ }
+
+ // Connects nodes that become reachable with an insertion.
+ static void ComputeUnreachableDominators(
+ DomTreeT &DT, const BatchUpdatePtr BUI, const NodePtr Root,
+ const TreeNodePtr Incoming,
+ SmallVectorImpl<std::pair<NodePtr, TreeNodePtr>>
+ &DiscoveredConnectingEdges) {
+ assert(!DT.getNode(Root) && "Root must not be reachable");
+
+ // Visit only previously unreachable nodes.
+ auto UnreachableDescender = [&DT, &DiscoveredConnectingEdges](NodePtr From,
+ NodePtr To) {
+ const TreeNodePtr ToTN = DT.getNode(To);
+ if (!ToTN) return true;
+
+ DiscoveredConnectingEdges.push_back({From, ToTN});
+ return false;
+ };
+
+ SemiNCAInfo SNCA(BUI);
+ SNCA.runDFS(Root, 0, UnreachableDescender, 0);
+ SNCA.runSemiNCA(DT);
+ SNCA.attachNewSubtree(DT, Incoming);
+
+ LLVM_DEBUG(dbgs() << "After adding unreachable nodes\n");
+ }
+
+ static void DeleteEdge(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const NodePtr From, const NodePtr To) {
+ assert(From && To && "Cannot disconnect nullptrs");
+ LLVM_DEBUG(dbgs() << "Deleting edge " << BlockNamePrinter(From) << " -> "
+ << BlockNamePrinter(To) << "\n");
+
+#ifdef LLVM_ENABLE_ABI_BREAKING_CHECKS
+ // Ensure that the edge was in fact deleted from the CFG before informing
+ // the DomTree about it.
+ // The check is O(N), so run it only in debug configuration.
+ auto IsSuccessor = [BUI](const NodePtr SuccCandidate, const NodePtr Of) {
+ auto Successors = getChildren<IsPostDom>(Of, BUI);
+ return llvm::is_contained(Successors, SuccCandidate);
+ };
+ (void)IsSuccessor;
+ assert(!IsSuccessor(To, From) && "Deleted edge still exists in the CFG!");
+#endif
+
+ const TreeNodePtr FromTN = DT.getNode(From);
+ // Deletion in an unreachable subtree -- nothing to do.
+ if (!FromTN) return;
+
+ const TreeNodePtr ToTN = DT.getNode(To);
+ if (!ToTN) {
+ LLVM_DEBUG(
+ dbgs() << "\tTo (" << BlockNamePrinter(To)
+ << ") already unreachable -- there is no edge to delete\n");
+ return;
+ }
+
+ const NodePtr NCDBlock = DT.findNearestCommonDominator(From, To);
+ const TreeNodePtr NCD = DT.getNode(NCDBlock);
+
+ // If To dominates From -- nothing to do.
+ if (ToTN != NCD) {
+ DT.DFSInfoValid = false;
+
+ const TreeNodePtr ToIDom = ToTN->getIDom();
+ LLVM_DEBUG(dbgs() << "\tNCD " << BlockNamePrinter(NCD) << ", ToIDom "
+ << BlockNamePrinter(ToIDom) << "\n");
+
+ // To remains reachable after deletion.
+ // (Based on the caption under Figure 4. from [2].)
+ if (FromTN != ToIDom || HasProperSupport(DT, BUI, ToTN))
+ DeleteReachable(DT, BUI, FromTN, ToTN);
+ else
+ DeleteUnreachable(DT, BUI, ToTN);
+ }
+
+ if (IsPostDom) UpdateRootsAfterUpdate(DT, BUI);
+ }
+
+ // Handles deletions that leave destination nodes reachable.
+ static void DeleteReachable(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr FromTN,
+ const TreeNodePtr ToTN) {
+ LLVM_DEBUG(dbgs() << "Deleting reachable " << BlockNamePrinter(FromTN)
+ << " -> " << BlockNamePrinter(ToTN) << "\n");
+ LLVM_DEBUG(dbgs() << "\tRebuilding subtree\n");
+
+ // Find the top of the subtree that needs to be rebuilt.
+ // (Based on the lemma 2.6 from [2].)
+ const NodePtr ToIDom =
+ DT.findNearestCommonDominator(FromTN->getBlock(), ToTN->getBlock());
+ assert(ToIDom || DT.isPostDominator());
+ const TreeNodePtr ToIDomTN = DT.getNode(ToIDom);
+ assert(ToIDomTN);
+ const TreeNodePtr PrevIDomSubTree = ToIDomTN->getIDom();
+ // Top of the subtree to rebuild is the root node. Rebuild the tree from
+ // scratch.
+ if (!PrevIDomSubTree) {
+ LLVM_DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
+ CalculateFromScratch(DT, BUI);
+ return;
+ }
+
+ // Only visit nodes in the subtree starting at To.
+ const unsigned Level = ToIDomTN->getLevel();
+ auto DescendBelow = [Level, &DT](NodePtr, NodePtr To) {
+ return DT.getNode(To)->getLevel() > Level;
+ };
+
+ LLVM_DEBUG(dbgs() << "\tTop of subtree: " << BlockNamePrinter(ToIDomTN)
+ << "\n");
+
+ SemiNCAInfo SNCA(BUI);
+ SNCA.runDFS(ToIDom, 0, DescendBelow, 0);
+ LLVM_DEBUG(dbgs() << "\tRunning Semi-NCA\n");
+ SNCA.runSemiNCA(DT, Level);
+ SNCA.reattachExistingSubtree(DT, PrevIDomSubTree);
+ }
+
+ // Checks if a node has proper support, as defined on the page 3 and later
+ // explained on the page 7 of [2].
+ static bool HasProperSupport(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr TN) {
+ LLVM_DEBUG(dbgs() << "IsReachableFromIDom " << BlockNamePrinter(TN)
+ << "\n");
+ auto TNB = TN->getBlock();
+ for (const NodePtr Pred : getChildren<!IsPostDom>(TNB, BUI)) {
+ LLVM_DEBUG(dbgs() << "\tPred " << BlockNamePrinter(Pred) << "\n");
+ if (!DT.getNode(Pred)) continue;
+
+ const NodePtr Support = DT.findNearestCommonDominator(TNB, Pred);
+ LLVM_DEBUG(dbgs() << "\tSupport " << BlockNamePrinter(Support) << "\n");
+ if (Support != TNB) {
+ LLVM_DEBUG(dbgs() << "\t" << BlockNamePrinter(TN)
+ << " is reachable from support "
+ << BlockNamePrinter(Support) << "\n");
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Handle deletions that make destination node unreachable.
+ // (Based on the lemma 2.7 from the [2].)
+ static void DeleteUnreachable(DomTreeT &DT, const BatchUpdatePtr BUI,
+ const TreeNodePtr ToTN) {
+ LLVM_DEBUG(dbgs() << "Deleting unreachable subtree "
+ << BlockNamePrinter(ToTN) << "\n");
+ assert(ToTN);
+ assert(ToTN->getBlock());
+
+ if (IsPostDom) {
+ // Deletion makes a region reverse-unreachable and creates a new root.
+ // Simulate that by inserting an edge from the virtual root to ToTN and
+ // adding it as a new root.
+ LLVM_DEBUG(dbgs() << "\tDeletion made a region reverse-unreachable\n");
+ LLVM_DEBUG(dbgs() << "\tAdding new root " << BlockNamePrinter(ToTN)
+ << "\n");
+ DT.Roots.push_back(ToTN->getBlock());
+ InsertReachable(DT, BUI, DT.getNode(nullptr), ToTN);
+ return;
+ }
+
+ SmallVector<NodePtr, 16> AffectedQueue;
+ const unsigned Level = ToTN->getLevel();
+
+ // Traverse destination node's descendants with greater level in the tree
+ // and collect visited nodes.
+ auto DescendAndCollect = [Level, &AffectedQueue, &DT](NodePtr, NodePtr To) {
+ const TreeNodePtr TN = DT.getNode(To);
+ assert(TN);
+ if (TN->getLevel() > Level) return true;
+ if (!llvm::is_contained(AffectedQueue, To))
+ AffectedQueue.push_back(To);
+
+ return false;
+ };
+
+ SemiNCAInfo SNCA(BUI);
+ unsigned LastDFSNum =
+ SNCA.runDFS(ToTN->getBlock(), 0, DescendAndCollect, 0);
+
+ TreeNodePtr MinNode = ToTN;
+
+ // Identify the top of the subtree to rebuild by finding the NCD of all
+ // the affected nodes.
+ for (const NodePtr N : AffectedQueue) {
+ const TreeNodePtr TN = DT.getNode(N);
+ const NodePtr NCDBlock =
+ DT.findNearestCommonDominator(TN->getBlock(), ToTN->getBlock());
+ assert(NCDBlock || DT.isPostDominator());
+ const TreeNodePtr NCD = DT.getNode(NCDBlock);
+ assert(NCD);
+
+ LLVM_DEBUG(dbgs() << "Processing affected node " << BlockNamePrinter(TN)
+ << " with NCD = " << BlockNamePrinter(NCD)
+ << ", MinNode =" << BlockNamePrinter(MinNode) << "\n");
+ if (NCD != TN && NCD->getLevel() < MinNode->getLevel()) MinNode = NCD;
+ }
+
+ // Root reached, rebuild the whole tree from scratch.
+ if (!MinNode->getIDom()) {
+ LLVM_DEBUG(dbgs() << "The entire tree needs to be rebuilt\n");
+ CalculateFromScratch(DT, BUI);
+ return;
+ }
+
+ // Erase the unreachable subtree in reverse preorder to process all children
+ // before deleting their parent.
+ for (unsigned i = LastDFSNum; i > 0; --i) {
+ const NodePtr N = SNCA.NumToNode[i];
+ const TreeNodePtr TN = DT.getNode(N);
+ LLVM_DEBUG(dbgs() << "Erasing node " << BlockNamePrinter(TN) << "\n");
+
+ EraseNode(DT, TN);
+ }
+
+ // The affected subtree start at the To node -- there's no extra work to do.
+ if (MinNode == ToTN) return;
+
+ LLVM_DEBUG(dbgs() << "DeleteUnreachable: running DFS with MinNode = "
+ << BlockNamePrinter(MinNode) << "\n");
+ const unsigned MinLevel = MinNode->getLevel();
+ const TreeNodePtr PrevIDom = MinNode->getIDom();
+ assert(PrevIDom);
+ SNCA.clear();
+
+ // Identify nodes that remain in the affected subtree.
+ auto DescendBelow = [MinLevel, &DT](NodePtr, NodePtr To) {
+ const TreeNodePtr ToTN = DT.getNode(To);
+ return ToTN && ToTN->getLevel() > MinLevel;
+ };
+ SNCA.runDFS(MinNode->getBlock(), 0, DescendBelow, 0);
+
+ LLVM_DEBUG(dbgs() << "Previous IDom(MinNode) = "
+ << BlockNamePrinter(PrevIDom) << "\nRunning Semi-NCA\n");
+
+ // Rebuild the remaining part of affected subtree.
+ SNCA.runSemiNCA(DT, MinLevel);
+ SNCA.reattachExistingSubtree(DT, PrevIDom);
+ }
+
+ // Removes leaf tree nodes from the dominator tree.
+ static void EraseNode(DomTreeT &DT, const TreeNodePtr TN) {
+ assert(TN);
+ assert(TN->getNumChildren() == 0 && "Not a tree leaf");
+
+ const TreeNodePtr IDom = TN->getIDom();
+ assert(IDom);
+
+ auto ChIt = llvm::find(IDom->Children, TN);
+ assert(ChIt != IDom->Children.end());
+ std::swap(*ChIt, IDom->Children.back());
+ IDom->Children.pop_back();
+
+ DT.DomTreeNodes.erase(TN->getBlock());
+ }
+
+ //~~
+ //===--------------------- DomTree Batch Updater --------------------------===
+ //~~
+
+ static void ApplyUpdates(DomTreeT &DT, GraphDiffT &PreViewCFG,
+ GraphDiffT *PostViewCFG) {
+ // Note: the PostViewCFG is only used when computing from scratch. It's data
+ // should already included in the PreViewCFG for incremental updates.
+ const size_t NumUpdates = PreViewCFG.getNumLegalizedUpdates();
+ if (NumUpdates == 0)
+ return;
+
+ // Take the fast path for a single update and avoid running the batch update
+ // machinery.
+ if (NumUpdates == 1) {
+ UpdateT Update = PreViewCFG.popUpdateForIncrementalUpdates();
+ if (!PostViewCFG) {
+ if (Update.getKind() == UpdateKind::Insert)
+ InsertEdge(DT, /*BUI=*/nullptr, Update.getFrom(), Update.getTo());
+ else
+ DeleteEdge(DT, /*BUI=*/nullptr, Update.getFrom(), Update.getTo());
+ } else {
+ BatchUpdateInfo BUI(*PostViewCFG, PostViewCFG);
+ if (Update.getKind() == UpdateKind::Insert)
+ InsertEdge(DT, &BUI, Update.getFrom(), Update.getTo());
+ else
+ DeleteEdge(DT, &BUI, Update.getFrom(), Update.getTo());
+ }
+ return;
+ }
+
+ BatchUpdateInfo BUI(PreViewCFG, PostViewCFG);
+ // Recalculate the DominatorTree when the number of updates
+ // exceeds a threshold, which usually makes direct updating slower than
+ // recalculation. We select this threshold proportional to the
+ // size of the DominatorTree. The constant is selected
+ // by choosing the one with an acceptable performance on some real-world
+ // inputs.
+
+ // Make unittests of the incremental algorithm work
+ if (DT.DomTreeNodes.size() <= 100) {
+ if (BUI.NumLegalized > DT.DomTreeNodes.size())
+ CalculateFromScratch(DT, &BUI);
+ } else if (BUI.NumLegalized > DT.DomTreeNodes.size() / 40)
+ CalculateFromScratch(DT, &BUI);
+
+ // If the DominatorTree was recalculated at some point, stop the batch
+ // updates. Full recalculations ignore batch updates and look at the actual
+ // CFG.
+ for (size_t i = 0; i < BUI.NumLegalized && !BUI.IsRecalculated; ++i)
+ ApplyNextUpdate(DT, BUI);
+ }
+
+ static void ApplyNextUpdate(DomTreeT &DT, BatchUpdateInfo &BUI) {
+ // Popping the next update, will move the PreViewCFG to the next snapshot.
+ UpdateT CurrentUpdate = BUI.PreViewCFG.popUpdateForIncrementalUpdates();
+#if 0
+ // FIXME: The LLVM_DEBUG macro only plays well with a modular
+ // build of LLVM when the header is marked as textual, but doing
+ // so causes redefinition errors.
+ LLVM_DEBUG(dbgs() << "Applying update: ");
+ LLVM_DEBUG(CurrentUpdate.dump(); dbgs() << "\n");
+#endif
+
+ if (CurrentUpdate.getKind() == UpdateKind::Insert)
+ InsertEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo());
+ else
+ DeleteEdge(DT, &BUI, CurrentUpdate.getFrom(), CurrentUpdate.getTo());
+ }
+
+ //~~
+ //===--------------- DomTree correctness verification ---------------------===
+ //~~
+
+ // Check if the tree has correct roots. A DominatorTree always has a single
+ // root which is the function's entry node. A PostDominatorTree can have
+ // multiple roots - one for each node with no successors and for infinite
+ // loops.
+ // Running time: O(N).
+ bool verifyRoots(const DomTreeT &DT) {
+ if (!DT.Parent && !DT.Roots.empty()) {
+ errs() << "Tree has no parent but has roots!\n";
+ errs().flush();
+ return false;
+ }
+
+ if (!IsPostDom) {
+ if (DT.Roots.empty()) {
+ errs() << "Tree doesn't have a root!\n";
+ errs().flush();
+ return false;
+ }
+
+ if (DT.getRoot() != GetEntryNode(DT)) {
+ errs() << "Tree's root is not its parent's entry node!\n";
+ errs().flush();
+ return false;
+ }
+ }
+
+ RootsT ComputedRoots = FindRoots(DT, nullptr);
+ if (!isPermutation(DT.Roots, ComputedRoots)) {
+ errs() << "Tree has different roots than freshly computed ones!\n";
+ errs() << "\tPDT roots: ";
+ for (const NodePtr N : DT.Roots) errs() << BlockNamePrinter(N) << ", ";
+ errs() << "\n\tComputed roots: ";
+ for (const NodePtr N : ComputedRoots)
+ errs() << BlockNamePrinter(N) << ", ";
+ errs() << "\n";
+ errs().flush();
+ return false;
+ }
+
+ return true;
+ }
+
+ // Checks if the tree contains all reachable nodes in the input graph.
+ // Running time: O(N).
+ bool verifyReachability(const DomTreeT &DT) {
+ clear();
+ doFullDFSWalk(DT, AlwaysDescend);
+
+ for (auto &NodeToTN : DT.DomTreeNodes) {
+ const TreeNodePtr TN = NodeToTN.second.get();
+ const NodePtr BB = TN->getBlock();
+
+ // Virtual root has a corresponding virtual CFG node.
+ if (DT.isVirtualRoot(TN)) continue;
+
+ if (NodeToInfo.count(BB) == 0) {
+ errs() << "DomTree node " << BlockNamePrinter(BB)
+ << " not found by DFS walk!\n";
+ errs().flush();
+
+ return false;
+ }
+ }
+
+ for (const NodePtr N : NumToNode) {
+ if (N && !DT.getNode(N)) {
+ errs() << "CFG node " << BlockNamePrinter(N)
+ << " not found in the DomTree!\n";
+ errs().flush();
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // Check if for every parent with a level L in the tree all of its children
+ // have level L + 1.
+ // Running time: O(N).
+ static bool VerifyLevels(const DomTreeT &DT) {
+ for (auto &NodeToTN : DT.DomTreeNodes) {
+ const TreeNodePtr TN = NodeToTN.second.get();
+ const NodePtr BB = TN->getBlock();
+ if (!BB) continue;
+
+ const TreeNodePtr IDom = TN->getIDom();
+ if (!IDom && TN->getLevel() != 0) {
+ errs() << "Node without an IDom " << BlockNamePrinter(BB)
+ << " has a nonzero level " << TN->getLevel() << "!\n";
+ errs().flush();
+
+ return false;
+ }
+
+ if (IDom && TN->getLevel() != IDom->getLevel() + 1) {
+ errs() << "Node " << BlockNamePrinter(BB) << " has level "
+ << TN->getLevel() << " while its IDom "
+ << BlockNamePrinter(IDom->getBlock()) << " has level "
+ << IDom->getLevel() << "!\n";
+ errs().flush();
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // Check if the computed DFS numbers are correct. Note that DFS info may not
+ // be valid, and when that is the case, we don't verify the numbers.
+ // Running time: O(N log(N)).
+ static bool VerifyDFSNumbers(const DomTreeT &DT) {
+ if (!DT.DFSInfoValid || !DT.Parent)
+ return true;
+
+ const NodePtr RootBB = IsPostDom ? nullptr : *DT.root_begin();
+ const TreeNodePtr Root = DT.getNode(RootBB);
+
+ auto PrintNodeAndDFSNums = [](const TreeNodePtr TN) {
+ errs() << BlockNamePrinter(TN) << " {" << TN->getDFSNumIn() << ", "
+ << TN->getDFSNumOut() << '}';
+ };
+
+ // Verify the root's DFS In number. Although DFS numbering would also work
+ // if we started from some other value, we assume 0-based numbering.
+ if (Root->getDFSNumIn() != 0) {
+ errs() << "DFSIn number for the tree root is not:\n\t";
+ PrintNodeAndDFSNums(Root);
+ errs() << '\n';
+ errs().flush();
+ return false;
+ }
+
+ // For each tree node verify if children's DFS numbers cover their parent's
+ // DFS numbers with no gaps.
+ for (const auto &NodeToTN : DT.DomTreeNodes) {
+ const TreeNodePtr Node = NodeToTN.second.get();
+
+ // Handle tree leaves.
+ if (Node->isLeaf()) {
+ if (Node->getDFSNumIn() + 1 != Node->getDFSNumOut()) {
+ errs() << "Tree leaf should have DFSOut = DFSIn + 1:\n\t";
+ PrintNodeAndDFSNums(Node);
+ errs() << '\n';
+ errs().flush();
+ return false;
+ }
+
+ continue;
+ }
+
+ // Make a copy and sort it such that it is possible to check if there are
+ // no gaps between DFS numbers of adjacent children.
+ SmallVector<TreeNodePtr, 8> Children(Node->begin(), Node->end());
+ llvm::sort(Children, [](const TreeNodePtr Ch1, const TreeNodePtr Ch2) {
+ return Ch1->getDFSNumIn() < Ch2->getDFSNumIn();
+ });
+
+ auto PrintChildrenError = [Node, &Children, PrintNodeAndDFSNums](
+ const TreeNodePtr FirstCh, const TreeNodePtr SecondCh) {
+ assert(FirstCh);
+
+ errs() << "Incorrect DFS numbers for:\n\tParent ";
+ PrintNodeAndDFSNums(Node);
+
+ errs() << "\n\tChild ";
+ PrintNodeAndDFSNums(FirstCh);
+
+ if (SecondCh) {
+ errs() << "\n\tSecond child ";
+ PrintNodeAndDFSNums(SecondCh);
+ }
+
+ errs() << "\nAll children: ";
+ for (const TreeNodePtr Ch : Children) {
+ PrintNodeAndDFSNums(Ch);
+ errs() << ", ";
+ }
+
+ errs() << '\n';
+ errs().flush();
+ };
+
+ if (Children.front()->getDFSNumIn() != Node->getDFSNumIn() + 1) {
+ PrintChildrenError(Children.front(), nullptr);
+ return false;
+ }
+
+ if (Children.back()->getDFSNumOut() + 1 != Node->getDFSNumOut()) {
+ PrintChildrenError(Children.back(), nullptr);
+ return false;
+ }
+
+ for (size_t i = 0, e = Children.size() - 1; i != e; ++i) {
+ if (Children[i]->getDFSNumOut() + 1 != Children[i + 1]->getDFSNumIn()) {
+ PrintChildrenError(Children[i], Children[i + 1]);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // The below routines verify the correctness of the dominator tree relative to
+ // the CFG it's coming from. A tree is a dominator tree iff it has two
+ // properties, called the parent property and the sibling property. Tarjan
+ // and Lengauer prove (but don't explicitly name) the properties as part of
+ // the proofs in their 1972 paper, but the proofs are mostly part of proving
+ // things about semidominators and idoms, and some of them are simply asserted
+ // based on even earlier papers (see, e.g., lemma 2). Some papers refer to
+ // these properties as "valid" and "co-valid". See, e.g., "Dominators,
+ // directed bipolar orders, and independent spanning trees" by Loukas
+ // Georgiadis and Robert E. Tarjan, as well as "Dominator Tree Verification
+ // and Vertex-Disjoint Paths " by the same authors.
+
+ // A very simple and direct explanation of these properties can be found in
+ // "An Experimental Study of Dynamic Dominators", found at
+ // https://arxiv.org/abs/1604.02711
+
+ // The easiest way to think of the parent property is that it's a requirement
+ // of being a dominator. Let's just take immediate dominators. For PARENT to
+ // be an immediate dominator of CHILD, all paths in the CFG must go through
+ // PARENT before they hit CHILD. This implies that if you were to cut PARENT
+ // out of the CFG, there should be no paths to CHILD that are reachable. If
+ // there are, then you now have a path from PARENT to CHILD that goes around
+ // PARENT and still reaches CHILD, which by definition, means PARENT can't be
+ // a dominator of CHILD (let alone an immediate one).
+
+ // The sibling property is similar. It says that for each pair of sibling
+ // nodes in the dominator tree (LEFT and RIGHT) , they must not dominate each
+ // other. If sibling LEFT dominated sibling RIGHT, it means there are no
+ // paths in the CFG from sibling LEFT to sibling RIGHT that do not go through
+ // LEFT, and thus, LEFT is really an ancestor (in the dominator tree) of
+ // RIGHT, not a sibling.
+
+ // It is possible to verify the parent and sibling properties in linear time,
+ // but the algorithms are complex. Instead, we do it in a straightforward
+ // N^2 and N^3 way below, using direct path reachability.
+
+ // Checks if the tree has the parent property: if for all edges from V to W in
+ // the input graph, such that V is reachable, the parent of W in the tree is
+ // an ancestor of V in the tree.
+ // Running time: O(N^2).
+ //
+ // This means that if a node gets disconnected from the graph, then all of
+ // the nodes it dominated previously will now become unreachable.
+ bool verifyParentProperty(const DomTreeT &DT) {
+ for (auto &NodeToTN : DT.DomTreeNodes) {
+ const TreeNodePtr TN = NodeToTN.second.get();
+ const NodePtr BB = TN->getBlock();
+ if (!BB || TN->isLeaf())
+ continue;
+
+ LLVM_DEBUG(dbgs() << "Verifying parent property of node "
+ << BlockNamePrinter(TN) << "\n");
+ clear();
+ doFullDFSWalk(DT, [BB](NodePtr From, NodePtr To) {
+ return From != BB && To != BB;
+ });
+
+ for (TreeNodePtr Child : TN->children())
+ if (NodeToInfo.count(Child->getBlock()) != 0) {
+ errs() << "Child " << BlockNamePrinter(Child)
+ << " reachable after its parent " << BlockNamePrinter(BB)
+ << " is removed!\n";
+ errs().flush();
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // Check if the tree has sibling property: if a node V does not dominate a
+ // node W for all siblings V and W in the tree.
+ // Running time: O(N^3).
+ //
+ // This means that if a node gets disconnected from the graph, then all of its
+ // siblings will now still be reachable.
+ bool verifySiblingProperty(const DomTreeT &DT) {
+ for (auto &NodeToTN : DT.DomTreeNodes) {
+ const TreeNodePtr TN = NodeToTN.second.get();
+ const NodePtr BB = TN->getBlock();
+ if (!BB || TN->isLeaf())
+ continue;
+
+ for (const TreeNodePtr N : TN->children()) {
+ clear();
+ NodePtr BBN = N->getBlock();
+ doFullDFSWalk(DT, [BBN](NodePtr From, NodePtr To) {
+ return From != BBN && To != BBN;
+ });
+
+ for (const TreeNodePtr S : TN->children()) {
+ if (S == N) continue;
+
+ if (NodeToInfo.count(S->getBlock()) == 0) {
+ errs() << "Node " << BlockNamePrinter(S)
+ << " not reachable when its sibling " << BlockNamePrinter(N)
+ << " is removed!\n";
+ errs().flush();
+
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // Check if the given tree is the same as a freshly computed one for the same
+ // Parent.
+ // Running time: O(N^2), but faster in practice (same as tree construction).
+ //
+ // Note that this does not check if that the tree construction algorithm is
+ // correct and should be only used for fast (but possibly unsound)
+ // verification.
+ static bool IsSameAsFreshTree(const DomTreeT &DT) {
+ DomTreeT FreshTree;
+ FreshTree.recalculate(*DT.Parent);
+ const bool Different = DT.compare(FreshTree);
+
+ if (Different) {
+ errs() << (DT.isPostDominator() ? "Post" : "")
+ << "DominatorTree is different than a freshly computed one!\n"
+ << "\tCurrent:\n";
+ DT.print(errs());
+ errs() << "\n\tFreshly computed tree:\n";
+ FreshTree.print(errs());
+ errs().flush();
+ }
+
+ return !Different;
+ }
+};
+
+template <class DomTreeT>
+void Calculate(DomTreeT &DT) {
+ SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, nullptr);
+}
+
+template <typename DomTreeT>
+void CalculateWithUpdates(DomTreeT &DT,
+ ArrayRef<typename DomTreeT::UpdateType> Updates) {
+ // FIXME: Updated to use the PreViewCFG and behave the same as until now.
+ // This behavior is however incorrect; this actually needs the PostViewCFG.
+ GraphDiff<typename DomTreeT::NodePtr, DomTreeT::IsPostDominator> PreViewCFG(
+ Updates, /*ReverseApplyUpdates=*/true);
+ typename SemiNCAInfo<DomTreeT>::BatchUpdateInfo BUI(PreViewCFG);
+ SemiNCAInfo<DomTreeT>::CalculateFromScratch(DT, &BUI);
+}
+
+template <class DomTreeT>
+void InsertEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
+ typename DomTreeT::NodePtr To) {
+ if (DT.isPostDominator()) std::swap(From, To);
+ SemiNCAInfo<DomTreeT>::InsertEdge(DT, nullptr, From, To);
+}
+
+template <class DomTreeT>
+void DeleteEdge(DomTreeT &DT, typename DomTreeT::NodePtr From,
+ typename DomTreeT::NodePtr To) {
+ if (DT.isPostDominator()) std::swap(From, To);
+ SemiNCAInfo<DomTreeT>::DeleteEdge(DT, nullptr, From, To);
+}
+
+template <class DomTreeT>
+void ApplyUpdates(DomTreeT &DT,
+ GraphDiff<typename DomTreeT::NodePtr,
+ DomTreeT::IsPostDominator> &PreViewCFG,
+ GraphDiff<typename DomTreeT::NodePtr,
+ DomTreeT::IsPostDominator> *PostViewCFG) {
+ SemiNCAInfo<DomTreeT>::ApplyUpdates(DT, PreViewCFG, PostViewCFG);
+}
+
+template <class DomTreeT>
+bool Verify(const DomTreeT &DT, typename DomTreeT::VerificationLevel VL) {
+ SemiNCAInfo<DomTreeT> SNCA(nullptr);
+
+ // Simplist check is to compare against a new tree. This will also
+ // usefully print the old and new trees, if they are different.
+ if (!SNCA.IsSameAsFreshTree(DT))
+ return false;
+
+ // Common checks to verify the properties of the tree. O(N log N) at worst.
+ if (!SNCA.verifyRoots(DT) || !SNCA.verifyReachability(DT) ||
+ !SNCA.VerifyLevels(DT) || !SNCA.VerifyDFSNumbers(DT))
+ return false;
+
+ // Extra checks depending on VerificationLevel. Up to O(N^3).
+ if (VL == DomTreeT::VerificationLevel::Basic ||
+ VL == DomTreeT::VerificationLevel::Full)
+ if (!SNCA.verifyParentProperty(DT))
+ return false;
+ if (VL == DomTreeT::VerificationLevel::Full)
+ if (!SNCA.verifySiblingProperty(DT))
+ return false;
+
+ return true;
+}
+
+} // namespace DomTreeBuilder
+} // namespace llvm
+
+#undef DEBUG_TYPE
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/GenericIteratedDominanceFrontier.h b/contrib/libs/llvm16/include/llvm/Support/GenericIteratedDominanceFrontier.h
new file mode 100644
index 00000000000..ef576216fe5
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/GenericIteratedDominanceFrontier.h
@@ -0,0 +1,220 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- IteratedDominanceFrontier.h - Calculate IDF --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// Compute iterated dominance frontiers using a linear time algorithm.
+///
+/// The algorithm used here is based on:
+///
+/// Sreedhar and Gao. A linear time algorithm for placing phi-nodes.
+/// In Proceedings of the 22nd ACM SIGPLAN-SIGACT Symposium on Principles of
+/// Programming Languages
+/// POPL '95. ACM, New York, NY, 62-73.
+///
+/// It has been modified to not explicitly use the DJ graph data structure and
+/// to directly compute pruned SSA using per-variable liveness information.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_GENERICITERATEDDOMINANCEFRONTIER_H
+#define LLVM_SUPPORT_GENERICITERATEDDOMINANCEFRONTIER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/GenericDomTree.h"
+#include <queue>
+
+namespace llvm {
+
+namespace IDFCalculatorDetail {
+
+/// Generic utility class used for getting the children of a basic block.
+/// May be specialized if, for example, one wouldn't like to return nullpointer
+/// successors.
+template <class NodeTy, bool IsPostDom> struct ChildrenGetterTy {
+ using NodeRef = typename GraphTraits<NodeTy *>::NodeRef;
+ using ChildrenTy = SmallVector<NodeRef, 8>;
+
+ ChildrenTy get(const NodeRef &N);
+};
+
+} // end of namespace IDFCalculatorDetail
+
+/// Determine the iterated dominance frontier, given a set of defining
+/// blocks, and optionally, a set of live-in blocks.
+///
+/// In turn, the results can be used to place phi nodes.
+///
+/// This algorithm is a linear time computation of Iterated Dominance Frontiers,
+/// pruned using the live-in set.
+/// By default, liveness is not used to prune the IDF computation.
+/// The template parameters should be of a CFG block type.
+template <class NodeTy, bool IsPostDom> class IDFCalculatorBase {
+public:
+ using OrderedNodeTy =
+ std::conditional_t<IsPostDom, Inverse<NodeTy *>, NodeTy *>;
+ using ChildrenGetterTy =
+ IDFCalculatorDetail::ChildrenGetterTy<NodeTy, IsPostDom>;
+
+ IDFCalculatorBase(DominatorTreeBase<NodeTy, IsPostDom> &DT) : DT(DT) {}
+
+ IDFCalculatorBase(DominatorTreeBase<NodeTy, IsPostDom> &DT,
+ const ChildrenGetterTy &C)
+ : DT(DT), ChildrenGetter(C) {}
+
+ /// Give the IDF calculator the set of blocks in which the value is
+ /// defined. This is equivalent to the set of starting blocks it should be
+ /// calculating the IDF for (though later gets pruned based on liveness).
+ ///
+ /// Note: This set *must* live for the entire lifetime of the IDF calculator.
+ void setDefiningBlocks(const SmallPtrSetImpl<NodeTy *> &Blocks) {
+ DefBlocks = &Blocks;
+ }
+
+ /// Give the IDF calculator the set of blocks in which the value is
+ /// live on entry to the block. This is used to prune the IDF calculation to
+ /// not include blocks where any phi insertion would be dead.
+ ///
+ /// Note: This set *must* live for the entire lifetime of the IDF calculator.
+ void setLiveInBlocks(const SmallPtrSetImpl<NodeTy *> &Blocks) {
+ LiveInBlocks = &Blocks;
+ useLiveIn = true;
+ }
+
+ /// Reset the live-in block set to be empty, and tell the IDF
+ /// calculator to not use liveness anymore.
+ void resetLiveInBlocks() {
+ LiveInBlocks = nullptr;
+ useLiveIn = false;
+ }
+
+ /// Calculate iterated dominance frontiers
+ ///
+ /// This uses the linear-time phi algorithm based on DJ-graphs mentioned in
+ /// the file-level comment. It performs DF->IDF pruning using the live-in
+ /// set, to avoid computing the IDF for blocks where an inserted PHI node
+ /// would be dead.
+ void calculate(SmallVectorImpl<NodeTy *> &IDFBlocks);
+
+private:
+ DominatorTreeBase<NodeTy, IsPostDom> &DT;
+ ChildrenGetterTy ChildrenGetter;
+ bool useLiveIn = false;
+ const SmallPtrSetImpl<NodeTy *> *LiveInBlocks;
+ const SmallPtrSetImpl<NodeTy *> *DefBlocks;
+};
+
+//===----------------------------------------------------------------------===//
+// Implementation.
+//===----------------------------------------------------------------------===//
+
+namespace IDFCalculatorDetail {
+
+template <class NodeTy, bool IsPostDom>
+typename ChildrenGetterTy<NodeTy, IsPostDom>::ChildrenTy
+ChildrenGetterTy<NodeTy, IsPostDom>::get(const NodeRef &N) {
+ using OrderedNodeTy =
+ typename IDFCalculatorBase<NodeTy, IsPostDom>::OrderedNodeTy;
+
+ auto Children = children<OrderedNodeTy>(N);
+ return {Children.begin(), Children.end()};
+}
+
+} // end of namespace IDFCalculatorDetail
+
+template <class NodeTy, bool IsPostDom>
+void IDFCalculatorBase<NodeTy, IsPostDom>::calculate(
+ SmallVectorImpl<NodeTy *> &IDFBlocks) {
+ // Use a priority queue keyed on dominator tree level so that inserted nodes
+ // are handled from the bottom of the dominator tree upwards. We also augment
+ // the level with a DFS number to ensure that the blocks are ordered in a
+ // deterministic way.
+ using DomTreeNodePair =
+ std::pair<DomTreeNodeBase<NodeTy> *, std::pair<unsigned, unsigned>>;
+ using IDFPriorityQueue =
+ std::priority_queue<DomTreeNodePair, SmallVector<DomTreeNodePair, 32>,
+ less_second>;
+
+ IDFPriorityQueue PQ;
+
+ DT.updateDFSNumbers();
+
+ SmallVector<DomTreeNodeBase<NodeTy> *, 32> Worklist;
+ SmallPtrSet<DomTreeNodeBase<NodeTy> *, 32> VisitedPQ;
+ SmallPtrSet<DomTreeNodeBase<NodeTy> *, 32> VisitedWorklist;
+
+ for (NodeTy *BB : *DefBlocks)
+ if (DomTreeNodeBase<NodeTy> *Node = DT.getNode(BB)) {
+ PQ.push({Node, std::make_pair(Node->getLevel(), Node->getDFSNumIn())});
+ VisitedWorklist.insert(Node);
+ }
+
+ while (!PQ.empty()) {
+ DomTreeNodePair RootPair = PQ.top();
+ PQ.pop();
+ DomTreeNodeBase<NodeTy> *Root = RootPair.first;
+ unsigned RootLevel = RootPair.second.first;
+
+ // Walk all dominator tree children of Root, inspecting their CFG edges with
+ // targets elsewhere on the dominator tree. Only targets whose level is at
+ // most Root's level are added to the iterated dominance frontier of the
+ // definition set.
+
+ assert(Worklist.empty());
+ Worklist.push_back(Root);
+
+ while (!Worklist.empty()) {
+ DomTreeNodeBase<NodeTy> *Node = Worklist.pop_back_val();
+ NodeTy *BB = Node->getBlock();
+ // Succ is the successor in the direction we are calculating IDF, so it is
+ // successor for IDF, and predecessor for Reverse IDF.
+ auto DoWork = [&](NodeTy *Succ) {
+ DomTreeNodeBase<NodeTy> *SuccNode = DT.getNode(Succ);
+
+ const unsigned SuccLevel = SuccNode->getLevel();
+ if (SuccLevel > RootLevel)
+ return;
+
+ if (!VisitedPQ.insert(SuccNode).second)
+ return;
+
+ NodeTy *SuccBB = SuccNode->getBlock();
+ if (useLiveIn && !LiveInBlocks->count(SuccBB))
+ return;
+
+ IDFBlocks.emplace_back(SuccBB);
+ if (!DefBlocks->count(SuccBB))
+ PQ.push(std::make_pair(
+ SuccNode, std::make_pair(SuccLevel, SuccNode->getDFSNumIn())));
+ };
+
+ for (auto *Succ : ChildrenGetter.get(BB))
+ DoWork(Succ);
+
+ for (auto DomChild : *Node) {
+ if (VisitedWorklist.insert(DomChild).second)
+ Worklist.push_back(DomChild);
+ }
+ }
+ }
+}
+
+} // end of namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/GlobPattern.h b/contrib/libs/llvm16/include/llvm/Support/GlobPattern.h
new file mode 100644
index 00000000000..de38921a796
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/GlobPattern.h
@@ -0,0 +1,68 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- GlobPattern.h - glob pattern matcher implementation -*- C++ -*-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a glob pattern matcher. The glob pattern is the
+// rule used by the shell.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_GLOBPATTERN_H
+#define LLVM_SUPPORT_GLOBPATTERN_H
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/Support/Error.h"
+#include <optional>
+#include <vector>
+
+// This class represents a glob pattern. Supported metacharacters
+// are "*", "?", "\", "[<chars>]", "[^<chars>]", and "[!<chars>]".
+namespace llvm {
+
+template <typename T> class ArrayRef;
+class StringRef;
+
+class GlobPattern {
+public:
+ static Expected<GlobPattern> create(StringRef Pat);
+ bool match(StringRef S) const;
+
+ // Returns true for glob pattern "*". Can be used to avoid expensive
+ // preparation/acquisition of the input for match().
+ bool isTrivialMatchAll() const {
+ if (Prefix && Prefix->empty()) {
+ assert(!Suffix);
+ return true;
+ }
+ return false;
+ }
+
+private:
+ bool matchOne(ArrayRef<BitVector> Pat, StringRef S) const;
+
+ // Parsed glob pattern.
+ std::vector<BitVector> Tokens;
+
+ // The following members are for optimization.
+ std::optional<StringRef> Exact;
+ std::optional<StringRef> Prefix;
+ std::optional<StringRef> Suffix;
+};
+}
+
+#endif // LLVM_SUPPORT_GLOBPATTERN_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/GraphWriter.h b/contrib/libs/llvm16/include/llvm/Support/GraphWriter.h
new file mode 100644
index 00000000000..44ac83f0a5a
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/GraphWriter.h
@@ -0,0 +1,451 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/GraphWriter.h - Write graph to a .dot file --*- 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 defines a simple interface that can be used to print out generic
+// LLVM graphs to ".dot" files. "dot" is a tool that is part of the AT&T
+// graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
+// be used to turn the files output by this interface into a variety of
+// different graphics formats.
+//
+// Graphs do not need to implement any interface past what is already required
+// by the GraphTraits template, but they can choose to implement specializations
+// of the DOTGraphTraits template if they want to customize the graphs output in
+// any way.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_GRAPHWRITER_H
+#define LLVM_SUPPORT_GRAPHWRITER_H
+
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/DOTGraphTraits.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include <iterator>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+
+namespace DOT { // Private functions...
+
+std::string EscapeString(const std::string &Label);
+
+/// Get a color string for this node number. Simply round-robin selects
+/// from a reasonable number of colors.
+StringRef getColorString(unsigned NodeNumber);
+
+} // end namespace DOT
+
+namespace GraphProgram {
+
+enum Name {
+ DOT,
+ FDP,
+ NEATO,
+ TWOPI,
+ CIRCO
+};
+
+} // end namespace GraphProgram
+
+bool DisplayGraph(StringRef Filename, bool wait = true,
+ GraphProgram::Name program = GraphProgram::DOT);
+
+template<typename GraphType>
+class GraphWriter {
+ raw_ostream &O;
+ const GraphType &G;
+ bool RenderUsingHTML = false;
+
+ using DOTTraits = DOTGraphTraits<GraphType>;
+ using GTraits = GraphTraits<GraphType>;
+ using NodeRef = typename GTraits::NodeRef;
+ using node_iterator = typename GTraits::nodes_iterator;
+ using child_iterator = typename GTraits::ChildIteratorType;
+ DOTTraits DTraits;
+
+ static_assert(std::is_pointer<NodeRef>::value,
+ "FIXME: Currently GraphWriter requires the NodeRef type to be "
+ "a pointer.\nThe pointer usage should be moved to "
+ "DOTGraphTraits, and removed from GraphWriter itself.");
+
+ // Writes the edge labels of the node to O and returns true if there are any
+ // edge labels not equal to the empty string "".
+ bool getEdgeSourceLabels(raw_ostream &O, NodeRef Node) {
+ child_iterator EI = GTraits::child_begin(Node);
+ child_iterator EE = GTraits::child_end(Node);
+ bool hasEdgeSourceLabels = false;
+
+ if (RenderUsingHTML)
+ O << "</tr><tr>";
+
+ for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i) {
+ std::string label = DTraits.getEdgeSourceLabel(Node, EI);
+
+ if (label.empty())
+ continue;
+
+ hasEdgeSourceLabels = true;
+
+ if (RenderUsingHTML)
+ O << "<td colspan=\"1\" port=\"s" << i << "\">" << label << "</td>";
+ else {
+ if (i)
+ O << "|";
+
+ O << "<s" << i << ">" << DOT::EscapeString(label);
+ }
+ }
+
+ if (EI != EE && hasEdgeSourceLabels) {
+ if (RenderUsingHTML)
+ O << "<td colspan=\"1\" port=\"s64\">truncated...</td>";
+ else
+ O << "|<s64>truncated...";
+ }
+
+ return hasEdgeSourceLabels;
+ }
+
+public:
+ GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) {
+ DTraits = DOTTraits(SN);
+ RenderUsingHTML = DTraits.renderNodesUsingHTML();
+ }
+
+ void writeGraph(const std::string &Title = "") {
+ // Output the header for the graph...
+ writeHeader(Title);
+
+ // Emit all of the nodes in the graph...
+ writeNodes();
+
+ // Output any customizations on the graph
+ DOTGraphTraits<GraphType>::addCustomGraphFeatures(G, *this);
+
+ // Output the end of the graph
+ writeFooter();
+ }
+
+ void writeHeader(const std::string &Title) {
+ std::string GraphName(DTraits.getGraphName(G));
+
+ if (!Title.empty())
+ O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n";
+ else if (!GraphName.empty())
+ O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n";
+ else
+ O << "digraph unnamed {\n";
+
+ if (DTraits.renderGraphFromBottomUp())
+ O << "\trankdir=\"BT\";\n";
+
+ if (!Title.empty())
+ O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n";
+ else if (!GraphName.empty())
+ O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n";
+ O << DTraits.getGraphProperties(G);
+ O << "\n";
+ }
+
+ void writeFooter() {
+ // Finish off the graph
+ O << "}\n";
+ }
+
+ void writeNodes() {
+ // Loop over the graph, printing it out...
+ for (const auto Node : nodes<GraphType>(G))
+ if (!isNodeHidden(Node))
+ writeNode(Node);
+ }
+
+ bool isNodeHidden(NodeRef Node) { return DTraits.isNodeHidden(Node, G); }
+
+ void writeNode(NodeRef Node) {
+ std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
+
+ O << "\tNode" << static_cast<const void *>(Node) << " [shape=";
+ if (RenderUsingHTML)
+ O << "none,";
+ else
+ O << "record,";
+
+ if (!NodeAttributes.empty()) O << NodeAttributes << ",";
+ O << "label=";
+
+ if (RenderUsingHTML) {
+ // Count the numbewr of edges out of the node to determine how
+ // many columns to span (max 64)
+ unsigned ColSpan = 0;
+ child_iterator EI = GTraits::child_begin(Node);
+ child_iterator EE = GTraits::child_end(Node);
+ for (; EI != EE && ColSpan != 64; ++EI, ++ColSpan)
+ ;
+ if (ColSpan == 0)
+ ColSpan = 1;
+ // Include truncated messages when counting.
+ if (EI != EE)
+ ++ColSpan;
+ O << "<<table border=\"0\" cellborder=\"1\" cellspacing=\"0\""
+ << " cellpadding=\"0\"><tr><td align=\"text\" colspan=\"" << ColSpan
+ << "\">";
+ } else
+ O << "\"{";
+
+ if (!DTraits.renderGraphFromBottomUp()) {
+ if (RenderUsingHTML)
+ O << DTraits.getNodeLabel(Node, G) << "</td>";
+ else
+ O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
+
+ // If we should include the address of the node in the label, do so now.
+ std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
+ if (!Id.empty())
+ O << "|" << DOT::EscapeString(Id);
+
+ std::string NodeDesc = DTraits.getNodeDescription(Node, G);
+ if (!NodeDesc.empty())
+ O << "|" << DOT::EscapeString(NodeDesc);
+ }
+
+ std::string edgeSourceLabels;
+ raw_string_ostream EdgeSourceLabels(edgeSourceLabels);
+ bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
+
+ if (hasEdgeSourceLabels) {
+ if (!DTraits.renderGraphFromBottomUp())
+ if (!RenderUsingHTML)
+ O << "|";
+
+ if (RenderUsingHTML)
+ O << EdgeSourceLabels.str();
+ else
+ O << "{" << EdgeSourceLabels.str() << "}";
+
+ if (DTraits.renderGraphFromBottomUp())
+ if (!RenderUsingHTML)
+ O << "|";
+ }
+
+ if (DTraits.renderGraphFromBottomUp()) {
+ if (RenderUsingHTML)
+ O << DTraits.getNodeLabel(Node, G);
+ else
+ O << DOT::EscapeString(DTraits.getNodeLabel(Node, G));
+
+ // If we should include the address of the node in the label, do so now.
+ std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
+ if (!Id.empty())
+ O << "|" << DOT::EscapeString(Id);
+
+ std::string NodeDesc = DTraits.getNodeDescription(Node, G);
+ if (!NodeDesc.empty())
+ O << "|" << DOT::EscapeString(NodeDesc);
+ }
+
+ if (DTraits.hasEdgeDestLabels()) {
+ O << "|{";
+
+ unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
+ for (; i != e && i != 64; ++i) {
+ if (i) O << "|";
+ O << "<d" << i << ">"
+ << DOT::EscapeString(DTraits.getEdgeDestLabel(Node, i));
+ }
+
+ if (i != e)
+ O << "|<d64>truncated...";
+ O << "}";
+ }
+
+ if (RenderUsingHTML)
+ O << "</tr></table>>";
+ else
+ O << "}\"";
+ O << "];\n"; // Finish printing the "node" line
+
+ // Output all of the edges now
+ child_iterator EI = GTraits::child_begin(Node);
+ child_iterator EE = GTraits::child_end(Node);
+ for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
+ if (!DTraits.isNodeHidden(*EI, G))
+ writeEdge(Node, i, EI);
+ for (; EI != EE; ++EI)
+ if (!DTraits.isNodeHidden(*EI, G))
+ writeEdge(Node, 64, EI);
+ }
+
+ void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI) {
+ if (NodeRef TargetNode = *EI) {
+ int DestPort = -1;
+ if (DTraits.edgeTargetsEdgeSource(Node, EI)) {
+ child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
+
+ // Figure out which edge this targets...
+ unsigned Offset =
+ (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
+ DestPort = static_cast<int>(Offset);
+ }
+
+ if (DTraits.getEdgeSourceLabel(Node, EI).empty())
+ edgeidx = -1;
+
+ emitEdge(static_cast<const void*>(Node), edgeidx,
+ static_cast<const void*>(TargetNode), DestPort,
+ DTraits.getEdgeAttributes(Node, EI, G));
+ }
+ }
+
+ /// emitSimpleNode - Outputs a simple (non-record) node
+ void emitSimpleNode(const void *ID, const std::string &Attr,
+ const std::string &Label, unsigned NumEdgeSources = 0,
+ const std::vector<std::string> *EdgeSourceLabels = nullptr) {
+ O << "\tNode" << ID << "[ ";
+ if (!Attr.empty())
+ O << Attr << ",";
+ O << " label =\"";
+ if (NumEdgeSources) O << "{";
+ O << DOT::EscapeString(Label);
+ if (NumEdgeSources) {
+ O << "|{";
+
+ for (unsigned i = 0; i != NumEdgeSources; ++i) {
+ if (i) O << "|";
+ O << "<s" << i << ">";
+ if (EdgeSourceLabels) O << DOT::EscapeString((*EdgeSourceLabels)[i]);
+ }
+ O << "}}";
+ }
+ O << "\"];\n";
+ }
+
+ /// emitEdge - Output an edge from a simple node into the graph...
+ void emitEdge(const void *SrcNodeID, int SrcNodePort,
+ const void *DestNodeID, int DestNodePort,
+ const std::string &Attrs) {
+ if (SrcNodePort > 64) return; // Eminating from truncated part?
+ if (DestNodePort > 64) DestNodePort = 64; // Targeting the truncated part?
+
+ O << "\tNode" << SrcNodeID;
+ if (SrcNodePort >= 0)
+ O << ":s" << SrcNodePort;
+ O << " -> Node" << DestNodeID;
+ if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
+ O << ":d" << DestNodePort;
+
+ if (!Attrs.empty())
+ O << "[" << Attrs << "]";
+ O << ";\n";
+ }
+
+ /// getOStream - Get the raw output stream into the graph file. Useful to
+ /// write fancy things using addCustomGraphFeatures().
+ raw_ostream &getOStream() {
+ return O;
+ }
+};
+
+template<typename GraphType>
+raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G,
+ bool ShortNames = false,
+ const Twine &Title = "") {
+ // Start the graph emission process...
+ GraphWriter<GraphType> W(O, G, ShortNames);
+
+ // Emit the graph.
+ W.writeGraph(Title.str());
+
+ return O;
+}
+
+std::string createGraphFilename(const Twine &Name, int &FD);
+
+/// Writes graph into a provided @c Filename.
+/// If @c Filename is empty, generates a random one.
+/// \return The resulting filename, or an empty string if writing
+/// failed.
+template <typename GraphType>
+std::string WriteGraph(const GraphType &G, const Twine &Name,
+ bool ShortNames = false,
+ const Twine &Title = "",
+ std::string Filename = "") {
+ int FD;
+ if (Filename.empty()) {
+ Filename = createGraphFilename(Name.str(), FD);
+ } else {
+ std::error_code EC = sys::fs::openFileForWrite(
+ Filename, FD, sys::fs::CD_CreateAlways, sys::fs::OF_Text);
+
+ // Writing over an existing file is not considered an error.
+ if (EC == std::errc::file_exists) {
+ errs() << "file exists, overwriting" << "\n";
+ } else if (EC) {
+ errs() << "error writing into file" << "\n";
+ return "";
+ } else {
+ errs() << "writing to the newly created file " << Filename << "\n";
+ }
+ }
+ raw_fd_ostream O(FD, /*shouldClose=*/ true);
+
+ if (FD == -1) {
+ errs() << "error opening file '" << Filename << "' for writing!\n";
+ return "";
+ }
+
+ llvm::WriteGraph(O, G, ShortNames, Title);
+ errs() << " done. \n";
+
+ return Filename;
+}
+
+/// DumpDotGraph - Just dump a dot graph to the user-provided file name.
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+template <typename GraphType>
+LLVM_DUMP_METHOD void
+dumpDotGraphToFile(const GraphType &G, const Twine &FileName,
+ const Twine &Title, bool ShortNames = false,
+ const Twine &Name = "") {
+ llvm::WriteGraph(G, Name, ShortNames, Title, FileName.str());
+}
+#endif
+
+/// ViewGraph - Emit a dot graph, run 'dot', run gv on the postscript file,
+/// then cleanup. For use from the debugger.
+///
+template<typename GraphType>
+void ViewGraph(const GraphType &G, const Twine &Name,
+ bool ShortNames = false, const Twine &Title = "",
+ GraphProgram::Name Program = GraphProgram::DOT) {
+ std::string Filename = llvm::WriteGraph(G, Name, ShortNames, Title);
+
+ if (Filename.empty())
+ return;
+
+ DisplayGraph(Filename, false, Program);
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_GRAPHWRITER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/HashBuilder.h b/contrib/libs/llvm16/include/llvm/Support/HashBuilder.h
new file mode 100644
index 00000000000..e636485ffac
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/HashBuilder.h
@@ -0,0 +1,442 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/HashBuilder.h - Convenient hashing interface-*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements an interface allowing to conveniently build hashes of
+// various data types, without relying on the underlying hasher type to know
+// about hashed data types.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_HASHBUILDER_H
+#define LLVM_SUPPORT_HASHBUILDER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/type_traits.h"
+
+#include <iterator>
+#include <optional>
+#include <utility>
+
+namespace llvm {
+
+namespace hashbuilder_detail {
+/// Trait to indicate whether a type's bits can be hashed directly (after
+/// endianness correction).
+template <typename U>
+struct IsHashableData
+ : std::integral_constant<bool, is_integral_or_enum<U>::value> {};
+
+} // namespace hashbuilder_detail
+
+/// Declares the hasher member, and functions forwarding directly to the hasher.
+template <typename HasherT> class HashBuilderBase {
+public:
+ template <typename HasherT_ = HasherT>
+ using HashResultTy = decltype(std::declval<HasherT_ &>().final());
+
+ HasherT &getHasher() { return Hasher; }
+
+ /// Forward to `HasherT::update(ArrayRef<uint8_t>)`.
+ ///
+ /// This may not take the size of `Data` into account.
+ /// Users of this function should pay attention to respect endianness
+ /// contraints.
+ void update(ArrayRef<uint8_t> Data) { this->getHasher().update(Data); }
+
+ /// Forward to `HasherT::update(ArrayRef<uint8_t>)`.
+ ///
+ /// This may not take the size of `Data` into account.
+ /// Users of this function should pay attention to respect endianness
+ /// contraints.
+ void update(StringRef Data) {
+ update(
+ ArrayRef(reinterpret_cast<const uint8_t *>(Data.data()), Data.size()));
+ }
+
+ /// Forward to `HasherT::final()` if available.
+ template <typename HasherT_ = HasherT> HashResultTy<HasherT_> final() {
+ return this->getHasher().final();
+ }
+
+ /// Forward to `HasherT::result()` if available.
+ template <typename HasherT_ = HasherT> HashResultTy<HasherT_> result() {
+ return this->getHasher().result();
+ }
+
+protected:
+ explicit HashBuilderBase(HasherT &Hasher) : Hasher(Hasher) {}
+
+ template <typename... ArgTypes>
+ explicit HashBuilderBase(ArgTypes &&...Args)
+ : OptionalHasher(std::in_place, std::forward<ArgTypes>(Args)...),
+ Hasher(*OptionalHasher) {}
+
+private:
+ std::optional<HasherT> OptionalHasher;
+ HasherT &Hasher;
+};
+
+/// Implementation of the `HashBuilder` interface.
+///
+/// `support::endianness::native` is not supported. `HashBuilder` is
+/// expected to canonicalize `support::endianness::native` to one of
+/// `support::endianness::big` or `support::endianness::little`.
+template <typename HasherT, support::endianness Endianness>
+class HashBuilderImpl : public HashBuilderBase<HasherT> {
+ static_assert(Endianness != support::endianness::native,
+ "HashBuilder should canonicalize endianness");
+
+public:
+ explicit HashBuilderImpl(HasherT &Hasher)
+ : HashBuilderBase<HasherT>(Hasher) {}
+ template <typename... ArgTypes>
+ explicit HashBuilderImpl(ArgTypes &&...Args)
+ : HashBuilderBase<HasherT>(Args...) {}
+
+ /// Implement hashing for hashable data types, e.g. integral or enum values.
+ template <typename T>
+ std::enable_if_t<hashbuilder_detail::IsHashableData<T>::value,
+ HashBuilderImpl &>
+ add(T Value) {
+ return adjustForEndiannessAndAdd(Value);
+ }
+
+ /// Support hashing `ArrayRef`.
+ ///
+ /// `Value.size()` is taken into account to ensure cases like
+ /// ```
+ /// builder.add({1});
+ /// builder.add({2, 3});
+ /// ```
+ /// and
+ /// ```
+ /// builder.add({1, 2});
+ /// builder.add({3});
+ /// ```
+ /// do not collide.
+ template <typename T> HashBuilderImpl &add(ArrayRef<T> Value) {
+ // As of implementation time, simply calling `addRange(Value)` would also go
+ // through the `update` fast path. But that would rely on the implementation
+ // details of `ArrayRef::begin()` and `ArrayRef::end()`. Explicitly call
+ // `update` to guarantee the fast path.
+ add(Value.size());
+ if (hashbuilder_detail::IsHashableData<T>::value &&
+ Endianness == support::endian::system_endianness()) {
+ this->update(ArrayRef(reinterpret_cast<const uint8_t *>(Value.begin()),
+ Value.size() * sizeof(T)));
+ } else {
+ for (auto &V : Value)
+ add(V);
+ }
+ return *this;
+ }
+
+ /// Support hashing `StringRef`.
+ ///
+ /// `Value.size()` is taken into account to ensure cases like
+ /// ```
+ /// builder.add("a");
+ /// builder.add("bc");
+ /// ```
+ /// and
+ /// ```
+ /// builder.add("ab");
+ /// builder.add("c");
+ /// ```
+ /// do not collide.
+ HashBuilderImpl &add(StringRef Value) {
+ // As of implementation time, simply calling `addRange(Value)` would also go
+ // through `update`. But that would rely on the implementation of
+ // `StringRef::begin()` and `StringRef::end()`. Explicitly call `update` to
+ // guarantee the fast path.
+ add(Value.size());
+ this->update(ArrayRef(reinterpret_cast<const uint8_t *>(Value.begin()),
+ Value.size()));
+ return *this;
+ }
+
+ template <typename T>
+ using HasAddHashT =
+ decltype(addHash(std::declval<HashBuilderImpl &>(), std::declval<T &>()));
+ /// Implement hashing for user-defined `struct`s.
+ ///
+ /// Any user-define `struct` can participate in hashing via `HashBuilder` by
+ /// providing a `addHash` templated function.
+ ///
+ /// ```
+ /// template <typename HasherT, support::endianness Endianness>
+ /// void addHash(HashBuilder<HasherT, Endianness> &HBuilder,
+ /// const UserDefinedStruct &Value);
+ /// ```
+ ///
+ /// For example:
+ /// ```
+ /// struct SimpleStruct {
+ /// char c;
+ /// int i;
+ /// };
+ ///
+ /// template <typename HasherT, support::endianness Endianness>
+ /// void addHash(HashBuilderImpl<HasherT, Endianness> &HBuilder,
+ /// const SimpleStruct &Value) {
+ /// HBuilder.add(Value.c);
+ /// HBuilder.add(Value.i);
+ /// }
+ /// ```
+ ///
+ /// To avoid endianness issues, specializations of `addHash` should
+ /// generally rely on exising `add`, `addRange`, and `addRangeElements`
+ /// functions. If directly using `update`, an implementation must correctly
+ /// handle endianness.
+ ///
+ /// ```
+ /// struct __attribute__ ((packed)) StructWithFastHash {
+ /// int I;
+ /// char C;
+ ///
+ /// // If possible, we want to hash both `I` and `C` in a single
+ /// // `update` call for performance concerns.
+ /// template <typename HasherT, support::endianness Endianness>
+ /// friend void addHash(HashBuilderImpl<HasherT, Endianness> &HBuilder,
+ /// const StructWithFastHash &Value) {
+ /// if (Endianness == support::endian::system_endianness()) {
+ /// HBuilder.update(ArrayRef(
+ /// reinterpret_cast<const uint8_t *>(&Value), sizeof(Value)));
+ /// } else {
+ /// // Rely on existing `add` methods to handle endianness.
+ /// HBuilder.add(Value.I);
+ /// HBuilder.add(Value.C);
+ /// }
+ /// }
+ /// };
+ /// ```
+ ///
+ /// To avoid collisions, specialization of `addHash` for variable-size
+ /// types must take the size into account.
+ ///
+ /// For example:
+ /// ```
+ /// struct CustomContainer {
+ /// private:
+ /// size_t Size;
+ /// int Elements[100];
+ ///
+ /// public:
+ /// CustomContainer(size_t Size) : Size(Size) {
+ /// for (size_t I = 0; I != Size; ++I)
+ /// Elements[I] = I;
+ /// }
+ /// template <typename HasherT, support::endianness Endianness>
+ /// friend void addHash(HashBuilderImpl<HasherT, Endianness> &HBuilder,
+ /// const CustomContainer &Value) {
+ /// if (Endianness == support::endian::system_endianness()) {
+ /// HBuilder.update(ArrayRef(
+ /// reinterpret_cast<const uint8_t *>(&Value.Size),
+ /// sizeof(Value.Size) + Value.Size * sizeof(Value.Elements[0])));
+ /// } else {
+ /// // `addRange` will take care of encoding the size.
+ /// HBuilder.addRange(&Value.Elements[0], &Value.Elements[0] +
+ /// Value.Size);
+ /// }
+ /// }
+ /// };
+ /// ```
+ template <typename T>
+ std::enable_if_t<is_detected<HasAddHashT, T>::value &&
+ !hashbuilder_detail::IsHashableData<T>::value,
+ HashBuilderImpl &>
+ add(const T &Value) {
+ addHash(*this, Value);
+ return *this;
+ }
+
+ template <typename T1, typename T2>
+ HashBuilderImpl &add(const std::pair<T1, T2> &Value) {
+ return add(Value.first, Value.second);
+ }
+
+ template <typename... Ts> HashBuilderImpl &add(const std::tuple<Ts...> &Arg) {
+ std::apply([this](const auto &...Args) { this->add(Args...); }, Arg);
+ return *this;
+ }
+
+ /// A convenenience variadic helper.
+ /// It simply iterates over its arguments, in order.
+ /// ```
+ /// add(Arg1, Arg2);
+ /// ```
+ /// is equivalent to
+ /// ```
+ /// add(Arg1)
+ /// add(Arg2)
+ /// ```
+ template <typename... Ts>
+ std::enable_if_t<(sizeof...(Ts) > 1), HashBuilderImpl &>
+ add(const Ts &...Args) {
+ return (add(Args), ...);
+ }
+
+ template <typename ForwardIteratorT>
+ HashBuilderImpl &addRange(ForwardIteratorT First, ForwardIteratorT Last) {
+ add(std::distance(First, Last));
+ return addRangeElements(First, Last);
+ }
+
+ template <typename RangeT> HashBuilderImpl &addRange(const RangeT &Range) {
+ return addRange(adl_begin(Range), adl_end(Range));
+ }
+
+ template <typename ForwardIteratorT>
+ HashBuilderImpl &addRangeElements(ForwardIteratorT First,
+ ForwardIteratorT Last) {
+ return addRangeElementsImpl(
+ First, Last,
+ typename std::iterator_traits<ForwardIteratorT>::iterator_category());
+ }
+
+ template <typename RangeT>
+ HashBuilderImpl &addRangeElements(const RangeT &Range) {
+ return addRangeElements(adl_begin(Range), adl_end(Range));
+ }
+
+ template <typename T>
+ using HasByteSwapT = decltype(support::endian::byte_swap(
+ std::declval<T &>(), support::endianness::little));
+ /// Adjust `Value` for the target endianness and add it to the hash.
+ template <typename T>
+ std::enable_if_t<is_detected<HasByteSwapT, T>::value, HashBuilderImpl &>
+ adjustForEndiannessAndAdd(const T &Value) {
+ T SwappedValue = support::endian::byte_swap(Value, Endianness);
+ this->update(ArrayRef(reinterpret_cast<const uint8_t *>(&SwappedValue),
+ sizeof(SwappedValue)));
+ return *this;
+ }
+
+private:
+ // FIXME: Once available, specialize this function for `contiguous_iterator`s,
+ // and use it for `ArrayRef` and `StringRef`.
+ template <typename ForwardIteratorT>
+ HashBuilderImpl &addRangeElementsImpl(ForwardIteratorT First,
+ ForwardIteratorT Last,
+ std::forward_iterator_tag) {
+ for (auto It = First; It != Last; ++It)
+ add(*It);
+ return *this;
+ }
+
+ template <typename T>
+ std::enable_if_t<hashbuilder_detail::IsHashableData<T>::value &&
+ Endianness == support::endian::system_endianness(),
+ HashBuilderImpl &>
+ addRangeElementsImpl(T *First, T *Last, std::forward_iterator_tag) {
+ this->update(ArrayRef(reinterpret_cast<const uint8_t *>(First),
+ (Last - First) * sizeof(T)));
+ return *this;
+ }
+};
+
+/// Interface to help hash various types through a hasher type.
+///
+/// Via provided specializations of `add`, `addRange`, and `addRangeElements`
+/// functions, various types (e.g. `ArrayRef`, `StringRef`, etc.) can be hashed
+/// without requiring any knowledge of hashed types from the hasher type.
+///
+/// The only method expected from the templated hasher type `HasherT` is:
+/// * void update(ArrayRef<uint8_t> Data)
+///
+/// Additionally, the following methods will be forwarded to the hasher type:
+/// * decltype(std::declval<HasherT &>().final()) final()
+/// * decltype(std::declval<HasherT &>().result()) result()
+///
+/// From a user point of view, the interface provides the following:
+/// * `template<typename T> add(const T &Value)`
+/// The `add` function implements hashing of various types.
+/// * `template <typename ItT> void addRange(ItT First, ItT Last)`
+/// The `addRange` function is designed to aid hashing a range of values.
+/// It explicitly adds the size of the range in the hash.
+/// * `template <typename ItT> void addRangeElements(ItT First, ItT Last)`
+/// The `addRangeElements` function is also designed to aid hashing a range of
+/// values. In contrast to `addRange`, it **ignores** the size of the range,
+/// behaving as if elements were added one at a time with `add`.
+///
+/// User-defined `struct` types can participate in this interface by providing
+/// an `addHash` templated function. See the associated template specialization
+/// for details.
+///
+/// This interface does not impose requirements on the hasher
+/// `update(ArrayRef<uint8_t> Data)` method. We want to avoid collisions for
+/// variable-size types; for example for
+/// ```
+/// builder.add({1});
+/// builder.add({2, 3});
+/// ```
+/// and
+/// ```
+/// builder.add({1, 2});
+/// builder.add({3});
+/// ```
+/// . Thus, specializations of `add` and `addHash` for variable-size types must
+/// not assume that the hasher type considers the size as part of the hash; they
+/// must explicitly add the size to the hash. See for example specializations
+/// for `ArrayRef` and `StringRef`.
+///
+/// Additionally, since types are eventually forwarded to the hasher's
+/// `void update(ArrayRef<uint8_t>)` method, endianness plays a role in the hash
+/// computation (for example when computing `add((int)123)`).
+/// Specifiying a non-`native` `Endianness` template parameter allows to compute
+/// stable hash across platforms with different endianness.
+template <class HasherT, support::endianness Endianness>
+using HashBuilder =
+ HashBuilderImpl<HasherT, (Endianness == support::endianness::native
+ ? support::endian::system_endianness()
+ : Endianness)>;
+
+namespace hashbuilder_detail {
+class HashCodeHasher {
+public:
+ HashCodeHasher() : Code(0) {}
+ void update(ArrayRef<uint8_t> Data) {
+ hash_code DataCode = hash_value(Data);
+ Code = hash_combine(Code, DataCode);
+ }
+ hash_code Code;
+};
+
+using HashCodeHashBuilder = HashBuilder<hashbuilder_detail::HashCodeHasher,
+ support::endianness::native>;
+} // namespace hashbuilder_detail
+
+/// Provide a default implementation of `hash_value` when `addHash(const T &)`
+/// is supported.
+template <typename T>
+std::enable_if_t<
+ is_detected<hashbuilder_detail::HashCodeHashBuilder::HasAddHashT, T>::value,
+ hash_code>
+hash_value(const T &Value) {
+ hashbuilder_detail::HashCodeHashBuilder HBuilder;
+ HBuilder.add(Value);
+ return HBuilder.getHasher().Code;
+}
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_HASHBUILDER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Host.h b/contrib/libs/llvm16/include/llvm/Support/Host.h
new file mode 100644
index 00000000000..b1e1b9e4db2
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Host.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/Host.h -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This header is deprecated in favour of `llvm/TargetParser/Host.h`.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/Host.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/InitLLVM.h b/contrib/libs/llvm16/include/llvm/Support/InitLLVM.h
new file mode 100644
index 00000000000..f89411c9796
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/InitLLVM.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- InitLLVM.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_INITLLVM_H
+#define LLVM_SUPPORT_INITLLVM_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include <optional>
+
+// The main() functions in typical LLVM tools start with InitLLVM which does
+// the following one-time initializations:
+//
+// 1. Setting up a signal handler so that pretty stack trace is printed out
+// if a process crashes. A signal handler that exits when a failed write to
+// a pipe occurs may optionally be installed: this is on-by-default.
+//
+// 2. Set up the global new-handler which is called when a memory allocation
+// attempt fails.
+//
+// 3. If running on Windows, obtain command line arguments using a
+// multibyte character-aware API and convert arguments into UTF-8
+// encoding, so that you can assume that command line arguments are
+// always encoded in UTF-8 on any platform.
+//
+// InitLLVM calls llvm_shutdown() on destruction, which cleans up
+// ManagedStatic objects.
+namespace llvm {
+class InitLLVM {
+public:
+ InitLLVM(int &Argc, const char **&Argv,
+ bool InstallPipeSignalExitHandler = true);
+ InitLLVM(int &Argc, char **&Argv, bool InstallPipeSignalExitHandler = true)
+ : InitLLVM(Argc, const_cast<const char **&>(Argv),
+ InstallPipeSignalExitHandler) {}
+
+ ~InitLLVM();
+
+private:
+ BumpPtrAllocator Alloc;
+ SmallVector<const char *, 0> Args;
+ std::optional<PrettyStackTraceProgram> StackPrinter;
+};
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/InstructionCost.h b/contrib/libs/llvm16/include/llvm/Support/InstructionCost.h
new file mode 100644
index 00000000000..a9a7ea1e15d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/InstructionCost.h
@@ -0,0 +1,298 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- InstructionCost.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file defines an InstructionCost class that is used when calculating
+/// the cost of an instruction, or a group of instructions. In addition to a
+/// numeric value representing the cost the class also contains a state that
+/// can be used to encode particular properties, such as a cost being invalid.
+/// Operations on InstructionCost implement saturation arithmetic, so that
+/// accumulating costs on large cost-values don't overflow.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_INSTRUCTIONCOST_H
+#define LLVM_SUPPORT_INSTRUCTIONCOST_H
+
+#include "llvm/Support/MathExtras.h"
+#include <limits>
+#include <optional>
+
+namespace llvm {
+
+class raw_ostream;
+
+class InstructionCost {
+public:
+ using CostType = int64_t;
+
+ /// CostState describes the state of a cost.
+ enum CostState {
+ Valid, /// < The cost value represents a valid cost, even when the
+ /// cost-value is large.
+ Invalid /// < Invalid indicates there is no way to represent the cost as a
+ /// numeric value. This state exists to represent a possible issue,
+ /// e.g. if the cost-model knows the operation cannot be expanded
+ /// into a valid code-sequence by the code-generator. While some
+ /// passes may assert that the calculated cost must be valid, it is
+ /// up to individual passes how to interpret an Invalid cost. For
+ /// example, a transformation pass could choose not to perform a
+ /// transformation if the resulting cost would end up Invalid.
+ /// Because some passes may assert a cost is Valid, it is not
+ /// recommended to use Invalid costs to model 'Unknown'.
+ /// Note that Invalid is semantically different from a (very) high,
+ /// but valid cost, which intentionally indicates no issue, but
+ /// rather a strong preference not to select a certain operation.
+ };
+
+private:
+ CostType Value = 0;
+ CostState State = Valid;
+
+ void propagateState(const InstructionCost &RHS) {
+ if (RHS.State == Invalid)
+ State = Invalid;
+ }
+
+ static CostType getMaxValue() { return std::numeric_limits<CostType>::max(); }
+ static CostType getMinValue() { return std::numeric_limits<CostType>::min(); }
+
+public:
+ // A default constructed InstructionCost is a valid zero cost
+ InstructionCost() = default;
+
+ InstructionCost(CostState) = delete;
+ InstructionCost(CostType Val) : Value(Val), State(Valid) {}
+
+ static InstructionCost getMax() { return getMaxValue(); }
+ static InstructionCost getMin() { return getMinValue(); }
+ static InstructionCost getInvalid(CostType Val = 0) {
+ InstructionCost Tmp(Val);
+ Tmp.setInvalid();
+ return Tmp;
+ }
+
+ bool isValid() const { return State == Valid; }
+ void setValid() { State = Valid; }
+ void setInvalid() { State = Invalid; }
+ CostState getState() const { return State; }
+
+ /// This function is intended to be used as sparingly as possible, since the
+ /// class provides the full range of operator support required for arithmetic
+ /// and comparisons.
+ std::optional<CostType> getValue() const {
+ if (isValid())
+ return Value;
+ return std::nullopt;
+ }
+
+ /// For all of the arithmetic operators provided here any invalid state is
+ /// perpetuated and cannot be removed. Once a cost becomes invalid it stays
+ /// invalid, and it also inherits any invalid state from the RHS.
+ /// Arithmetic work on the actual values is implemented with saturation,
+ /// to avoid overflow when using more extreme cost values.
+
+ InstructionCost &operator+=(const InstructionCost &RHS) {
+ propagateState(RHS);
+
+ // Saturating addition.
+ InstructionCost::CostType Result;
+ if (AddOverflow(Value, RHS.Value, Result))
+ Result = RHS.Value > 0 ? getMaxValue() : getMinValue();
+
+ Value = Result;
+ return *this;
+ }
+
+ InstructionCost &operator+=(const CostType RHS) {
+ InstructionCost RHS2(RHS);
+ *this += RHS2;
+ return *this;
+ }
+
+ InstructionCost &operator-=(const InstructionCost &RHS) {
+ propagateState(RHS);
+
+ // Saturating subtract.
+ InstructionCost::CostType Result;
+ if (SubOverflow(Value, RHS.Value, Result))
+ Result = RHS.Value > 0 ? getMinValue() : getMaxValue();
+ Value = Result;
+ return *this;
+ }
+
+ InstructionCost &operator-=(const CostType RHS) {
+ InstructionCost RHS2(RHS);
+ *this -= RHS2;
+ return *this;
+ }
+
+ InstructionCost &operator*=(const InstructionCost &RHS) {
+ propagateState(RHS);
+
+ // Saturating multiply.
+ InstructionCost::CostType Result;
+ if (MulOverflow(Value, RHS.Value, Result)) {
+ if ((Value > 0 && RHS.Value > 0) || (Value < 0 && RHS.Value < 0))
+ Result = getMaxValue();
+ else
+ Result = getMinValue();
+ }
+
+ Value = Result;
+ return *this;
+ }
+
+ InstructionCost &operator*=(const CostType RHS) {
+ InstructionCost RHS2(RHS);
+ *this *= RHS2;
+ return *this;
+ }
+
+ InstructionCost &operator/=(const InstructionCost &RHS) {
+ propagateState(RHS);
+ Value /= RHS.Value;
+ return *this;
+ }
+
+ InstructionCost &operator/=(const CostType RHS) {
+ InstructionCost RHS2(RHS);
+ *this /= RHS2;
+ return *this;
+ }
+
+ InstructionCost &operator++() {
+ *this += 1;
+ return *this;
+ }
+
+ InstructionCost operator++(int) {
+ InstructionCost Copy = *this;
+ ++*this;
+ return Copy;
+ }
+
+ InstructionCost &operator--() {
+ *this -= 1;
+ return *this;
+ }
+
+ InstructionCost operator--(int) {
+ InstructionCost Copy = *this;
+ --*this;
+ return Copy;
+ }
+
+ /// For the comparison operators we have chosen to use lexicographical
+ /// ordering where valid costs are always considered to be less than invalid
+ /// costs. This avoids having to add asserts to the comparison operators that
+ /// the states are valid and users can test for validity of the cost
+ /// explicitly.
+ bool operator<(const InstructionCost &RHS) const {
+ if (State != RHS.State)
+ return State < RHS.State;
+ return Value < RHS.Value;
+ }
+
+ // Implement in terms of operator< to ensure that the two comparisons stay in
+ // sync
+ bool operator==(const InstructionCost &RHS) const {
+ return !(*this < RHS) && !(RHS < *this);
+ }
+
+ bool operator!=(const InstructionCost &RHS) const { return !(*this == RHS); }
+
+ bool operator==(const CostType RHS) const {
+ InstructionCost RHS2(RHS);
+ return *this == RHS2;
+ }
+
+ bool operator!=(const CostType RHS) const { return !(*this == RHS); }
+
+ bool operator>(const InstructionCost &RHS) const { return RHS < *this; }
+
+ bool operator<=(const InstructionCost &RHS) const { return !(RHS < *this); }
+
+ bool operator>=(const InstructionCost &RHS) const { return !(*this < RHS); }
+
+ bool operator<(const CostType RHS) const {
+ InstructionCost RHS2(RHS);
+ return *this < RHS2;
+ }
+
+ bool operator>(const CostType RHS) const {
+ InstructionCost RHS2(RHS);
+ return *this > RHS2;
+ }
+
+ bool operator<=(const CostType RHS) const {
+ InstructionCost RHS2(RHS);
+ return *this <= RHS2;
+ }
+
+ bool operator>=(const CostType RHS) const {
+ InstructionCost RHS2(RHS);
+ return *this >= RHS2;
+ }
+
+ void print(raw_ostream &OS) const;
+
+ template <class Function>
+ auto map(const Function &F) const -> InstructionCost {
+ if (isValid())
+ return F(Value);
+ return getInvalid();
+ }
+};
+
+inline InstructionCost operator+(const InstructionCost &LHS,
+ const InstructionCost &RHS) {
+ InstructionCost LHS2(LHS);
+ LHS2 += RHS;
+ return LHS2;
+}
+
+inline InstructionCost operator-(const InstructionCost &LHS,
+ const InstructionCost &RHS) {
+ InstructionCost LHS2(LHS);
+ LHS2 -= RHS;
+ return LHS2;
+}
+
+inline InstructionCost operator*(const InstructionCost &LHS,
+ const InstructionCost &RHS) {
+ InstructionCost LHS2(LHS);
+ LHS2 *= RHS;
+ return LHS2;
+}
+
+inline InstructionCost operator/(const InstructionCost &LHS,
+ const InstructionCost &RHS) {
+ InstructionCost LHS2(LHS);
+ LHS2 /= RHS;
+ return LHS2;
+}
+
+inline raw_ostream &operator<<(raw_ostream &OS, const InstructionCost &V) {
+ V.print(OS);
+ return OS;
+}
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ItaniumManglingCanonicalizer.h b/contrib/libs/llvm16/include/llvm/Support/ItaniumManglingCanonicalizer.h
new file mode 100644
index 00000000000..383203e048d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ItaniumManglingCanonicalizer.h
@@ -0,0 +1,104 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- ItaniumManglingCanonicalizer.h -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a class for computing equivalence classes of mangled names
+// given a set of equivalences between name fragments.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H
+#define LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H
+
+#include <cstdint>
+
+namespace llvm {
+
+class StringRef;
+
+/// Canonicalizer for mangled names.
+///
+/// This class allows specifying a list of "equivalent" manglings. For example,
+/// you can specify that Ss is equivalent to
+/// NSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
+/// and then manglings that refer to libstdc++'s 'std::string' will be
+/// considered equivalent to manglings that are the same except that they refer
+/// to libc++'s 'std::string'.
+///
+/// This can be used when data (eg, profiling data) is available for a version
+/// of a program built in a different configuration, with correspondingly
+/// different manglings.
+class ItaniumManglingCanonicalizer {
+public:
+ ItaniumManglingCanonicalizer();
+ ItaniumManglingCanonicalizer(const ItaniumManglingCanonicalizer &) = delete;
+ void operator=(const ItaniumManglingCanonicalizer &) = delete;
+ ~ItaniumManglingCanonicalizer();
+
+ enum class EquivalenceError {
+ Success,
+
+ /// Both the equivalent manglings have already been used as components of
+ /// some other mangling we've looked at. It's too late to add this
+ /// equivalence.
+ ManglingAlreadyUsed,
+
+ /// The first equivalent mangling is invalid.
+ InvalidFirstMangling,
+
+ /// The second equivalent mangling is invalid.
+ InvalidSecondMangling,
+ };
+
+ enum class FragmentKind {
+ /// The mangling fragment is a <name> (or a predefined <substitution>).
+ Name,
+ /// The mangling fragment is a <type>.
+ Type,
+ /// The mangling fragment is an <encoding>.
+ Encoding,
+ };
+
+ /// Add an equivalence between \p First and \p Second. Both manglings must
+ /// live at least as long as the canonicalizer.
+ EquivalenceError addEquivalence(FragmentKind Kind, StringRef First,
+ StringRef Second);
+
+ using Key = uintptr_t;
+
+ /// Form a canonical key for the specified mangling. They key will be the
+ /// same for all equivalent manglings, and different for any two
+ /// non-equivalent manglings, but is otherwise unspecified.
+ ///
+ /// Returns Key() if (and only if) the mangling is not a valid Itanium C++
+ /// ABI mangling.
+ ///
+ /// The string denoted by Mangling must live as long as the canonicalizer.
+ Key canonicalize(StringRef Mangling);
+
+ /// Find a canonical key for the specified mangling, if one has already been
+ /// formed. Otherwise returns Key().
+ Key lookup(StringRef Mangling);
+
+private:
+ struct Impl;
+ Impl *P;
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_ITANIUMMANGLINGCANONICALIZER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/JSON.h b/contrib/libs/llvm16/include/llvm/Support/JSON.h
new file mode 100644
index 00000000000..6a1bbca118e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/JSON.h
@@ -0,0 +1,1091 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- JSON.h - JSON values, parsing and serialization -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+///
+/// \file
+/// This file supports working with JSON data.
+///
+/// It comprises:
+///
+/// - classes which hold dynamically-typed parsed JSON structures
+/// These are value types that can be composed, inspected, and modified.
+/// See json::Value, and the related types json::Object and json::Array.
+///
+/// - functions to parse JSON text into Values, and to serialize Values to text.
+/// See parse(), operator<<, and format_provider.
+///
+/// - a convention and helpers for mapping between json::Value and user-defined
+/// types. See fromJSON(), ObjectMapper, and the class comment on Value.
+///
+/// - an output API json::OStream which can emit JSON without materializing
+/// all structures as json::Value.
+///
+/// Typically, JSON data would be read from an external source, parsed into
+/// a Value, and then converted into some native data structure before doing
+/// real work on it. (And vice versa when writing).
+///
+/// Other serialization mechanisms you may consider:
+///
+/// - YAML is also text-based, and more human-readable than JSON. It's a more
+/// complex format and data model, and YAML parsers aren't ubiquitous.
+/// YAMLParser.h is a streaming parser suitable for parsing large documents
+/// (including JSON, as YAML is a superset). It can be awkward to use
+/// directly. YAML I/O (YAMLTraits.h) provides data mapping that is more
+/// declarative than the toJSON/fromJSON conventions here.
+///
+/// - LLVM bitstream is a space- and CPU- efficient binary format. Typically it
+/// encodes LLVM IR ("bitcode"), but it can be a container for other data.
+/// Low-level reader/writer libraries are in Bitstream/Bitstream*.h
+///
+//===---------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_JSON_H
+#define LLVM_SUPPORT_JSON_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cmath>
+#include <map>
+
+namespace llvm {
+namespace json {
+
+// === String encodings ===
+//
+// JSON strings are character sequences (not byte sequences like std::string).
+// We need to know the encoding, and for simplicity only support UTF-8.
+//
+// - When parsing, invalid UTF-8 is a syntax error like any other
+//
+// - When creating Values from strings, callers must ensure they are UTF-8.
+// with asserts on, invalid UTF-8 will crash the program
+// with asserts off, we'll substitute the replacement character (U+FFFD)
+// Callers can use json::isUTF8() and json::fixUTF8() for validation.
+//
+// - When retrieving strings from Values (e.g. asString()), the result will
+// always be valid UTF-8.
+
+/// Returns true if \p S is valid UTF-8, which is required for use as JSON.
+/// If it returns false, \p Offset is set to a byte offset near the first error.
+bool isUTF8(llvm::StringRef S, size_t *ErrOffset = nullptr);
+/// Replaces invalid UTF-8 sequences in \p S with the replacement character
+/// (U+FFFD). The returned string is valid UTF-8.
+/// This is much slower than isUTF8, so test that first.
+std::string fixUTF8(llvm::StringRef S);
+
+class Array;
+class ObjectKey;
+class Value;
+template <typename T> Value toJSON(const std::optional<T> &Opt);
+
+/// An Object is a JSON object, which maps strings to heterogenous JSON values.
+/// It simulates DenseMap<ObjectKey, Value>. ObjectKey is a maybe-owned string.
+class Object {
+ using Storage = DenseMap<ObjectKey, Value, llvm::DenseMapInfo<StringRef>>;
+ Storage M;
+
+public:
+ using key_type = ObjectKey;
+ using mapped_type = Value;
+ using value_type = Storage::value_type;
+ using iterator = Storage::iterator;
+ using const_iterator = Storage::const_iterator;
+
+ Object() = default;
+ // KV is a trivial key-value struct for list-initialization.
+ // (using std::pair forces extra copies).
+ struct KV;
+ explicit Object(std::initializer_list<KV> Properties);
+
+ iterator begin() { return M.begin(); }
+ const_iterator begin() const { return M.begin(); }
+ iterator end() { return M.end(); }
+ const_iterator end() const { return M.end(); }
+
+ bool empty() const { return M.empty(); }
+ size_t size() const { return M.size(); }
+
+ void clear() { M.clear(); }
+ std::pair<iterator, bool> insert(KV E);
+ template <typename... Ts>
+ std::pair<iterator, bool> try_emplace(const ObjectKey &K, Ts &&... Args) {
+ return M.try_emplace(K, std::forward<Ts>(Args)...);
+ }
+ template <typename... Ts>
+ std::pair<iterator, bool> try_emplace(ObjectKey &&K, Ts &&... Args) {
+ return M.try_emplace(std::move(K), std::forward<Ts>(Args)...);
+ }
+ bool erase(StringRef K);
+ void erase(iterator I) { M.erase(I); }
+
+ iterator find(StringRef K) { return M.find_as(K); }
+ const_iterator find(StringRef K) const { return M.find_as(K); }
+ // operator[] acts as if Value was default-constructible as null.
+ Value &operator[](const ObjectKey &K);
+ Value &operator[](ObjectKey &&K);
+ // Look up a property, returning nullptr if it doesn't exist.
+ Value *get(StringRef K);
+ const Value *get(StringRef K) const;
+ // Typed accessors return std::nullopt/nullptr if
+ // - the property doesn't exist
+ // - or it has the wrong type
+ std::optional<std::nullptr_t> getNull(StringRef K) const;
+ std::optional<bool> getBoolean(StringRef K) const;
+ std::optional<double> getNumber(StringRef K) const;
+ std::optional<int64_t> getInteger(StringRef K) const;
+ std::optional<llvm::StringRef> getString(StringRef K) const;
+ const json::Object *getObject(StringRef K) const;
+ json::Object *getObject(StringRef K);
+ const json::Array *getArray(StringRef K) const;
+ json::Array *getArray(StringRef K);
+};
+bool operator==(const Object &LHS, const Object &RHS);
+inline bool operator!=(const Object &LHS, const Object &RHS) {
+ return !(LHS == RHS);
+}
+
+/// An Array is a JSON array, which contains heterogeneous JSON values.
+/// It simulates std::vector<Value>.
+class Array {
+ std::vector<Value> V;
+
+public:
+ using value_type = Value;
+ using iterator = std::vector<Value>::iterator;
+ using const_iterator = std::vector<Value>::const_iterator;
+
+ Array() = default;
+ explicit Array(std::initializer_list<Value> Elements);
+ template <typename Collection> explicit Array(const Collection &C) {
+ for (const auto &V : C)
+ emplace_back(V);
+ }
+
+ Value &operator[](size_t I);
+ const Value &operator[](size_t I) const;
+ Value &front();
+ const Value &front() const;
+ Value &back();
+ const Value &back() const;
+ Value *data();
+ const Value *data() const;
+
+ iterator begin();
+ const_iterator begin() const;
+ iterator end();
+ const_iterator end() const;
+
+ bool empty() const;
+ size_t size() const;
+ void reserve(size_t S);
+
+ void clear();
+ void push_back(const Value &E);
+ void push_back(Value &&E);
+ template <typename... Args> void emplace_back(Args &&...A);
+ void pop_back();
+ iterator insert(const_iterator P, const Value &E);
+ iterator insert(const_iterator P, Value &&E);
+ template <typename It> iterator insert(const_iterator P, It A, It Z);
+ template <typename... Args> iterator emplace(const_iterator P, Args &&...A);
+
+ friend bool operator==(const Array &L, const Array &R);
+};
+inline bool operator!=(const Array &L, const Array &R) { return !(L == R); }
+
+/// A Value is an JSON value of unknown type.
+/// They can be copied, but should generally be moved.
+///
+/// === Composing values ===
+///
+/// You can implicitly construct Values from:
+/// - strings: std::string, SmallString, formatv, StringRef, char*
+/// (char*, and StringRef are references, not copies!)
+/// - numbers
+/// - booleans
+/// - null: nullptr
+/// - arrays: {"foo", 42.0, false}
+/// - serializable things: types with toJSON(const T&)->Value, found by ADL
+///
+/// They can also be constructed from object/array helpers:
+/// - json::Object is a type like map<ObjectKey, Value>
+/// - json::Array is a type like vector<Value>
+/// These can be list-initialized, or used to build up collections in a loop.
+/// json::ary(Collection) converts all items in a collection to Values.
+///
+/// === Inspecting values ===
+///
+/// Each Value is one of the JSON kinds:
+/// null (nullptr_t)
+/// boolean (bool)
+/// number (double, int64 or uint64)
+/// string (StringRef)
+/// array (json::Array)
+/// object (json::Object)
+///
+/// The kind can be queried directly, or implicitly via the typed accessors:
+/// if (std::optional<StringRef> S = E.getAsString()
+/// assert(E.kind() == Value::String);
+///
+/// Array and Object also have typed indexing accessors for easy traversal:
+/// Expected<Value> E = parse(R"( {"options": {"font": "sans-serif"}} )");
+/// if (Object* O = E->getAsObject())
+/// if (Object* Opts = O->getObject("options"))
+/// if (std::optional<StringRef> Font = Opts->getString("font"))
+/// assert(Opts->at("font").kind() == Value::String);
+///
+/// === Converting JSON values to C++ types ===
+///
+/// The convention is to have a deserializer function findable via ADL:
+/// fromJSON(const json::Value&, T&, Path) -> bool
+///
+/// The return value indicates overall success, and Path is used for precise
+/// error reporting. (The Path::Root passed in at the top level fromJSON call
+/// captures any nested error and can render it in context).
+/// If conversion fails, fromJSON calls Path::report() and immediately returns.
+/// This ensures that the first fatal error survives.
+///
+/// Deserializers are provided for:
+/// - bool
+/// - int and int64_t
+/// - double
+/// - std::string
+/// - vector<T>, where T is deserializable
+/// - map<string, T>, where T is deserializable
+/// - std::optional<T>, where T is deserializable
+/// ObjectMapper can help writing fromJSON() functions for object types.
+///
+/// For conversion in the other direction, the serializer function is:
+/// toJSON(const T&) -> json::Value
+/// If this exists, then it also allows constructing Value from T, and can
+/// be used to serialize vector<T>, map<string, T>, and std::optional<T>.
+///
+/// === Serialization ===
+///
+/// Values can be serialized to JSON:
+/// 1) raw_ostream << Value // Basic formatting.
+/// 2) raw_ostream << formatv("{0}", Value) // Basic formatting.
+/// 3) raw_ostream << formatv("{0:2}", Value) // Pretty-print with indent 2.
+///
+/// And parsed:
+/// Expected<Value> E = json::parse("[1, 2, null]");
+/// assert(E && E->kind() == Value::Array);
+class Value {
+public:
+ enum Kind {
+ Null,
+ Boolean,
+ /// Number values can store both int64s and doubles at full precision,
+ /// depending on what they were constructed/parsed from.
+ Number,
+ String,
+ Array,
+ Object,
+ };
+
+ // It would be nice to have Value() be null. But that would make {} null too.
+ Value(const Value &M) { copyFrom(M); }
+ Value(Value &&M) { moveFrom(std::move(M)); }
+ Value(std::initializer_list<Value> Elements);
+ Value(json::Array &&Elements) : Type(T_Array) {
+ create<json::Array>(std::move(Elements));
+ }
+ template <typename Elt>
+ Value(const std::vector<Elt> &C) : Value(json::Array(C)) {}
+ Value(json::Object &&Properties) : Type(T_Object) {
+ create<json::Object>(std::move(Properties));
+ }
+ template <typename Elt>
+ Value(const std::map<std::string, Elt> &C) : Value(json::Object(C)) {}
+ // Strings: types with value semantics. Must be valid UTF-8.
+ Value(std::string V) : Type(T_String) {
+ if (LLVM_UNLIKELY(!isUTF8(V))) {
+ assert(false && "Invalid UTF-8 in value used as JSON");
+ V = fixUTF8(std::move(V));
+ }
+ create<std::string>(std::move(V));
+ }
+ Value(const llvm::SmallVectorImpl<char> &V)
+ : Value(std::string(V.begin(), V.end())) {}
+ Value(const llvm::formatv_object_base &V) : Value(V.str()) {}
+ // Strings: types with reference semantics. Must be valid UTF-8.
+ Value(StringRef V) : Type(T_StringRef) {
+ create<llvm::StringRef>(V);
+ if (LLVM_UNLIKELY(!isUTF8(V))) {
+ assert(false && "Invalid UTF-8 in value used as JSON");
+ *this = Value(fixUTF8(V));
+ }
+ }
+ Value(const char *V) : Value(StringRef(V)) {}
+ Value(std::nullptr_t) : Type(T_Null) {}
+ // Boolean (disallow implicit conversions).
+ // (The last template parameter is a dummy to keep templates distinct.)
+ template <typename T,
+ typename = std::enable_if_t<std::is_same<T, bool>::value>,
+ bool = false>
+ Value(T B) : Type(T_Boolean) {
+ create<bool>(B);
+ }
+
+ // Unsigned 64-bit long integers.
+ template <typename T,
+ typename = std::enable_if_t<std::is_same<T, uint64_t>::value>,
+ bool = false, bool = false>
+ Value(T V) : Type(T_UINT64) {
+ create<uint64_t>(uint64_t{V});
+ }
+
+ // Integers (except boolean and uint64_t).
+ // Must be non-narrowing convertible to int64_t.
+ template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>,
+ typename = std::enable_if_t<!std::is_same<T, bool>::value>,
+ typename = std::enable_if_t<!std::is_same<T, uint64_t>::value>>
+ Value(T I) : Type(T_Integer) {
+ create<int64_t>(int64_t{I});
+ }
+ // Floating point. Must be non-narrowing convertible to double.
+ template <typename T,
+ typename = std::enable_if_t<std::is_floating_point<T>::value>,
+ double * = nullptr>
+ Value(T D) : Type(T_Double) {
+ create<double>(double{D});
+ }
+ // Serializable types: with a toJSON(const T&)->Value function, found by ADL.
+ template <typename T,
+ typename = std::enable_if_t<std::is_same<
+ Value, decltype(toJSON(*(const T *)nullptr))>::value>,
+ Value * = nullptr>
+ Value(const T &V) : Value(toJSON(V)) {}
+
+ Value &operator=(const Value &M) {
+ destroy();
+ copyFrom(M);
+ return *this;
+ }
+ Value &operator=(Value &&M) {
+ destroy();
+ moveFrom(std::move(M));
+ return *this;
+ }
+ ~Value() { destroy(); }
+
+ Kind kind() const {
+ switch (Type) {
+ case T_Null:
+ return Null;
+ case T_Boolean:
+ return Boolean;
+ case T_Double:
+ case T_Integer:
+ case T_UINT64:
+ return Number;
+ case T_String:
+ case T_StringRef:
+ return String;
+ case T_Object:
+ return Object;
+ case T_Array:
+ return Array;
+ }
+ llvm_unreachable("Unknown kind");
+ }
+
+ // Typed accessors return std::nullopt/nullptr if the Value is not of this
+ // type.
+ std::optional<std::nullptr_t> getAsNull() const {
+ if (LLVM_LIKELY(Type == T_Null))
+ return nullptr;
+ return std::nullopt;
+ }
+ std::optional<bool> getAsBoolean() const {
+ if (LLVM_LIKELY(Type == T_Boolean))
+ return as<bool>();
+ return std::nullopt;
+ }
+ std::optional<double> getAsNumber() const {
+ if (LLVM_LIKELY(Type == T_Double))
+ return as<double>();
+ if (LLVM_LIKELY(Type == T_Integer))
+ return as<int64_t>();
+ if (LLVM_LIKELY(Type == T_UINT64))
+ return as<uint64_t>();
+ return std::nullopt;
+ }
+ // Succeeds if the Value is a Number, and exactly representable as int64_t.
+ std::optional<int64_t> getAsInteger() const {
+ if (LLVM_LIKELY(Type == T_Integer))
+ return as<int64_t>();
+ if (LLVM_LIKELY(Type == T_Double)) {
+ double D = as<double>();
+ if (LLVM_LIKELY(std::modf(D, &D) == 0.0 &&
+ D >= double(std::numeric_limits<int64_t>::min()) &&
+ D <= double(std::numeric_limits<int64_t>::max())))
+ return D;
+ }
+ return std::nullopt;
+ }
+ std::optional<uint64_t> getAsUINT64() const {
+ if (Type == T_UINT64)
+ return as<uint64_t>();
+ else if (Type == T_Integer) {
+ int64_t N = as<int64_t>();
+ if (N >= 0)
+ return as<uint64_t>();
+ }
+ return std::nullopt;
+ }
+ std::optional<llvm::StringRef> getAsString() const {
+ if (Type == T_String)
+ return llvm::StringRef(as<std::string>());
+ if (LLVM_LIKELY(Type == T_StringRef))
+ return as<llvm::StringRef>();
+ return std::nullopt;
+ }
+ const json::Object *getAsObject() const {
+ return LLVM_LIKELY(Type == T_Object) ? &as<json::Object>() : nullptr;
+ }
+ json::Object *getAsObject() {
+ return LLVM_LIKELY(Type == T_Object) ? &as<json::Object>() : nullptr;
+ }
+ const json::Array *getAsArray() const {
+ return LLVM_LIKELY(Type == T_Array) ? &as<json::Array>() : nullptr;
+ }
+ json::Array *getAsArray() {
+ return LLVM_LIKELY(Type == T_Array) ? &as<json::Array>() : nullptr;
+ }
+
+private:
+ void destroy();
+ void copyFrom(const Value &M);
+ // We allow moving from *const* Values, by marking all members as mutable!
+ // This hack is needed to support initializer-list syntax efficiently.
+ // (std::initializer_list<T> is a container of const T).
+ void moveFrom(const Value &&M);
+ friend class Array;
+ friend class Object;
+
+ template <typename T, typename... U> void create(U &&... V) {
+ new (reinterpret_cast<T *>(&Union)) T(std::forward<U>(V)...);
+ }
+ template <typename T> T &as() const {
+ // Using this two-step static_cast via void * instead of reinterpret_cast
+ // silences a -Wstrict-aliasing false positive from GCC6 and earlier.
+ void *Storage = static_cast<void *>(&Union);
+ return *static_cast<T *>(Storage);
+ }
+
+ friend class OStream;
+
+ enum ValueType : char16_t {
+ T_Null,
+ T_Boolean,
+ T_Double,
+ T_Integer,
+ T_UINT64,
+ T_StringRef,
+ T_String,
+ T_Object,
+ T_Array,
+ };
+ // All members mutable, see moveFrom().
+ mutable ValueType Type;
+ mutable llvm::AlignedCharArrayUnion<bool, double, int64_t, uint64_t,
+ llvm::StringRef, std::string, json::Array,
+ json::Object>
+ Union;
+ friend bool operator==(const Value &, const Value &);
+};
+
+bool operator==(const Value &, const Value &);
+inline bool operator!=(const Value &L, const Value &R) { return !(L == R); }
+
+// Array Methods
+inline Value &Array::operator[](size_t I) { return V[I]; }
+inline const Value &Array::operator[](size_t I) const { return V[I]; }
+inline Value &Array::front() { return V.front(); }
+inline const Value &Array::front() const { return V.front(); }
+inline Value &Array::back() { return V.back(); }
+inline const Value &Array::back() const { return V.back(); }
+inline Value *Array::data() { return V.data(); }
+inline const Value *Array::data() const { return V.data(); }
+
+inline typename Array::iterator Array::begin() { return V.begin(); }
+inline typename Array::const_iterator Array::begin() const { return V.begin(); }
+inline typename Array::iterator Array::end() { return V.end(); }
+inline typename Array::const_iterator Array::end() const { return V.end(); }
+
+inline bool Array::empty() const { return V.empty(); }
+inline size_t Array::size() const { return V.size(); }
+inline void Array::reserve(size_t S) { V.reserve(S); }
+
+inline void Array::clear() { V.clear(); }
+inline void Array::push_back(const Value &E) { V.push_back(E); }
+inline void Array::push_back(Value &&E) { V.push_back(std::move(E)); }
+template <typename... Args> inline void Array::emplace_back(Args &&...A) {
+ V.emplace_back(std::forward<Args>(A)...);
+}
+inline void Array::pop_back() { V.pop_back(); }
+inline typename Array::iterator Array::insert(const_iterator P, const Value &E) {
+ return V.insert(P, E);
+}
+inline typename Array::iterator Array::insert(const_iterator P, Value &&E) {
+ return V.insert(P, std::move(E));
+}
+template <typename It>
+inline typename Array::iterator Array::insert(const_iterator P, It A, It Z) {
+ return V.insert(P, A, Z);
+}
+template <typename... Args>
+inline typename Array::iterator Array::emplace(const_iterator P, Args &&...A) {
+ return V.emplace(P, std::forward<Args>(A)...);
+}
+inline bool operator==(const Array &L, const Array &R) { return L.V == R.V; }
+
+/// ObjectKey is a used to capture keys in Object. Like Value but:
+/// - only strings are allowed
+/// - it's optimized for the string literal case (Owned == nullptr)
+/// Like Value, strings must be UTF-8. See isUTF8 documentation for details.
+class ObjectKey {
+public:
+ ObjectKey(const char *S) : ObjectKey(StringRef(S)) {}
+ ObjectKey(std::string S) : Owned(new std::string(std::move(S))) {
+ if (LLVM_UNLIKELY(!isUTF8(*Owned))) {
+ assert(false && "Invalid UTF-8 in value used as JSON");
+ *Owned = fixUTF8(std::move(*Owned));
+ }
+ Data = *Owned;
+ }
+ ObjectKey(llvm::StringRef S) : Data(S) {
+ if (LLVM_UNLIKELY(!isUTF8(Data))) {
+ assert(false && "Invalid UTF-8 in value used as JSON");
+ *this = ObjectKey(fixUTF8(S));
+ }
+ }
+ ObjectKey(const llvm::SmallVectorImpl<char> &V)
+ : ObjectKey(std::string(V.begin(), V.end())) {}
+ ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {}
+
+ ObjectKey(const ObjectKey &C) { *this = C; }
+ ObjectKey(ObjectKey &&C) : ObjectKey(static_cast<const ObjectKey &&>(C)) {}
+ ObjectKey &operator=(const ObjectKey &C) {
+ if (C.Owned) {
+ Owned.reset(new std::string(*C.Owned));
+ Data = *Owned;
+ } else {
+ Data = C.Data;
+ }
+ return *this;
+ }
+ ObjectKey &operator=(ObjectKey &&) = default;
+
+ operator llvm::StringRef() const { return Data; }
+ std::string str() const { return Data.str(); }
+
+private:
+ // FIXME: this is unneccesarily large (3 pointers). Pointer + length + owned
+ // could be 2 pointers at most.
+ std::unique_ptr<std::string> Owned;
+ llvm::StringRef Data;
+};
+
+inline bool operator==(const ObjectKey &L, const ObjectKey &R) {
+ return llvm::StringRef(L) == llvm::StringRef(R);
+}
+inline bool operator!=(const ObjectKey &L, const ObjectKey &R) {
+ return !(L == R);
+}
+inline bool operator<(const ObjectKey &L, const ObjectKey &R) {
+ return StringRef(L) < StringRef(R);
+}
+
+struct Object::KV {
+ ObjectKey K;
+ Value V;
+};
+
+inline Object::Object(std::initializer_list<KV> Properties) {
+ for (const auto &P : Properties) {
+ auto R = try_emplace(P.K, nullptr);
+ if (R.second)
+ R.first->getSecond().moveFrom(std::move(P.V));
+ }
+}
+inline std::pair<Object::iterator, bool> Object::insert(KV E) {
+ return try_emplace(std::move(E.K), std::move(E.V));
+}
+inline bool Object::erase(StringRef K) {
+ return M.erase(ObjectKey(K));
+}
+
+/// A "cursor" marking a position within a Value.
+/// The Value is a tree, and this is the path from the root to the current node.
+/// This is used to associate errors with particular subobjects.
+class Path {
+public:
+ class Root;
+
+ /// Records that the value at the current path is invalid.
+ /// Message is e.g. "expected number" and becomes part of the final error.
+ /// This overwrites any previously written error message in the root.
+ void report(llvm::StringLiteral Message);
+
+ /// The root may be treated as a Path.
+ Path(Root &R) : Parent(nullptr), Seg(&R) {}
+ /// Derives a path for an array element: this[Index]
+ Path index(unsigned Index) const { return Path(this, Segment(Index)); }
+ /// Derives a path for an object field: this.Field
+ Path field(StringRef Field) const { return Path(this, Segment(Field)); }
+
+private:
+ /// One element in a JSON path: an object field (.foo) or array index [27].
+ /// Exception: the root Path encodes a pointer to the Path::Root.
+ class Segment {
+ uintptr_t Pointer;
+ unsigned Offset;
+
+ public:
+ Segment() = default;
+ Segment(Root *R) : Pointer(reinterpret_cast<uintptr_t>(R)) {}
+ Segment(llvm::StringRef Field)
+ : Pointer(reinterpret_cast<uintptr_t>(Field.data())),
+ Offset(static_cast<unsigned>(Field.size())) {}
+ Segment(unsigned Index) : Pointer(0), Offset(Index) {}
+
+ bool isField() const { return Pointer != 0; }
+ StringRef field() const {
+ return StringRef(reinterpret_cast<const char *>(Pointer), Offset);
+ }
+ unsigned index() const { return Offset; }
+ Root *root() const { return reinterpret_cast<Root *>(Pointer); }
+ };
+
+ const Path *Parent;
+ Segment Seg;
+
+ Path(const Path *Parent, Segment S) : Parent(Parent), Seg(S) {}
+};
+
+/// The root is the trivial Path to the root value.
+/// It also stores the latest reported error and the path where it occurred.
+class Path::Root {
+ llvm::StringRef Name;
+ llvm::StringLiteral ErrorMessage;
+ std::vector<Path::Segment> ErrorPath; // Only valid in error state. Reversed.
+
+ friend void Path::report(llvm::StringLiteral Message);
+
+public:
+ Root(llvm::StringRef Name = "") : Name(Name), ErrorMessage("") {}
+ // No copy/move allowed as there are incoming pointers.
+ Root(Root &&) = delete;
+ Root &operator=(Root &&) = delete;
+ Root(const Root &) = delete;
+ Root &operator=(const Root &) = delete;
+
+ /// Returns the last error reported, or else a generic error.
+ Error getError() const;
+ /// Print the root value with the error shown inline as a comment.
+ /// Unrelated parts of the value are elided for brevity, e.g.
+ /// {
+ /// "id": 42,
+ /// "name": /* expected string */ null,
+ /// "properties": { ... }
+ /// }
+ void printErrorContext(const Value &, llvm::raw_ostream &) const;
+};
+
+// Standard deserializers are provided for primitive types.
+// See comments on Value.
+inline bool fromJSON(const Value &E, std::string &Out, Path P) {
+ if (auto S = E.getAsString()) {
+ Out = std::string(*S);
+ return true;
+ }
+ P.report("expected string");
+ return false;
+}
+inline bool fromJSON(const Value &E, int &Out, Path P) {
+ if (auto S = E.getAsInteger()) {
+ Out = *S;
+ return true;
+ }
+ P.report("expected integer");
+ return false;
+}
+inline bool fromJSON(const Value &E, int64_t &Out, Path P) {
+ if (auto S = E.getAsInteger()) {
+ Out = *S;
+ return true;
+ }
+ P.report("expected integer");
+ return false;
+}
+inline bool fromJSON(const Value &E, double &Out, Path P) {
+ if (auto S = E.getAsNumber()) {
+ Out = *S;
+ return true;
+ }
+ P.report("expected number");
+ return false;
+}
+inline bool fromJSON(const Value &E, bool &Out, Path P) {
+ if (auto S = E.getAsBoolean()) {
+ Out = *S;
+ return true;
+ }
+ P.report("expected boolean");
+ return false;
+}
+inline bool fromJSON(const Value &E, uint64_t &Out, Path P) {
+ if (auto S = E.getAsUINT64()) {
+ Out = *S;
+ return true;
+ }
+ P.report("expected uint64_t");
+ return false;
+}
+inline bool fromJSON(const Value &E, std::nullptr_t &Out, Path P) {
+ if (auto S = E.getAsNull()) {
+ Out = *S;
+ return true;
+ }
+ P.report("expected null");
+ return false;
+}
+template <typename T>
+bool fromJSON(const Value &E, std::optional<T> &Out, Path P) {
+ if (E.getAsNull()) {
+ Out = std::nullopt;
+ return true;
+ }
+ T Result;
+ if (!fromJSON(E, Result, P))
+ return false;
+ Out = std::move(Result);
+ return true;
+}
+template <typename T>
+bool fromJSON(const Value &E, std::vector<T> &Out, Path P) {
+ if (auto *A = E.getAsArray()) {
+ Out.clear();
+ Out.resize(A->size());
+ for (size_t I = 0; I < A->size(); ++I)
+ if (!fromJSON((*A)[I], Out[I], P.index(I)))
+ return false;
+ return true;
+ }
+ P.report("expected array");
+ return false;
+}
+template <typename T>
+bool fromJSON(const Value &E, std::map<std::string, T> &Out, Path P) {
+ if (auto *O = E.getAsObject()) {
+ Out.clear();
+ for (const auto &KV : *O)
+ if (!fromJSON(KV.second, Out[std::string(llvm::StringRef(KV.first))],
+ P.field(KV.first)))
+ return false;
+ return true;
+ }
+ P.report("expected object");
+ return false;
+}
+
+// Allow serialization of std::optional<T> for supported T.
+template <typename T> Value toJSON(const std::optional<T> &Opt) {
+ return Opt ? Value(*Opt) : Value(nullptr);
+}
+
+/// Helper for mapping JSON objects onto protocol structs.
+///
+/// Example:
+/// \code
+/// bool fromJSON(const Value &E, MyStruct &R, Path P) {
+/// ObjectMapper O(E, P);
+/// // When returning false, error details were already reported.
+/// return O && O.map("mandatory_field", R.MandatoryField) &&
+/// O.mapOptional("optional_field", R.OptionalField);
+/// }
+/// \endcode
+class ObjectMapper {
+public:
+ /// If O is not an object, this mapper is invalid and an error is reported.
+ ObjectMapper(const Value &E, Path P) : O(E.getAsObject()), P(P) {
+ if (!O)
+ P.report("expected object");
+ }
+
+ /// True if the expression is an object.
+ /// Must be checked before calling map().
+ operator bool() const { return O; }
+
+ /// Maps a property to a field.
+ /// If the property is missing or invalid, reports an error.
+ template <typename T> bool map(StringLiteral Prop, T &Out) {
+ assert(*this && "Must check this is an object before calling map()");
+ if (const Value *E = O->get(Prop))
+ return fromJSON(*E, Out, P.field(Prop));
+ P.field(Prop).report("missing value");
+ return false;
+ }
+
+ /// Maps a property to a field, if it exists.
+ /// If the property exists and is invalid, reports an error.
+ /// (Optional requires special handling, because missing keys are OK).
+ template <typename T> bool map(StringLiteral Prop, std::optional<T> &Out) {
+ assert(*this && "Must check this is an object before calling map()");
+ if (const Value *E = O->get(Prop))
+ return fromJSON(*E, Out, P.field(Prop));
+ Out = std::nullopt;
+ return true;
+ }
+
+ /// Maps a property to a field, if it exists.
+ /// If the property exists and is invalid, reports an error.
+ /// If the property does not exist, Out is unchanged.
+ template <typename T> bool mapOptional(StringLiteral Prop, T &Out) {
+ assert(*this && "Must check this is an object before calling map()");
+ if (const Value *E = O->get(Prop))
+ return fromJSON(*E, Out, P.field(Prop));
+ return true;
+ }
+
+private:
+ const Object *O;
+ Path P;
+};
+
+/// Parses the provided JSON source, or returns a ParseError.
+/// The returned Value is self-contained and owns its strings (they do not refer
+/// to the original source).
+llvm::Expected<Value> parse(llvm::StringRef JSON);
+
+class ParseError : public llvm::ErrorInfo<ParseError> {
+ const char *Msg;
+ unsigned Line, Column, Offset;
+
+public:
+ static char ID;
+ ParseError(const char *Msg, unsigned Line, unsigned Column, unsigned Offset)
+ : Msg(Msg), Line(Line), Column(Column), Offset(Offset) {}
+ void log(llvm::raw_ostream &OS) const override {
+ OS << llvm::formatv("[{0}:{1}, byte={2}]: {3}", Line, Column, Offset, Msg);
+ }
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+};
+
+/// Version of parse() that converts the parsed value to the type T.
+/// RootName describes the root object and is used in error messages.
+template <typename T>
+Expected<T> parse(const llvm::StringRef &JSON, const char *RootName = "") {
+ auto V = parse(JSON);
+ if (!V)
+ return V.takeError();
+ Path::Root R(RootName);
+ T Result;
+ if (fromJSON(*V, Result, R))
+ return std::move(Result);
+ return R.getError();
+}
+
+/// json::OStream allows writing well-formed JSON without materializing
+/// all structures as json::Value ahead of time.
+/// It's faster, lower-level, and less safe than OS << json::Value.
+/// It also allows emitting more constructs, such as comments.
+///
+/// Only one "top-level" object can be written to a stream.
+/// Simplest usage involves passing lambdas (Blocks) to fill in containers:
+///
+/// json::OStream J(OS);
+/// J.array([&]{
+/// for (const Event &E : Events)
+/// J.object([&] {
+/// J.attribute("timestamp", int64_t(E.Time));
+/// J.attributeArray("participants", [&] {
+/// for (const Participant &P : E.Participants)
+/// J.value(P.toString());
+/// });
+/// });
+/// });
+///
+/// This would produce JSON like:
+///
+/// [
+/// {
+/// "timestamp": 19287398741,
+/// "participants": [
+/// "King Kong",
+/// "Miley Cyrus",
+/// "Cleopatra"
+/// ]
+/// },
+/// ...
+/// ]
+///
+/// The lower level begin/end methods (arrayBegin()) are more flexible but
+/// care must be taken to pair them correctly:
+///
+/// json::OStream J(OS);
+// J.arrayBegin();
+/// for (const Event &E : Events) {
+/// J.objectBegin();
+/// J.attribute("timestamp", int64_t(E.Time));
+/// J.attributeBegin("participants");
+/// for (const Participant &P : E.Participants)
+/// J.value(P.toString());
+/// J.attributeEnd();
+/// J.objectEnd();
+/// }
+/// J.arrayEnd();
+///
+/// If the call sequence isn't valid JSON, asserts will fire in debug mode.
+/// This can be mismatched begin()/end() pairs, trying to emit attributes inside
+/// an array, and so on.
+/// With asserts disabled, this is undefined behavior.
+class OStream {
+ public:
+ using Block = llvm::function_ref<void()>;
+ // If IndentSize is nonzero, output is pretty-printed.
+ explicit OStream(llvm::raw_ostream &OS, unsigned IndentSize = 0)
+ : OS(OS), IndentSize(IndentSize) {
+ Stack.emplace_back();
+ }
+ ~OStream() {
+ assert(Stack.size() == 1 && "Unmatched begin()/end()");
+ assert(Stack.back().Ctx == Singleton);
+ assert(Stack.back().HasValue && "Did not write top-level value");
+ }
+
+ /// Flushes the underlying ostream. OStream does not buffer internally.
+ void flush() { OS.flush(); }
+
+ // High level functions to output a value.
+ // Valid at top-level (exactly once), in an attribute value (exactly once),
+ // or in an array (any number of times).
+
+ /// Emit a self-contained value (number, string, vector<string> etc).
+ void value(const Value &V);
+ /// Emit an array whose elements are emitted in the provided Block.
+ void array(Block Contents) {
+ arrayBegin();
+ Contents();
+ arrayEnd();
+ }
+ /// Emit an object whose elements are emitted in the provided Block.
+ void object(Block Contents) {
+ objectBegin();
+ Contents();
+ objectEnd();
+ }
+ /// Emit an externally-serialized value.
+ /// The caller must write exactly one valid JSON value to the provided stream.
+ /// No validation or formatting of this value occurs.
+ void rawValue(llvm::function_ref<void(raw_ostream &)> Contents) {
+ rawValueBegin();
+ Contents(OS);
+ rawValueEnd();
+ }
+ void rawValue(llvm::StringRef Contents) {
+ rawValue([&](raw_ostream &OS) { OS << Contents; });
+ }
+ /// Emit a JavaScript comment associated with the next printed value.
+ /// The string must be valid until the next attribute or value is emitted.
+ /// Comments are not part of standard JSON, and many parsers reject them!
+ void comment(llvm::StringRef);
+
+ // High level functions to output object attributes.
+ // Valid only within an object (any number of times).
+
+ /// Emit an attribute whose value is self-contained (number, vector<int> etc).
+ void attribute(llvm::StringRef Key, const Value& Contents) {
+ attributeImpl(Key, [&] { value(Contents); });
+ }
+ /// Emit an attribute whose value is an array with elements from the Block.
+ void attributeArray(llvm::StringRef Key, Block Contents) {
+ attributeImpl(Key, [&] { array(Contents); });
+ }
+ /// Emit an attribute whose value is an object with attributes from the Block.
+ void attributeObject(llvm::StringRef Key, Block Contents) {
+ attributeImpl(Key, [&] { object(Contents); });
+ }
+
+ // Low-level begin/end functions to output arrays, objects, and attributes.
+ // Must be correctly paired. Allowed contexts are as above.
+
+ void arrayBegin();
+ void arrayEnd();
+ void objectBegin();
+ void objectEnd();
+ void attributeBegin(llvm::StringRef Key);
+ void attributeEnd();
+ raw_ostream &rawValueBegin();
+ void rawValueEnd();
+
+private:
+ void attributeImpl(llvm::StringRef Key, Block Contents) {
+ attributeBegin(Key);
+ Contents();
+ attributeEnd();
+ }
+
+ void valueBegin();
+ void flushComment();
+ void newline();
+
+ enum Context {
+ Singleton, // Top level, or object attribute.
+ Array,
+ Object,
+ RawValue, // External code writing a value to OS directly.
+ };
+ struct State {
+ Context Ctx = Singleton;
+ bool HasValue = false;
+ };
+ llvm::SmallVector<State, 16> Stack; // Never empty.
+ llvm::StringRef PendingComment;
+ llvm::raw_ostream &OS;
+ unsigned IndentSize;
+ unsigned Indent = 0;
+};
+
+/// Serializes this Value to JSON, writing it to the provided stream.
+/// The formatting is compact (no extra whitespace) and deterministic.
+/// For pretty-printing, use the formatv() format_provider below.
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Value &V) {
+ OStream(OS).value(V);
+ return OS;
+}
+} // namespace json
+
+/// Allow printing json::Value with formatv().
+/// The default style is basic/compact formatting, like operator<<.
+/// A format string like formatv("{0:2}", Value) pretty-prints with indent 2.
+template <> struct format_provider<llvm::json::Value> {
+ static void format(const llvm::json::Value &, raw_ostream &, StringRef);
+};
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/KnownBits.h b/contrib/libs/llvm16/include/llvm/Support/KnownBits.h
new file mode 100644
index 00000000000..81a5113a812
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/KnownBits.h
@@ -0,0 +1,478 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/KnownBits.h - Stores known zeros/ones -------*- 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 a class for representing known zeros and ones used by
+// computeKnownBits.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_KNOWNBITS_H
+#define LLVM_SUPPORT_KNOWNBITS_H
+
+#include "llvm/ADT/APInt.h"
+#include <optional>
+
+namespace llvm {
+
+// Struct for tracking the known zeros and ones of a value.
+struct KnownBits {
+ APInt Zero;
+ APInt One;
+
+private:
+ // Internal constructor for creating a KnownBits from two APInts.
+ KnownBits(APInt Zero, APInt One)
+ : Zero(std::move(Zero)), One(std::move(One)) {}
+
+public:
+ // Default construct Zero and One.
+ KnownBits() = default;
+
+ /// Create a known bits object of BitWidth bits initialized to unknown.
+ KnownBits(unsigned BitWidth) : Zero(BitWidth, 0), One(BitWidth, 0) {}
+
+ /// Get the bit width of this value.
+ unsigned getBitWidth() const {
+ assert(Zero.getBitWidth() == One.getBitWidth() &&
+ "Zero and One should have the same width!");
+ return Zero.getBitWidth();
+ }
+
+ /// Returns true if there is conflicting information.
+ bool hasConflict() const { return Zero.intersects(One); }
+
+ /// Returns true if we know the value of all bits.
+ bool isConstant() const {
+ assert(!hasConflict() && "KnownBits conflict!");
+ return Zero.countPopulation() + One.countPopulation() == getBitWidth();
+ }
+
+ /// Returns the value when all bits have a known value. This just returns One
+ /// with a protective assertion.
+ const APInt &getConstant() const {
+ assert(isConstant() && "Can only get value when all bits are known");
+ return One;
+ }
+
+ /// Returns true if we don't know any bits.
+ bool isUnknown() const { return Zero.isZero() && One.isZero(); }
+
+ /// Resets the known state of all bits.
+ void resetAll() {
+ Zero.clearAllBits();
+ One.clearAllBits();
+ }
+
+ /// Returns true if value is all zero.
+ bool isZero() const {
+ assert(!hasConflict() && "KnownBits conflict!");
+ return Zero.isAllOnes();
+ }
+
+ /// Returns true if value is all one bits.
+ bool isAllOnes() const {
+ assert(!hasConflict() && "KnownBits conflict!");
+ return One.isAllOnes();
+ }
+
+ /// Make all bits known to be zero and discard any previous information.
+ void setAllZero() {
+ Zero.setAllBits();
+ One.clearAllBits();
+ }
+
+ /// Make all bits known to be one and discard any previous information.
+ void setAllOnes() {
+ Zero.clearAllBits();
+ One.setAllBits();
+ }
+
+ /// Returns true if this value is known to be negative.
+ bool isNegative() const { return One.isSignBitSet(); }
+
+ /// Returns true if this value is known to be non-negative.
+ bool isNonNegative() const { return Zero.isSignBitSet(); }
+
+ /// Returns true if this value is known to be non-zero.
+ bool isNonZero() const { return !One.isZero(); }
+
+ /// Returns true if this value is known to be positive.
+ bool isStrictlyPositive() const {
+ return Zero.isSignBitSet() && !One.isZero();
+ }
+
+ /// Make this value negative.
+ void makeNegative() {
+ One.setSignBit();
+ }
+
+ /// Make this value non-negative.
+ void makeNonNegative() {
+ Zero.setSignBit();
+ }
+
+ /// Return the minimal unsigned value possible given these KnownBits.
+ APInt getMinValue() const {
+ // Assume that all bits that aren't known-ones are zeros.
+ return One;
+ }
+
+ /// Return the minimal signed value possible given these KnownBits.
+ APInt getSignedMinValue() const {
+ // Assume that all bits that aren't known-ones are zeros.
+ APInt Min = One;
+ // Sign bit is unknown.
+ if (Zero.isSignBitClear())
+ Min.setSignBit();
+ return Min;
+ }
+
+ /// Return the maximal unsigned value possible given these KnownBits.
+ APInt getMaxValue() const {
+ // Assume that all bits that aren't known-zeros are ones.
+ return ~Zero;
+ }
+
+ /// Return the maximal signed value possible given these KnownBits.
+ APInt getSignedMaxValue() const {
+ // Assume that all bits that aren't known-zeros are ones.
+ APInt Max = ~Zero;
+ // Sign bit is unknown.
+ if (One.isSignBitClear())
+ Max.clearSignBit();
+ return Max;
+ }
+
+ /// Return known bits for a truncation of the value we're tracking.
+ KnownBits trunc(unsigned BitWidth) const {
+ return KnownBits(Zero.trunc(BitWidth), One.trunc(BitWidth));
+ }
+
+ /// Return known bits for an "any" extension of the value we're tracking,
+ /// where we don't know anything about the extended bits.
+ KnownBits anyext(unsigned BitWidth) const {
+ return KnownBits(Zero.zext(BitWidth), One.zext(BitWidth));
+ }
+
+ /// Return known bits for a zero extension of the value we're tracking.
+ KnownBits zext(unsigned BitWidth) const {
+ unsigned OldBitWidth = getBitWidth();
+ APInt NewZero = Zero.zext(BitWidth);
+ NewZero.setBitsFrom(OldBitWidth);
+ return KnownBits(NewZero, One.zext(BitWidth));
+ }
+
+ /// Return known bits for a sign extension of the value we're tracking.
+ KnownBits sext(unsigned BitWidth) const {
+ return KnownBits(Zero.sext(BitWidth), One.sext(BitWidth));
+ }
+
+ /// Return known bits for an "any" extension or truncation of the value we're
+ /// tracking.
+ KnownBits anyextOrTrunc(unsigned BitWidth) const {
+ if (BitWidth > getBitWidth())
+ return anyext(BitWidth);
+ if (BitWidth < getBitWidth())
+ return trunc(BitWidth);
+ return *this;
+ }
+
+ /// Return known bits for a zero extension or truncation of the value we're
+ /// tracking.
+ KnownBits zextOrTrunc(unsigned BitWidth) const {
+ if (BitWidth > getBitWidth())
+ return zext(BitWidth);
+ if (BitWidth < getBitWidth())
+ return trunc(BitWidth);
+ return *this;
+ }
+
+ /// Return known bits for a sign extension or truncation of the value we're
+ /// tracking.
+ KnownBits sextOrTrunc(unsigned BitWidth) const {
+ if (BitWidth > getBitWidth())
+ return sext(BitWidth);
+ if (BitWidth < getBitWidth())
+ return trunc(BitWidth);
+ return *this;
+ }
+
+ /// Return known bits for a in-register sign extension of the value we're
+ /// tracking.
+ KnownBits sextInReg(unsigned SrcBitWidth) const;
+
+ /// Insert the bits from a smaller known bits starting at bitPosition.
+ void insertBits(const KnownBits &SubBits, unsigned BitPosition) {
+ Zero.insertBits(SubBits.Zero, BitPosition);
+ One.insertBits(SubBits.One, BitPosition);
+ }
+
+ /// Return a subset of the known bits from [bitPosition,bitPosition+numBits).
+ KnownBits extractBits(unsigned NumBits, unsigned BitPosition) const {
+ return KnownBits(Zero.extractBits(NumBits, BitPosition),
+ One.extractBits(NumBits, BitPosition));
+ }
+
+ /// Concatenate the bits from \p Lo onto the bottom of *this. This is
+ /// equivalent to:
+ /// (this->zext(NewWidth) << Lo.getBitWidth()) | Lo.zext(NewWidth)
+ KnownBits concat(const KnownBits &Lo) const {
+ return KnownBits(Zero.concat(Lo.Zero), One.concat(Lo.One));
+ }
+
+ /// Return KnownBits based on this, but updated given that the underlying
+ /// value is known to be greater than or equal to Val.
+ KnownBits makeGE(const APInt &Val) const;
+
+ /// Returns the minimum number of trailing zero bits.
+ unsigned countMinTrailingZeros() const {
+ return Zero.countTrailingOnes();
+ }
+
+ /// Returns the minimum number of trailing one bits.
+ unsigned countMinTrailingOnes() const {
+ return One.countTrailingOnes();
+ }
+
+ /// Returns the minimum number of leading zero bits.
+ unsigned countMinLeadingZeros() const {
+ return Zero.countLeadingOnes();
+ }
+
+ /// Returns the minimum number of leading one bits.
+ unsigned countMinLeadingOnes() const {
+ return One.countLeadingOnes();
+ }
+
+ /// Returns the number of times the sign bit is replicated into the other
+ /// bits.
+ unsigned countMinSignBits() const {
+ if (isNonNegative())
+ return countMinLeadingZeros();
+ if (isNegative())
+ return countMinLeadingOnes();
+ // Every value has at least 1 sign bit.
+ return 1;
+ }
+
+ /// Returns the maximum number of bits needed to represent all possible
+ /// signed values with these known bits. This is the inverse of the minimum
+ /// number of known sign bits. Examples for bitwidth 5:
+ /// 110?? --> 4
+ /// 0000? --> 2
+ unsigned countMaxSignificantBits() const {
+ return getBitWidth() - countMinSignBits() + 1;
+ }
+
+ /// Returns the maximum number of trailing zero bits possible.
+ unsigned countMaxTrailingZeros() const {
+ return One.countTrailingZeros();
+ }
+
+ /// Returns the maximum number of trailing one bits possible.
+ unsigned countMaxTrailingOnes() const {
+ return Zero.countTrailingZeros();
+ }
+
+ /// Returns the maximum number of leading zero bits possible.
+ unsigned countMaxLeadingZeros() const {
+ return One.countLeadingZeros();
+ }
+
+ /// Returns the maximum number of leading one bits possible.
+ unsigned countMaxLeadingOnes() const {
+ return Zero.countLeadingZeros();
+ }
+
+ /// Returns the number of bits known to be one.
+ unsigned countMinPopulation() const {
+ return One.countPopulation();
+ }
+
+ /// Returns the maximum number of bits that could be one.
+ unsigned countMaxPopulation() const {
+ return getBitWidth() - Zero.countPopulation();
+ }
+
+ /// Returns the maximum number of bits needed to represent all possible
+ /// unsigned values with these known bits. This is the inverse of the
+ /// minimum number of leading zeros.
+ unsigned countMaxActiveBits() const {
+ return getBitWidth() - countMinLeadingZeros();
+ }
+
+ /// Create known bits from a known constant.
+ static KnownBits makeConstant(const APInt &C) {
+ return KnownBits(~C, C);
+ }
+
+ /// Compute known bits common to LHS and RHS.
+ static KnownBits commonBits(const KnownBits &LHS, const KnownBits &RHS) {
+ return KnownBits(LHS.Zero & RHS.Zero, LHS.One & RHS.One);
+ }
+
+ /// Return true if LHS and RHS have no common bits set.
+ static bool haveNoCommonBitsSet(const KnownBits &LHS, const KnownBits &RHS) {
+ return (LHS.Zero | RHS.Zero).isAllOnes();
+ }
+
+ /// Compute known bits resulting from adding LHS, RHS and a 1-bit Carry.
+ static KnownBits computeForAddCarry(
+ const KnownBits &LHS, const KnownBits &RHS, const KnownBits &Carry);
+
+ /// Compute known bits resulting from adding LHS and RHS.
+ static KnownBits computeForAddSub(bool Add, bool NSW, const KnownBits &LHS,
+ KnownBits RHS);
+
+ /// Compute known bits resulting from multiplying LHS and RHS.
+ static KnownBits mul(const KnownBits &LHS, const KnownBits &RHS,
+ bool NoUndefSelfMultiply = false);
+
+ /// Compute known bits from sign-extended multiply-hi.
+ static KnownBits mulhs(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits from zero-extended multiply-hi.
+ static KnownBits mulhu(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for udiv(LHS, RHS).
+ static KnownBits udiv(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for urem(LHS, RHS).
+ static KnownBits urem(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for srem(LHS, RHS).
+ static KnownBits srem(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for umax(LHS, RHS).
+ static KnownBits umax(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for umin(LHS, RHS).
+ static KnownBits umin(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for smax(LHS, RHS).
+ static KnownBits smax(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for smin(LHS, RHS).
+ static KnownBits smin(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for shl(LHS, RHS).
+ /// NOTE: RHS (shift amount) bitwidth doesn't need to be the same as LHS.
+ static KnownBits shl(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for lshr(LHS, RHS).
+ /// NOTE: RHS (shift amount) bitwidth doesn't need to be the same as LHS.
+ static KnownBits lshr(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Compute known bits for ashr(LHS, RHS).
+ /// NOTE: RHS (shift amount) bitwidth doesn't need to be the same as LHS.
+ static KnownBits ashr(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_EQ result.
+ static std::optional<bool> eq(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_NE result.
+ static std::optional<bool> ne(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_UGT result.
+ static std::optional<bool> ugt(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_UGE result.
+ static std::optional<bool> uge(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_ULT result.
+ static std::optional<bool> ult(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_ULE result.
+ static std::optional<bool> ule(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_SGT result.
+ static std::optional<bool> sgt(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_SGE result.
+ static std::optional<bool> sge(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_SLT result.
+ static std::optional<bool> slt(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Determine if these known bits always give the same ICMP_SLE result.
+ static std::optional<bool> sle(const KnownBits &LHS, const KnownBits &RHS);
+
+ /// Update known bits based on ANDing with RHS.
+ KnownBits &operator&=(const KnownBits &RHS);
+
+ /// Update known bits based on ORing with RHS.
+ KnownBits &operator|=(const KnownBits &RHS);
+
+ /// Update known bits based on XORing with RHS.
+ KnownBits &operator^=(const KnownBits &RHS);
+
+ /// Compute known bits for the absolute value.
+ KnownBits abs(bool IntMinIsPoison = false) const;
+
+ KnownBits byteSwap() const {
+ return KnownBits(Zero.byteSwap(), One.byteSwap());
+ }
+
+ KnownBits reverseBits() const {
+ return KnownBits(Zero.reverseBits(), One.reverseBits());
+ }
+
+ bool operator==(const KnownBits &Other) const {
+ return Zero == Other.Zero && One == Other.One;
+ }
+
+ bool operator!=(const KnownBits &Other) const { return !(*this == Other); }
+
+ void print(raw_ostream &OS) const;
+ void dump() const;
+};
+
+inline KnownBits operator&(KnownBits LHS, const KnownBits &RHS) {
+ LHS &= RHS;
+ return LHS;
+}
+
+inline KnownBits operator&(const KnownBits &LHS, KnownBits &&RHS) {
+ RHS &= LHS;
+ return std::move(RHS);
+}
+
+inline KnownBits operator|(KnownBits LHS, const KnownBits &RHS) {
+ LHS |= RHS;
+ return LHS;
+}
+
+inline KnownBits operator|(const KnownBits &LHS, KnownBits &&RHS) {
+ RHS |= LHS;
+ return std::move(RHS);
+}
+
+inline KnownBits operator^(KnownBits LHS, const KnownBits &RHS) {
+ LHS ^= RHS;
+ return LHS;
+}
+
+inline KnownBits operator^(const KnownBits &LHS, KnownBits &&RHS) {
+ RHS ^= LHS;
+ return std::move(RHS);
+}
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/LEB128.h b/contrib/libs/llvm16/include/llvm/Support/LEB128.h
new file mode 100644
index 00000000000..df428226bed
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/LEB128.h
@@ -0,0 +1,219 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/LEB128.h - [SU]LEB128 utility functions -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares some utility functions for encoding SLEB128 and
+// ULEB128 values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_LEB128_H
+#define LLVM_SUPPORT_LEB128_H
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+/// Utility function to encode a SLEB128 value to an output stream. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeSLEB128(int64_t Value, raw_ostream &OS,
+ unsigned PadTo = 0) {
+ bool More;
+ unsigned Count = 0;
+ do {
+ uint8_t Byte = Value & 0x7f;
+ // NOTE: this assumes that this signed shift is an arithmetic right shift.
+ Value >>= 7;
+ More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
+ ((Value == -1) && ((Byte & 0x40) != 0))));
+ Count++;
+ if (More || Count < PadTo)
+ Byte |= 0x80; // Mark this byte to show that more bytes will follow.
+ OS << char(Byte);
+ } while (More);
+
+ // Pad with 0x80 and emit a terminating byte at the end.
+ if (Count < PadTo) {
+ uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
+ for (; Count < PadTo - 1; ++Count)
+ OS << char(PadValue | 0x80);
+ OS << char(PadValue);
+ Count++;
+ }
+ return Count;
+}
+
+/// Utility function to encode a SLEB128 value to a buffer. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeSLEB128(int64_t Value, uint8_t *p, unsigned PadTo = 0) {
+ uint8_t *orig_p = p;
+ unsigned Count = 0;
+ bool More;
+ do {
+ uint8_t Byte = Value & 0x7f;
+ // NOTE: this assumes that this signed shift is an arithmetic right shift.
+ Value >>= 7;
+ More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) ||
+ ((Value == -1) && ((Byte & 0x40) != 0))));
+ Count++;
+ if (More || Count < PadTo)
+ Byte |= 0x80; // Mark this byte to show that more bytes will follow.
+ *p++ = Byte;
+ } while (More);
+
+ // Pad with 0x80 and emit a terminating byte at the end.
+ if (Count < PadTo) {
+ uint8_t PadValue = Value < 0 ? 0x7f : 0x00;
+ for (; Count < PadTo - 1; ++Count)
+ *p++ = (PadValue | 0x80);
+ *p++ = PadValue;
+ }
+ return (unsigned)(p - orig_p);
+}
+
+/// Utility function to encode a ULEB128 value to an output stream. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeULEB128(uint64_t Value, raw_ostream &OS,
+ unsigned PadTo = 0) {
+ unsigned Count = 0;
+ do {
+ uint8_t Byte = Value & 0x7f;
+ Value >>= 7;
+ Count++;
+ if (Value != 0 || Count < PadTo)
+ Byte |= 0x80; // Mark this byte to show that more bytes will follow.
+ OS << char(Byte);
+ } while (Value != 0);
+
+ // Pad with 0x80 and emit a null byte at the end.
+ if (Count < PadTo) {
+ for (; Count < PadTo - 1; ++Count)
+ OS << '\x80';
+ OS << '\x00';
+ Count++;
+ }
+ return Count;
+}
+
+/// Utility function to encode a ULEB128 value to a buffer. Returns
+/// the length in bytes of the encoded value.
+inline unsigned encodeULEB128(uint64_t Value, uint8_t *p,
+ unsigned PadTo = 0) {
+ uint8_t *orig_p = p;
+ unsigned Count = 0;
+ do {
+ uint8_t Byte = Value & 0x7f;
+ Value >>= 7;
+ Count++;
+ if (Value != 0 || Count < PadTo)
+ Byte |= 0x80; // Mark this byte to show that more bytes will follow.
+ *p++ = Byte;
+ } while (Value != 0);
+
+ // Pad with 0x80 and emit a null byte at the end.
+ if (Count < PadTo) {
+ for (; Count < PadTo - 1; ++Count)
+ *p++ = '\x80';
+ *p++ = '\x00';
+ }
+
+ return (unsigned)(p - orig_p);
+}
+
+/// Utility function to decode a ULEB128 value.
+inline uint64_t decodeULEB128(const uint8_t *p, unsigned *n = nullptr,
+ const uint8_t *end = nullptr,
+ const char **error = nullptr) {
+ const uint8_t *orig_p = p;
+ uint64_t Value = 0;
+ unsigned Shift = 0;
+ if (error)
+ *error = nullptr;
+ do {
+ if (p == end) {
+ if (error)
+ *error = "malformed uleb128, extends past end";
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return 0;
+ }
+ uint64_t Slice = *p & 0x7f;
+ if ((Shift >= 64 && Slice != 0) || Slice << Shift >> Shift != Slice) {
+ if (error)
+ *error = "uleb128 too big for uint64";
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return 0;
+ }
+ Value += Slice << Shift;
+ Shift += 7;
+ } while (*p++ >= 128);
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return Value;
+}
+
+/// Utility function to decode a SLEB128 value.
+inline int64_t decodeSLEB128(const uint8_t *p, unsigned *n = nullptr,
+ const uint8_t *end = nullptr,
+ const char **error = nullptr) {
+ const uint8_t *orig_p = p;
+ int64_t Value = 0;
+ unsigned Shift = 0;
+ uint8_t Byte;
+ if (error)
+ *error = nullptr;
+ do {
+ if (p == end) {
+ if (error)
+ *error = "malformed sleb128, extends past end";
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return 0;
+ }
+ Byte = *p;
+ uint64_t Slice = Byte & 0x7f;
+ if ((Shift >= 64 && Slice != (Value < 0 ? 0x7f : 0x00)) ||
+ (Shift == 63 && Slice != 0 && Slice != 0x7f)) {
+ if (error)
+ *error = "sleb128 too big for int64";
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return 0;
+ }
+ Value |= Slice << Shift;
+ Shift += 7;
+ ++p;
+ } while (Byte >= 128);
+ // Sign extend negative numbers if needed.
+ if (Shift < 64 && (Byte & 0x40))
+ Value |= (-1ULL) << Shift;
+ if (n)
+ *n = (unsigned)(p - orig_p);
+ return Value;
+}
+
+/// Utility function to get the size of the ULEB128-encoded value.
+extern unsigned getULEB128Size(uint64_t Value);
+
+/// Utility function to get the size of the SLEB128-encoded value.
+extern unsigned getSLEB128Size(int64_t Value);
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_LEB128_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/LICENSE.TXT b/contrib/libs/llvm16/include/llvm/Support/LICENSE.TXT
new file mode 100644
index 00000000000..3f4dbf402b7
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/LICENSE.TXT
@@ -0,0 +1,6 @@
+LLVM System Interface Library
+-------------------------------------------------------------------------------
+
+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
diff --git a/contrib/libs/llvm16/include/llvm/Support/LineIterator.h b/contrib/libs/llvm16/include/llvm/Support/LineIterator.h
new file mode 100644
index 00000000000..f5c89d78c1f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/LineIterator.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- LineIterator.h - Iterator to read a text buffer's lines --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_LINEITERATOR_H
+#define LLVM_SUPPORT_LINEITERATOR_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include <iterator>
+#include <optional>
+
+namespace llvm {
+
+class MemoryBuffer;
+
+/// A forward iterator which reads text lines from a buffer.
+///
+/// This class provides a forward iterator interface for reading one line at
+/// a time from a buffer. When default constructed the iterator will be the
+/// "end" iterator.
+///
+/// The iterator is aware of what line number it is currently processing. It
+/// strips blank lines by default, and comment lines given a comment-starting
+/// character.
+///
+/// Note that this iterator requires the buffer to be nul terminated.
+class line_iterator {
+ std::optional<MemoryBufferRef> Buffer;
+ char CommentMarker = '\0';
+ bool SkipBlanks = true;
+
+ unsigned LineNumber = 1;
+ StringRef CurrentLine;
+
+public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = StringRef;
+ using difference_type = std::ptrdiff_t;
+ using pointer = value_type *;
+ using reference = value_type &;
+
+ /// Default construct an "end" iterator.
+ line_iterator() = default;
+
+ /// Construct a new iterator around an unowned memory buffer.
+ explicit line_iterator(const MemoryBufferRef &Buffer, bool SkipBlanks = true,
+ char CommentMarker = '\0');
+
+ /// Construct a new iterator around some memory buffer.
+ explicit line_iterator(const MemoryBuffer &Buffer, bool SkipBlanks = true,
+ char CommentMarker = '\0');
+
+ /// Return true if we've reached EOF or are an "end" iterator.
+ bool is_at_eof() const { return !Buffer; }
+
+ /// Return true if we're an "end" iterator or have reached EOF.
+ bool is_at_end() const { return is_at_eof(); }
+
+ /// Return the current line number. May return any number at EOF.
+ int64_t line_number() const { return LineNumber; }
+
+ /// Advance to the next (non-empty, non-comment) line.
+ line_iterator &operator++() {
+ advance();
+ return *this;
+ }
+ line_iterator operator++(int) {
+ line_iterator tmp(*this);
+ advance();
+ return tmp;
+ }
+
+ /// Get the current line as a \c StringRef.
+ StringRef operator*() const { return CurrentLine; }
+ const StringRef *operator->() const { return &CurrentLine; }
+
+ friend bool operator==(const line_iterator &LHS, const line_iterator &RHS) {
+ return LHS.Buffer == RHS.Buffer &&
+ LHS.CurrentLine.begin() == RHS.CurrentLine.begin();
+ }
+
+ friend bool operator!=(const line_iterator &LHS, const line_iterator &RHS) {
+ return !(LHS == RHS);
+ }
+
+private:
+ /// Advance the iterator to the next line.
+ void advance();
+};
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Locale.h b/contrib/libs/llvm16/include/llvm/Support/Locale.h
new file mode 100644
index 00000000000..e830d2f9bd6
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Locale.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+#ifndef LLVM_SUPPORT_LOCALE_H
+#define LLVM_SUPPORT_LOCALE_H
+
+namespace llvm {
+class StringRef;
+
+namespace sys {
+namespace locale {
+
+int columnWidth(StringRef s);
+bool isPrint(int c);
+
+}
+}
+}
+
+#endif // LLVM_SUPPORT_LOCALE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/LockFileManager.h b/contrib/libs/llvm16/include/llvm/Support/LockFileManager.h
new file mode 100644
index 00000000000..18c53b416fd
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/LockFileManager.h
@@ -0,0 +1,111 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- LockFileManager.h - File-level locking utility ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_LOCKFILEMANAGER_H
+#define LLVM_SUPPORT_LOCKFILEMANAGER_H
+
+#include "llvm/ADT/SmallString.h"
+#include <optional>
+#include <system_error>
+#include <utility> // for std::pair
+
+namespace llvm {
+class StringRef;
+
+/// Class that manages the creation of a lock file to aid
+/// implicit coordination between different processes.
+///
+/// The implicit coordination works by creating a ".lock" file alongside
+/// the file that we're coordinating for, using the atomicity of the file
+/// system to ensure that only a single process can create that ".lock" file.
+/// When the lock file is removed, the owning process has finished the
+/// operation.
+class LockFileManager {
+public:
+ /// Describes the state of a lock file.
+ enum LockFileState {
+ /// The lock file has been created and is owned by this instance
+ /// of the object.
+ LFS_Owned,
+ /// The lock file already exists and is owned by some other
+ /// instance.
+ LFS_Shared,
+ /// An error occurred while trying to create or find the lock
+ /// file.
+ LFS_Error
+ };
+
+ /// Describes the result of waiting for the owner to release the lock.
+ enum WaitForUnlockResult {
+ /// The lock was released successfully.
+ Res_Success,
+ /// Owner died while holding the lock.
+ Res_OwnerDied,
+ /// Reached timeout while waiting for the owner to release the lock.
+ Res_Timeout
+ };
+
+private:
+ SmallString<128> FileName;
+ SmallString<128> LockFileName;
+ SmallString<128> UniqueLockFileName;
+
+ std::optional<std::pair<std::string, int>> Owner;
+ std::error_code ErrorCode;
+ std::string ErrorDiagMsg;
+
+ LockFileManager(const LockFileManager &) = delete;
+ LockFileManager &operator=(const LockFileManager &) = delete;
+
+ static std::optional<std::pair<std::string, int>>
+ readLockFile(StringRef LockFileName);
+
+ static bool processStillExecuting(StringRef Hostname, int PID);
+
+public:
+
+ LockFileManager(StringRef FileName);
+ ~LockFileManager();
+
+ /// Determine the state of the lock file.
+ LockFileState getState() const;
+
+ operator LockFileState() const { return getState(); }
+
+ /// For a shared lock, wait until the owner releases the lock.
+ /// Total timeout for the file to appear is ~1.5 minutes.
+ /// \param MaxSeconds the maximum total wait time in seconds.
+ WaitForUnlockResult waitForUnlock(const unsigned MaxSeconds = 90);
+
+ /// Remove the lock file. This may delete a different lock file than
+ /// the one previously read if there is a race.
+ std::error_code unsafeRemoveLockFile();
+
+ /// Get error message, or "" if there is no error.
+ std::string getErrorMessage() const;
+
+ /// Set error and error message
+ void setError(const std::error_code &EC, StringRef ErrorMsg = "") {
+ ErrorCode = EC;
+ ErrorDiagMsg = ErrorMsg.str();
+ }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_LOCKFILEMANAGER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/LowLevelTypeImpl.h b/contrib/libs/llvm16/include/llvm/Support/LowLevelTypeImpl.h
new file mode 100644
index 00000000000..0552a8a733c
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/LowLevelTypeImpl.h
@@ -0,0 +1,442 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//== llvm/Support/LowLevelTypeImpl.h --------------------------- -*- C++ -*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// Implement a low-level type suitable for MachineInstr level instruction
+/// selection.
+///
+/// For a type attached to a MachineInstr, we only care about 2 details: total
+/// size and the number of vector lanes (if any). Accordingly, there are 4
+/// possible valid type-kinds:
+///
+/// * `sN` for scalars and aggregates
+/// * `<N x sM>` for vectors, which must have at least 2 elements.
+/// * `pN` for pointers
+///
+/// Other information required for correct selection is expected to be carried
+/// by the opcode, or non-type flags. For example the distinction between G_ADD
+/// and G_FADD for int/float or fast-math flags.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
+#define LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/MachineValueType.h"
+#include <cassert>
+
+namespace llvm {
+
+class Type;
+class raw_ostream;
+
+class LLT {
+public:
+ /// Get a low-level scalar or aggregate "bag of bits".
+ static constexpr LLT scalar(unsigned SizeInBits) {
+ return LLT{/*isPointer=*/false, /*isVector=*/false, /*isScalar=*/true,
+ ElementCount::getFixed(0), SizeInBits,
+ /*AddressSpace=*/0};
+ }
+
+ /// Get a low-level pointer in the given address space.
+ static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits) {
+ assert(SizeInBits > 0 && "invalid pointer size");
+ return LLT{/*isPointer=*/true, /*isVector=*/false, /*isScalar=*/false,
+ ElementCount::getFixed(0), SizeInBits, AddressSpace};
+ }
+
+ /// Get a low-level vector of some number of elements and element width.
+ static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits) {
+ assert(!EC.isScalar() && "invalid number of vector elements");
+ return LLT{/*isPointer=*/false, /*isVector=*/true, /*isScalar=*/false,
+ EC, ScalarSizeInBits, /*AddressSpace=*/0};
+ }
+
+ /// Get a low-level vector of some number of elements and element type.
+ static constexpr LLT vector(ElementCount EC, LLT ScalarTy) {
+ assert(!EC.isScalar() && "invalid number of vector elements");
+ assert(!ScalarTy.isVector() && "invalid vector element type");
+ return LLT{ScalarTy.isPointer(),
+ /*isVector=*/true,
+ /*isScalar=*/false,
+ EC,
+ ScalarTy.getSizeInBits().getFixedValue(),
+ ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0};
+ }
+
+ /// Get a low-level fixed-width vector of some number of elements and element
+ /// width.
+ static constexpr LLT fixed_vector(unsigned NumElements,
+ unsigned ScalarSizeInBits) {
+ return vector(ElementCount::getFixed(NumElements), ScalarSizeInBits);
+ }
+
+ /// Get a low-level fixed-width vector of some number of elements and element
+ /// type.
+ static constexpr LLT fixed_vector(unsigned NumElements, LLT ScalarTy) {
+ return vector(ElementCount::getFixed(NumElements), ScalarTy);
+ }
+
+ /// Get a low-level scalable vector of some number of elements and element
+ /// width.
+ static constexpr LLT scalable_vector(unsigned MinNumElements,
+ unsigned ScalarSizeInBits) {
+ return vector(ElementCount::getScalable(MinNumElements), ScalarSizeInBits);
+ }
+
+ /// Get a low-level scalable vector of some number of elements and element
+ /// type.
+ static constexpr LLT scalable_vector(unsigned MinNumElements, LLT ScalarTy) {
+ return vector(ElementCount::getScalable(MinNumElements), ScalarTy);
+ }
+
+ static constexpr LLT scalarOrVector(ElementCount EC, LLT ScalarTy) {
+ return EC.isScalar() ? ScalarTy : LLT::vector(EC, ScalarTy);
+ }
+
+ static constexpr LLT scalarOrVector(ElementCount EC, uint64_t ScalarSize) {
+ assert(ScalarSize <= std::numeric_limits<unsigned>::max() &&
+ "Not enough bits in LLT to represent size");
+ return scalarOrVector(EC, LLT::scalar(static_cast<unsigned>(ScalarSize)));
+ }
+
+ explicit constexpr LLT(bool isPointer, bool isVector, bool isScalar,
+ ElementCount EC, uint64_t SizeInBits,
+ unsigned AddressSpace)
+ : LLT() {
+ init(isPointer, isVector, isScalar, EC, SizeInBits, AddressSpace);
+ }
+ explicit constexpr LLT()
+ : IsScalar(false), IsPointer(false), IsVector(false), RawData(0) {}
+
+ explicit LLT(MVT VT);
+
+ constexpr bool isValid() const { return IsScalar || RawData != 0; }
+
+ constexpr bool isScalar() const { return IsScalar; }
+
+ constexpr bool isPointer() const {
+ return isValid() && IsPointer && !IsVector;
+ }
+
+ constexpr bool isVector() const { return isValid() && IsVector; }
+
+ /// Returns the number of elements in a vector LLT. Must only be called on
+ /// vector types.
+ constexpr uint16_t getNumElements() const {
+ if (isScalable())
+ llvm::reportInvalidSizeRequest(
+ "Possible incorrect use of LLT::getNumElements() for "
+ "scalable vector. Scalable flag may be dropped, use "
+ "LLT::getElementCount() instead");
+ return getElementCount().getKnownMinValue();
+ }
+
+ /// Returns true if the LLT is a scalable vector. Must only be called on
+ /// vector types.
+ constexpr bool isScalable() const {
+ assert(isVector() && "Expected a vector type");
+ return IsPointer ? getFieldValue(PointerVectorScalableFieldInfo)
+ : getFieldValue(VectorScalableFieldInfo);
+ }
+
+ constexpr ElementCount getElementCount() const {
+ assert(IsVector && "cannot get number of elements on scalar/aggregate");
+ return ElementCount::get(IsPointer
+ ? getFieldValue(PointerVectorElementsFieldInfo)
+ : getFieldValue(VectorElementsFieldInfo),
+ isScalable());
+ }
+
+ /// Returns the total size of the type. Must only be called on sized types.
+ constexpr TypeSize getSizeInBits() const {
+ if (isPointer() || isScalar())
+ return TypeSize::Fixed(getScalarSizeInBits());
+ auto EC = getElementCount();
+ return TypeSize(getScalarSizeInBits() * EC.getKnownMinValue(),
+ EC.isScalable());
+ }
+
+ /// Returns the total size of the type in bytes, i.e. number of whole bytes
+ /// needed to represent the size in bits. Must only be called on sized types.
+ constexpr TypeSize getSizeInBytes() const {
+ TypeSize BaseSize = getSizeInBits();
+ return {(BaseSize.getKnownMinValue() + 7) / 8, BaseSize.isScalable()};
+ }
+
+ constexpr LLT getScalarType() const {
+ return isVector() ? getElementType() : *this;
+ }
+
+ /// If this type is a vector, return a vector with the same number of elements
+ /// but the new element type. Otherwise, return the new element type.
+ constexpr LLT changeElementType(LLT NewEltTy) const {
+ return isVector() ? LLT::vector(getElementCount(), NewEltTy) : NewEltTy;
+ }
+
+ /// If this type is a vector, return a vector with the same number of elements
+ /// but the new element size. Otherwise, return the new element type. Invalid
+ /// for pointer types. For pointer types, use changeElementType.
+ constexpr LLT changeElementSize(unsigned NewEltSize) const {
+ assert(!getScalarType().isPointer() &&
+ "invalid to directly change element size for pointers");
+ return isVector() ? LLT::vector(getElementCount(), NewEltSize)
+ : LLT::scalar(NewEltSize);
+ }
+
+ /// Return a vector or scalar with the same element type and the new element
+ /// count.
+ constexpr LLT changeElementCount(ElementCount EC) const {
+ return LLT::scalarOrVector(EC, getScalarType());
+ }
+
+ /// Return a type that is \p Factor times smaller. Reduces the number of
+ /// elements if this is a vector, or the bitwidth for scalar/pointers. Does
+ /// not attempt to handle cases that aren't evenly divisible.
+ constexpr LLT divide(int Factor) const {
+ assert(Factor != 1);
+ assert((!isScalar() || getScalarSizeInBits() != 0) &&
+ "cannot divide scalar of size zero");
+ if (isVector()) {
+ assert(getElementCount().isKnownMultipleOf(Factor));
+ return scalarOrVector(getElementCount().divideCoefficientBy(Factor),
+ getElementType());
+ }
+
+ assert(getScalarSizeInBits() % Factor == 0);
+ return scalar(getScalarSizeInBits() / Factor);
+ }
+
+ /// Produce a vector type that is \p Factor times bigger, preserving the
+ /// element type. For a scalar or pointer, this will produce a new vector with
+ /// \p Factor elements.
+ constexpr LLT multiplyElements(int Factor) const {
+ if (isVector()) {
+ return scalarOrVector(getElementCount().multiplyCoefficientBy(Factor),
+ getElementType());
+ }
+
+ return fixed_vector(Factor, *this);
+ }
+
+ constexpr bool isByteSized() const {
+ return getSizeInBits().isKnownMultipleOf(8);
+ }
+
+ constexpr unsigned getScalarSizeInBits() const {
+ if (IsScalar)
+ return getFieldValue(ScalarSizeFieldInfo);
+ if (IsVector) {
+ if (!IsPointer)
+ return getFieldValue(VectorSizeFieldInfo);
+ else
+ return getFieldValue(PointerVectorSizeFieldInfo);
+ } else if (IsPointer)
+ return getFieldValue(PointerSizeFieldInfo);
+ else
+ llvm_unreachable("unexpected LLT");
+ }
+
+ constexpr unsigned getAddressSpace() const {
+ assert(RawData != 0 && "Invalid Type");
+ assert(IsPointer && "cannot get address space of non-pointer type");
+ if (!IsVector)
+ return getFieldValue(PointerAddressSpaceFieldInfo);
+ else
+ return getFieldValue(PointerVectorAddressSpaceFieldInfo);
+ }
+
+ /// Returns the vector's element type. Only valid for vector types.
+ constexpr LLT getElementType() const {
+ assert(isVector() && "cannot get element type of scalar/aggregate");
+ if (IsPointer)
+ return pointer(getAddressSpace(), getScalarSizeInBits());
+ else
+ return scalar(getScalarSizeInBits());
+ }
+
+ void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ LLVM_DUMP_METHOD void dump() const {
+ print(dbgs());
+ dbgs() << '\n';
+ }
+#endif
+
+ constexpr bool operator==(const LLT &RHS) const {
+ return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
+ IsScalar == RHS.IsScalar && RHS.RawData == RawData;
+ }
+
+ constexpr bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
+
+ friend struct DenseMapInfo<LLT>;
+ friend class GISelInstProfileBuilder;
+
+private:
+ /// LLT is packed into 64 bits as follows:
+ /// isScalar : 1
+ /// isPointer : 1
+ /// isVector : 1
+ /// with 61 bits remaining for Kind-specific data, packed in bitfields
+ /// as described below. As there isn't a simple portable way to pack bits
+ /// into bitfields, here the different fields in the packed structure is
+ /// described in static const *Field variables. Each of these variables
+ /// is a 2-element array, with the first element describing the bitfield size
+ /// and the second element describing the bitfield offset.
+ typedef int BitFieldInfo[2];
+ ///
+ /// This is how the bitfields are packed per Kind:
+ /// * Invalid:
+ /// gets encoded as RawData == 0, as that is an invalid encoding, since for
+ /// valid encodings, SizeInBits/SizeOfElement must be larger than 0.
+ /// * Non-pointer scalar (isPointer == 0 && isVector == 0):
+ /// SizeInBits: 32;
+ static const constexpr BitFieldInfo ScalarSizeFieldInfo{32, 0};
+ /// * Pointer (isPointer == 1 && isVector == 0):
+ /// SizeInBits: 16;
+ /// AddressSpace: 24;
+ static const constexpr BitFieldInfo PointerSizeFieldInfo{16, 0};
+ static const constexpr BitFieldInfo PointerAddressSpaceFieldInfo{
+ 24, PointerSizeFieldInfo[0] + PointerSizeFieldInfo[1]};
+ static_assert((PointerAddressSpaceFieldInfo[0] +
+ PointerAddressSpaceFieldInfo[1]) <= 61,
+ "Insufficient bits to encode all data");
+ /// * Vector-of-non-pointer (isPointer == 0 && isVector == 1):
+ /// NumElements: 16;
+ /// SizeOfElement: 32;
+ /// Scalable: 1;
+ static const constexpr BitFieldInfo VectorElementsFieldInfo{16, 0};
+ static const constexpr BitFieldInfo VectorSizeFieldInfo{
+ 32, VectorElementsFieldInfo[0] + VectorElementsFieldInfo[1]};
+ static const constexpr BitFieldInfo VectorScalableFieldInfo{
+ 1, VectorSizeFieldInfo[0] + VectorSizeFieldInfo[1]};
+ static_assert((VectorSizeFieldInfo[0] + VectorSizeFieldInfo[1]) <= 61,
+ "Insufficient bits to encode all data");
+ /// * Vector-of-pointer (isPointer == 1 && isVector == 1):
+ /// NumElements: 16;
+ /// SizeOfElement: 16;
+ /// AddressSpace: 24;
+ /// Scalable: 1;
+ static const constexpr BitFieldInfo PointerVectorElementsFieldInfo{16, 0};
+ static const constexpr BitFieldInfo PointerVectorSizeFieldInfo{
+ 16,
+ PointerVectorElementsFieldInfo[1] + PointerVectorElementsFieldInfo[0]};
+ static const constexpr BitFieldInfo PointerVectorAddressSpaceFieldInfo{
+ 24, PointerVectorSizeFieldInfo[1] + PointerVectorSizeFieldInfo[0]};
+ static const constexpr BitFieldInfo PointerVectorScalableFieldInfo{
+ 1, PointerVectorAddressSpaceFieldInfo[0] +
+ PointerVectorAddressSpaceFieldInfo[1]};
+ static_assert((PointerVectorAddressSpaceFieldInfo[0] +
+ PointerVectorAddressSpaceFieldInfo[1]) <= 61,
+ "Insufficient bits to encode all data");
+
+ uint64_t IsScalar : 1;
+ uint64_t IsPointer : 1;
+ uint64_t IsVector : 1;
+ uint64_t RawData : 61;
+
+ static constexpr uint64_t getMask(const BitFieldInfo FieldInfo) {
+ const int FieldSizeInBits = FieldInfo[0];
+ return (((uint64_t)1) << FieldSizeInBits) - 1;
+ }
+ static constexpr uint64_t maskAndShift(uint64_t Val, uint64_t Mask,
+ uint8_t Shift) {
+ assert(Val <= Mask && "Value too large for field");
+ return (Val & Mask) << Shift;
+ }
+ static constexpr uint64_t maskAndShift(uint64_t Val,
+ const BitFieldInfo FieldInfo) {
+ return maskAndShift(Val, getMask(FieldInfo), FieldInfo[1]);
+ }
+
+ constexpr uint64_t getFieldValue(const BitFieldInfo FieldInfo) const {
+ return getMask(FieldInfo) & (RawData >> FieldInfo[1]);
+ }
+
+ constexpr void init(bool IsPointer, bool IsVector, bool IsScalar,
+ ElementCount EC, uint64_t SizeInBits,
+ unsigned AddressSpace) {
+ assert(SizeInBits <= std::numeric_limits<unsigned>::max() &&
+ "Not enough bits in LLT to represent size");
+ this->IsPointer = IsPointer;
+ this->IsVector = IsVector;
+ this->IsScalar = IsScalar;
+ if (IsScalar)
+ RawData = maskAndShift(SizeInBits, ScalarSizeFieldInfo);
+ else if (IsVector) {
+ assert(EC.isVector() && "invalid number of vector elements");
+ if (!IsPointer)
+ RawData =
+ maskAndShift(EC.getKnownMinValue(), VectorElementsFieldInfo) |
+ maskAndShift(SizeInBits, VectorSizeFieldInfo) |
+ maskAndShift(EC.isScalable() ? 1 : 0, VectorScalableFieldInfo);
+ else
+ RawData =
+ maskAndShift(EC.getKnownMinValue(),
+ PointerVectorElementsFieldInfo) |
+ maskAndShift(SizeInBits, PointerVectorSizeFieldInfo) |
+ maskAndShift(AddressSpace, PointerVectorAddressSpaceFieldInfo) |
+ maskAndShift(EC.isScalable() ? 1 : 0,
+ PointerVectorScalableFieldInfo);
+ } else if (IsPointer)
+ RawData = maskAndShift(SizeInBits, PointerSizeFieldInfo) |
+ maskAndShift(AddressSpace, PointerAddressSpaceFieldInfo);
+ else
+ llvm_unreachable("unexpected LLT configuration");
+ }
+
+public:
+ constexpr uint64_t getUniqueRAWLLTData() const {
+ return ((uint64_t)RawData) << 3 | ((uint64_t)IsScalar) << 2 |
+ ((uint64_t)IsPointer) << 1 | ((uint64_t)IsVector);
+ }
+};
+
+inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
+ Ty.print(OS);
+ return OS;
+}
+
+template<> struct DenseMapInfo<LLT> {
+ static inline LLT getEmptyKey() {
+ LLT Invalid;
+ Invalid.IsPointer = true;
+ return Invalid;
+ }
+ static inline LLT getTombstoneKey() {
+ LLT Invalid;
+ Invalid.IsVector = true;
+ return Invalid;
+ }
+ static inline unsigned getHashValue(const LLT &Ty) {
+ uint64_t Val = Ty.getUniqueRAWLLTData();
+ return DenseMapInfo<uint64_t>::getHashValue(Val);
+ }
+ static bool isEqual(const LLT &LHS, const LLT &RHS) {
+ return LHS == RHS;
+ }
+};
+
+}
+
+#endif // LLVM_SUPPORT_LOWLEVELTYPEIMPL_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/MD5.h b/contrib/libs/llvm16/include/llvm/Support/MD5.h
new file mode 100644
index 00000000000..e96c6f0c092
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/MD5.h
@@ -0,0 +1,133 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+/* -*- C++ -*-
+ * This code is derived from (original license follows):
+ *
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * See md5.c for more information.
+ */
+
+#ifndef LLVM_SUPPORT_MD5_H
+#define LLVM_SUPPORT_MD5_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Endian.h"
+#include <array>
+#include <cstdint>
+
+namespace llvm {
+
+template <unsigned N> class SmallString;
+template <typename T> class ArrayRef;
+
+class MD5 {
+public:
+ struct MD5Result : public std::array<uint8_t, 16> {
+ SmallString<32> digest() const;
+
+ uint64_t low() const {
+ // Our MD5 implementation returns the result in little endian, so the low
+ // word is first.
+ using namespace support;
+ return endian::read<uint64_t, little, unaligned>(data());
+ }
+
+ uint64_t high() const {
+ using namespace support;
+ return endian::read<uint64_t, little, unaligned>(data() + 8);
+ }
+ std::pair<uint64_t, uint64_t> words() const {
+ using namespace support;
+ return std::make_pair(high(), low());
+ }
+ };
+
+ MD5();
+
+ /// Updates the hash for the byte stream provided.
+ void update(ArrayRef<uint8_t> Data);
+
+ /// Updates the hash for the StringRef provided.
+ void update(StringRef Str);
+
+ /// Finishes off the hash and puts the result in result.
+ void final(MD5Result &Result);
+
+ /// Finishes off the hash, and returns the 16-byte hash data.
+ MD5Result final();
+
+ /// Finishes off the hash, and returns the 16-byte hash data.
+ /// This is suitable for getting the MD5 at any time without invalidating the
+ /// internal state, so that more calls can be made into `update`.
+ MD5Result result();
+
+ /// Translates the bytes in \p Res to a hex string that is
+ /// deposited into \p Str. The result will be of length 32.
+ static void stringifyResult(MD5Result &Result, SmallVectorImpl<char> &Str);
+
+ /// Computes the hash for a given bytes.
+ static MD5Result hash(ArrayRef<uint8_t> Data);
+
+private:
+ // Any 32-bit or wider unsigned integer data type will do.
+ typedef uint32_t MD5_u32plus;
+
+ // Internal State
+ struct {
+ MD5_u32plus a = 0x67452301;
+ MD5_u32plus b = 0xefcdab89;
+ MD5_u32plus c = 0x98badcfe;
+ MD5_u32plus d = 0x10325476;
+ MD5_u32plus hi = 0;
+ MD5_u32plus lo = 0;
+ uint8_t buffer[64];
+ MD5_u32plus block[16];
+ } InternalState;
+
+ const uint8_t *body(ArrayRef<uint8_t> Data);
+};
+
+/// Helper to compute and return lower 64 bits of the given string's MD5 hash.
+inline uint64_t MD5Hash(StringRef Str) {
+ using namespace support;
+
+ MD5 Hash;
+ Hash.update(Str);
+ MD5::MD5Result Result;
+ Hash.final(Result);
+ // Return the least significant word.
+ return Result.low();
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_MD5_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/MSP430AttributeParser.h b/contrib/libs/llvm16/include/llvm/Support/MSP430AttributeParser.h
new file mode 100644
index 00000000000..33ab30d5c71
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/MSP430AttributeParser.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- MSP430AttributeParser.h - MSP430 Attribute Parser -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains support routines for parsing MSP430 ELF build attributes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MSP430ATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_MSP430ATTRIBUTEPARSER_H
+
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/MSP430Attributes.h"
+
+namespace llvm {
+class MSP430AttributeParser : public ELFAttributeParser {
+ struct DisplayHandler {
+ MSP430Attrs::AttrType Attribute;
+ Error (MSP430AttributeParser::*Routine)(MSP430Attrs::AttrType);
+ };
+ static const std::array<DisplayHandler, 4> DisplayRoutines;
+
+ Error parseISA(MSP430Attrs::AttrType Tag);
+ Error parseCodeModel(MSP430Attrs::AttrType Tag);
+ Error parseDataModel(MSP430Attrs::AttrType Tag);
+ Error parseEnumSize(MSP430Attrs::AttrType Tag);
+
+ Error handler(uint64_t Tag, bool &Handled) override;
+
+public:
+ MSP430AttributeParser(ScopedPrinter *SW)
+ : ELFAttributeParser(SW, MSP430Attrs::getMSP430AttributeTags(),
+ "mspabi") {}
+ MSP430AttributeParser()
+ : ELFAttributeParser(MSP430Attrs::getMSP430AttributeTags(), "mspabi") {}
+};
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/MSP430Attributes.h b/contrib/libs/llvm16/include/llvm/Support/MSP430Attributes.h
new file mode 100644
index 00000000000..99e5c953db9
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/MSP430Attributes.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- MSP430Attributes.h - MSP430 Attributes ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===-----------------------------------------------------------------------===//
+///
+/// \file
+/// This file contains enumerations for MSP430 ELF build attributes as
+/// defined in the MSP430 ELF psABI specification.
+///
+/// MSP430 ELF psABI specification
+///
+/// https://www.ti.com/lit/pdf/slaa534
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_MSP430ATTRIBUTES_H
+#define LLVM_SUPPORT_MSP430ATTRIBUTES_H
+
+#include "llvm/Support/ELFAttributes.h"
+
+namespace llvm {
+namespace MSP430Attrs {
+
+const TagNameMap &getMSP430AttributeTags();
+
+enum AttrType : unsigned {
+ // Attribute types in ELF/.MSP430.attributes.
+ TagISA = 4,
+ TagCodeModel = 6,
+ TagDataModel = 8,
+ TagEnumSize = 10
+};
+
+enum ISA { ISAMSP430 = 1, ISAMSP430X = 2 };
+enum CodeModel { CMSmall = 1, CMLarge = 2 };
+enum DataModel { DMSmall = 1, DMLarge = 2, DMRestricted = 3 };
+enum EnumSize { ESSmall = 1, ESInteger = 2, ESDontCare = 3 };
+
+} // namespace MSP430Attrs
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/MachineValueType.h b/contrib/libs/llvm16/include/llvm/Support/MachineValueType.h
new file mode 100644
index 00000000000..1887bb0de31
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/MachineValueType.h
@@ -0,0 +1,1587 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- Support/MachineValueType.h - Machine-Level types ---------*- 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 defines the set of machine-level target independent types which
+// legal values in the code generator use.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MACHINEVALUETYPE_H
+#define LLVM_SUPPORT_MACHINEVALUETYPE_H
+
+#include "llvm/ADT/Sequence.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/TypeSize.h"
+#include <cassert>
+
+namespace llvm {
+
+ class Type;
+
+ /// Machine Value Type. Every type that is supported natively by some
+ /// processor targeted by LLVM occurs here. This means that any legal value
+ /// type can be represented by an MVT.
+ class MVT {
+ public:
+ enum SimpleValueType : uint8_t {
+ // clang-format off
+
+ // Simple value types that aren't explicitly part of this enumeration
+ // are considered extended value types.
+ INVALID_SIMPLE_VALUE_TYPE = 0,
+
+ // If you change this numbering, you must change the values in
+ // ValueTypes.td as well!
+ Other = 1, // This is a non-standard value
+ i1 = 2, // This is a 1 bit integer value
+ i2 = 3, // This is a 2 bit integer value
+ i4 = 4, // This is a 4 bit integer value
+ i8 = 5, // This is an 8 bit integer value
+ i16 = 6, // This is a 16 bit integer value
+ i32 = 7, // This is a 32 bit integer value
+ i64 = 8, // This is a 64 bit integer value
+ i128 = 9, // This is a 128 bit integer value
+
+ FIRST_INTEGER_VALUETYPE = i1,
+ LAST_INTEGER_VALUETYPE = i128,
+
+ bf16 = 10, // This is a 16 bit brain floating point value
+ f16 = 11, // This is a 16 bit floating point value
+ f32 = 12, // This is a 32 bit floating point value
+ f64 = 13, // This is a 64 bit floating point value
+ f80 = 14, // This is a 80 bit floating point value
+ f128 = 15, // This is a 128 bit floating point value
+ ppcf128 = 16, // This is a PPC 128-bit floating point value
+
+ FIRST_FP_VALUETYPE = bf16,
+ LAST_FP_VALUETYPE = ppcf128,
+
+ v1i1 = 17, // 1 x i1
+ v2i1 = 18, // 2 x i1
+ v4i1 = 19, // 4 x i1
+ v8i1 = 20, // 8 x i1
+ v16i1 = 21, // 16 x i1
+ v32i1 = 22, // 32 x i1
+ v64i1 = 23, // 64 x i1
+ v128i1 = 24, // 128 x i1
+ v256i1 = 25, // 256 x i1
+ v512i1 = 26, // 512 x i1
+ v1024i1 = 27, // 1024 x i1
+ v2048i1 = 28, // 2048 x i1
+
+ v128i2 = 29, // 128 x i2
+ v256i2 = 30, // 256 x i2
+
+ v64i4 = 31, // 64 x i4
+ v128i4 = 32, // 128 x i4
+
+ v1i8 = 33, // 1 x i8
+ v2i8 = 34, // 2 x i8
+ v4i8 = 35, // 4 x i8
+ v8i8 = 36, // 8 x i8
+ v16i8 = 37, // 16 x i8
+ v32i8 = 38, // 32 x i8
+ v64i8 = 39, // 64 x i8
+ v128i8 = 40, // 128 x i8
+ v256i8 = 41, // 256 x i8
+ v512i8 = 42, // 512 x i8
+ v1024i8 = 43, // 1024 x i8
+
+ v1i16 = 44, // 1 x i16
+ v2i16 = 45, // 2 x i16
+ v3i16 = 46, // 3 x i16
+ v4i16 = 47, // 4 x i16
+ v8i16 = 48, // 8 x i16
+ v16i16 = 49, // 16 x i16
+ v32i16 = 50, // 32 x i16
+ v64i16 = 51, // 64 x i16
+ v128i16 = 52, // 128 x i16
+ v256i16 = 53, // 256 x i16
+ v512i16 = 54, // 512 x i16
+
+ v1i32 = 55, // 1 x i32
+ v2i32 = 56, // 2 x i32
+ v3i32 = 57, // 3 x i32
+ v4i32 = 58, // 4 x i32
+ v5i32 = 59, // 5 x i32
+ v6i32 = 60, // 6 x i32
+ v7i32 = 61, // 7 x i32
+ v8i32 = 62, // 8 x i32
+ v9i32 = 63, // 9 x i32
+ v10i32 = 64, // 10 x i32
+ v11i32 = 65, // 11 x i32
+ v12i32 = 66, // 12 x i32
+ v16i32 = 67, // 16 x i32
+ v32i32 = 68, // 32 x i32
+ v64i32 = 69, // 64 x i32
+ v128i32 = 70, // 128 x i32
+ v256i32 = 71, // 256 x i32
+ v512i32 = 72, // 512 x i32
+ v1024i32 = 73, // 1024 x i32
+ v2048i32 = 74, // 2048 x i32
+
+ v1i64 = 75, // 1 x i64
+ v2i64 = 76, // 2 x i64
+ v3i64 = 77, // 3 x i64
+ v4i64 = 78, // 4 x i64
+ v8i64 = 79, // 8 x i64
+ v16i64 = 80, // 16 x i64
+ v32i64 = 81, // 32 x i64
+ v64i64 = 82, // 64 x i64
+ v128i64 = 83, // 128 x i64
+ v256i64 = 84, // 256 x i64
+
+ v1i128 = 85, // 1 x i128
+
+ FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE = v1i1,
+ LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE = v1i128,
+
+ v1f16 = 86, // 1 x f16
+ v2f16 = 87, // 2 x f16
+ v3f16 = 88, // 3 x f16
+ v4f16 = 89, // 4 x f16
+ v8f16 = 90, // 8 x f16
+ v16f16 = 91, // 16 x f16
+ v32f16 = 92, // 32 x f16
+ v64f16 = 93, // 64 x f16
+ v128f16 = 94, // 128 x f16
+ v256f16 = 95, // 256 x f16
+ v512f16 = 96, // 512 x f16
+
+ v2bf16 = 97, // 2 x bf16
+ v3bf16 = 98, // 3 x bf16
+ v4bf16 = 99, // 4 x bf16
+ v8bf16 = 100, // 8 x bf16
+ v16bf16 = 101, // 16 x bf16
+ v32bf16 = 102, // 32 x bf16
+ v64bf16 = 103, // 64 x bf16
+ v128bf16 = 104, // 128 x bf16
+
+ v1f32 = 105, // 1 x f32
+ v2f32 = 106, // 2 x f32
+ v3f32 = 107, // 3 x f32
+ v4f32 = 108, // 4 x f32
+ v5f32 = 109, // 5 x f32
+ v6f32 = 110, // 6 x f32
+ v7f32 = 111, // 7 x f32
+ v8f32 = 112, // 8 x f32
+ v9f32 = 113, // 9 x f32
+ v10f32 = 114, // 10 x f32
+ v11f32 = 115, // 11 x f32
+ v12f32 = 116, // 12 x f32
+ v16f32 = 117, // 16 x f32
+
+ v32f32 = 118, // 32 x f32
+ v64f32 = 119, // 64 x f32
+ v128f32 = 120, // 128 x f32
+ v256f32 = 121, // 256 x f32
+ v512f32 = 122, // 512 x f32
+ v1024f32 = 123, // 1024 x f32
+ v2048f32 = 124, // 2048 x f32
+
+ v1f64 = 125, // 1 x f64
+ v2f64 = 126, // 2 x f64
+ v3f64 = 127, // 3 x f64
+ v4f64 = 128, // 4 x f64
+ v8f64 = 129, // 8 x f64
+ v16f64 = 130, // 16 x f64
+ v32f64 = 131, // 32 x f64
+ v64f64 = 132, // 64 x f64
+ v128f64 = 133, // 128 x f64
+ v256f64 = 134, // 256 x f64
+
+ FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE = v1f16,
+ LAST_FP_FIXEDLEN_VECTOR_VALUETYPE = v256f64,
+
+ FIRST_FIXEDLEN_VECTOR_VALUETYPE = v1i1,
+ LAST_FIXEDLEN_VECTOR_VALUETYPE = v256f64,
+
+ nxv1i1 = 135, // n x 1 x i1
+ nxv2i1 = 136, // n x 2 x i1
+ nxv4i1 = 137, // n x 4 x i1
+ nxv8i1 = 138, // n x 8 x i1
+ nxv16i1 = 139, // n x 16 x i1
+ nxv32i1 = 140, // n x 32 x i1
+ nxv64i1 = 141, // n x 64 x i1
+
+ nxv1i8 = 142, // n x 1 x i8
+ nxv2i8 = 143, // n x 2 x i8
+ nxv4i8 = 144, // n x 4 x i8
+ nxv8i8 = 145, // n x 8 x i8
+ nxv16i8 = 146, // n x 16 x i8
+ nxv32i8 = 147, // n x 32 x i8
+ nxv64i8 = 148, // n x 64 x i8
+
+ nxv1i16 = 149, // n x 1 x i16
+ nxv2i16 = 150, // n x 2 x i16
+ nxv4i16 = 151, // n x 4 x i16
+ nxv8i16 = 152, // n x 8 x i16
+ nxv16i16 = 153, // n x 16 x i16
+ nxv32i16 = 154, // n x 32 x i16
+
+ nxv1i32 = 155, // n x 1 x i32
+ nxv2i32 = 156, // n x 2 x i32
+ nxv4i32 = 157, // n x 4 x i32
+ nxv8i32 = 158, // n x 8 x i32
+ nxv16i32 = 159, // n x 16 x i32
+ nxv32i32 = 160, // n x 32 x i32
+
+ nxv1i64 = 161, // n x 1 x i64
+ nxv2i64 = 162, // n x 2 x i64
+ nxv4i64 = 163, // n x 4 x i64
+ nxv8i64 = 164, // n x 8 x i64
+ nxv16i64 = 165, // n x 16 x i64
+ nxv32i64 = 166, // n x 32 x i64
+
+ FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE = nxv1i1,
+ LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE = nxv32i64,
+
+ nxv1f16 = 167, // n x 1 x f16
+ nxv2f16 = 168, // n x 2 x f16
+ nxv4f16 = 169, // n x 4 x f16
+ nxv8f16 = 170, // n x 8 x f16
+ nxv16f16 = 171, // n x 16 x f16
+ nxv32f16 = 172, // n x 32 x f16
+
+ nxv1bf16 = 173, // n x 1 x bf16
+ nxv2bf16 = 174, // n x 2 x bf16
+ nxv4bf16 = 175, // n x 4 x bf16
+ nxv8bf16 = 176, // n x 8 x bf16
+ nxv16bf16 = 177, // n x 16 x bf16
+ nxv32bf16 = 178, // n x 32 x bf16
+
+ nxv1f32 = 179, // n x 1 x f32
+ nxv2f32 = 180, // n x 2 x f32
+ nxv4f32 = 181, // n x 4 x f32
+ nxv8f32 = 182, // n x 8 x f32
+ nxv16f32 = 183, // n x 16 x f32
+
+ nxv1f64 = 184, // n x 1 x f64
+ nxv2f64 = 185, // n x 2 x f64
+ nxv4f64 = 186, // n x 4 x f64
+ nxv8f64 = 187, // n x 8 x f64
+
+ FIRST_FP_SCALABLE_VECTOR_VALUETYPE = nxv1f16,
+ LAST_FP_SCALABLE_VECTOR_VALUETYPE = nxv8f64,
+
+ FIRST_SCALABLE_VECTOR_VALUETYPE = nxv1i1,
+ LAST_SCALABLE_VECTOR_VALUETYPE = nxv8f64,
+
+ FIRST_VECTOR_VALUETYPE = v1i1,
+ LAST_VECTOR_VALUETYPE = nxv8f64,
+
+ x86mmx = 188, // This is an X86 MMX value
+
+ Glue = 189, // This glues nodes together during pre-RA sched
+
+ isVoid = 190, // This has no value
+
+ Untyped = 191, // This value takes a register, but has
+ // unspecified type. The register class
+ // will be determined by the opcode.
+
+ funcref = 192, // WebAssembly's funcref type
+ externref = 193, // WebAssembly's externref type
+ x86amx = 194, // This is an X86 AMX value
+ i64x8 = 195, // 8 Consecutive GPRs (AArch64)
+
+ FIRST_VALUETYPE = 1, // This is always the beginning of the list.
+ LAST_VALUETYPE = i64x8, // This always remains at the end of the list.
+ VALUETYPE_SIZE = LAST_VALUETYPE + 1,
+
+ // This is the current maximum for LAST_VALUETYPE.
+ // MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors
+ // This value must be a multiple of 32.
+ MAX_ALLOWED_VALUETYPE = 224,
+
+ // A value of type llvm::TokenTy
+ token = 248,
+
+ // This is MDNode or MDString.
+ Metadata = 249,
+
+ // An int value the size of the pointer of the current
+ // target to any address space. This must only be used internal to
+ // tblgen. Other than for overloading, we treat iPTRAny the same as iPTR.
+ iPTRAny = 250,
+
+ // A vector with any length and element size. This is used
+ // for intrinsics that have overloadings based on vector types.
+ // This is only for tblgen's consumption!
+ vAny = 251,
+
+ // Any floating-point or vector floating-point value. This is used
+ // for intrinsics that have overloadings based on floating-point types.
+ // This is only for tblgen's consumption!
+ fAny = 252,
+
+ // An integer or vector integer value of any bit width. This is
+ // used for intrinsics that have overloadings based on integer bit widths.
+ // This is only for tblgen's consumption!
+ iAny = 253,
+
+ // An int value the size of the pointer of the current
+ // target. This should only be used internal to tblgen!
+ iPTR = 254,
+
+ // Any type. This is used for intrinsics that have overloadings.
+ // This is only for tblgen's consumption!
+ Any = 255
+
+ // clang-format on
+ };
+
+ SimpleValueType SimpleTy = INVALID_SIMPLE_VALUE_TYPE;
+
+ constexpr MVT() = default;
+ constexpr MVT(SimpleValueType SVT) : SimpleTy(SVT) {}
+
+ bool operator>(const MVT& S) const { return SimpleTy > S.SimpleTy; }
+ bool operator<(const MVT& S) const { return SimpleTy < S.SimpleTy; }
+ bool operator==(const MVT& S) const { return SimpleTy == S.SimpleTy; }
+ bool operator!=(const MVT& S) const { return SimpleTy != S.SimpleTy; }
+ bool operator>=(const MVT& S) const { return SimpleTy >= S.SimpleTy; }
+ bool operator<=(const MVT& S) const { return SimpleTy <= S.SimpleTy; }
+
+ /// Return true if this is a valid simple valuetype.
+ bool isValid() const {
+ return (SimpleTy >= MVT::FIRST_VALUETYPE &&
+ SimpleTy <= MVT::LAST_VALUETYPE);
+ }
+
+ /// Return true if this is a FP or a vector FP type.
+ bool isFloatingPoint() const {
+ return ((SimpleTy >= MVT::FIRST_FP_VALUETYPE &&
+ SimpleTy <= MVT::LAST_FP_VALUETYPE) ||
+ (SimpleTy >= MVT::FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_FP_FIXEDLEN_VECTOR_VALUETYPE) ||
+ (SimpleTy >= MVT::FIRST_FP_SCALABLE_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_FP_SCALABLE_VECTOR_VALUETYPE));
+ }
+
+ /// Return true if this is an integer or a vector integer type.
+ bool isInteger() const {
+ return ((SimpleTy >= MVT::FIRST_INTEGER_VALUETYPE &&
+ SimpleTy <= MVT::LAST_INTEGER_VALUETYPE) ||
+ (SimpleTy >= MVT::FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE) ||
+ (SimpleTy >= MVT::FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE));
+ }
+
+ /// Return true if this is an integer, not including vectors.
+ bool isScalarInteger() const {
+ return (SimpleTy >= MVT::FIRST_INTEGER_VALUETYPE &&
+ SimpleTy <= MVT::LAST_INTEGER_VALUETYPE);
+ }
+
+ /// Return true if this is a vector value type.
+ bool isVector() const {
+ return (SimpleTy >= MVT::FIRST_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_VECTOR_VALUETYPE);
+ }
+
+ /// Return true if this is a vector value type where the
+ /// runtime length is machine dependent
+ bool isScalableVector() const {
+ return (SimpleTy >= MVT::FIRST_SCALABLE_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_SCALABLE_VECTOR_VALUETYPE);
+ }
+
+ bool isFixedLengthVector() const {
+ return (SimpleTy >= MVT::FIRST_FIXEDLEN_VECTOR_VALUETYPE &&
+ SimpleTy <= MVT::LAST_FIXEDLEN_VECTOR_VALUETYPE);
+ }
+
+ /// Return true if this is a 16-bit vector type.
+ bool is16BitVector() const {
+ return (SimpleTy == MVT::v2i8 || SimpleTy == MVT::v1i16 ||
+ SimpleTy == MVT::v16i1 || SimpleTy == MVT::v1f16);
+ }
+
+ /// Return true if this is a 32-bit vector type.
+ bool is32BitVector() const {
+ return (SimpleTy == MVT::v32i1 || SimpleTy == MVT::v4i8 ||
+ SimpleTy == MVT::v2i16 || SimpleTy == MVT::v1i32 ||
+ SimpleTy == MVT::v2f16 || SimpleTy == MVT::v2bf16 ||
+ SimpleTy == MVT::v1f32);
+ }
+
+ /// Return true if this is a 64-bit vector type.
+ bool is64BitVector() const {
+ return (SimpleTy == MVT::v64i1 || SimpleTy == MVT::v8i8 ||
+ SimpleTy == MVT::v4i16 || SimpleTy == MVT::v2i32 ||
+ SimpleTy == MVT::v1i64 || SimpleTy == MVT::v4f16 ||
+ SimpleTy == MVT::v4bf16 ||SimpleTy == MVT::v2f32 ||
+ SimpleTy == MVT::v1f64);
+ }
+
+ /// Return true if this is a 128-bit vector type.
+ bool is128BitVector() const {
+ return (SimpleTy == MVT::v128i1 || SimpleTy == MVT::v16i8 ||
+ SimpleTy == MVT::v8i16 || SimpleTy == MVT::v4i32 ||
+ SimpleTy == MVT::v2i64 || SimpleTy == MVT::v1i128 ||
+ SimpleTy == MVT::v8f16 || SimpleTy == MVT::v8bf16 ||
+ SimpleTy == MVT::v4f32 || SimpleTy == MVT::v2f64);
+ }
+
+ /// Return true if this is a 256-bit vector type.
+ bool is256BitVector() const {
+ return (SimpleTy == MVT::v16f16 || SimpleTy == MVT::v16bf16 ||
+ SimpleTy == MVT::v8f32 || SimpleTy == MVT::v4f64 ||
+ SimpleTy == MVT::v32i8 || SimpleTy == MVT::v16i16 ||
+ SimpleTy == MVT::v8i32 || SimpleTy == MVT::v4i64 ||
+ SimpleTy == MVT::v256i1 || SimpleTy == MVT::v128i2 ||
+ SimpleTy == MVT::v64i4);
+ }
+
+ /// Return true if this is a 512-bit vector type.
+ bool is512BitVector() const {
+ return (SimpleTy == MVT::v32f16 || SimpleTy == MVT::v32bf16 ||
+ SimpleTy == MVT::v16f32 || SimpleTy == MVT::v8f64 ||
+ SimpleTy == MVT::v512i1 || SimpleTy == MVT::v256i2 ||
+ SimpleTy == MVT::v128i4 || SimpleTy == MVT::v64i8 ||
+ SimpleTy == MVT::v32i16 || SimpleTy == MVT::v16i32 ||
+ SimpleTy == MVT::v8i64);
+ }
+
+ /// Return true if this is a 1024-bit vector type.
+ bool is1024BitVector() const {
+ return (SimpleTy == MVT::v1024i1 || SimpleTy == MVT::v128i8 ||
+ SimpleTy == MVT::v64i16 || SimpleTy == MVT::v32i32 ||
+ SimpleTy == MVT::v16i64 || SimpleTy == MVT::v64f16 ||
+ SimpleTy == MVT::v32f32 || SimpleTy == MVT::v16f64 ||
+ SimpleTy == MVT::v64bf16);
+ }
+
+ /// Return true if this is a 2048-bit vector type.
+ bool is2048BitVector() const {
+ return (SimpleTy == MVT::v256i8 || SimpleTy == MVT::v128i16 ||
+ SimpleTy == MVT::v64i32 || SimpleTy == MVT::v32i64 ||
+ SimpleTy == MVT::v128f16 || SimpleTy == MVT::v64f32 ||
+ SimpleTy == MVT::v32f64 || SimpleTy == MVT::v128bf16 ||
+ SimpleTy == MVT::v2048i1);
+ }
+
+ /// Return true if this is an overloaded type for TableGen.
+ bool isOverloaded() const {
+ return (SimpleTy == MVT::Any || SimpleTy == MVT::iAny ||
+ SimpleTy == MVT::fAny || SimpleTy == MVT::vAny ||
+ SimpleTy == MVT::iPTRAny);
+ }
+
+ /// Return a vector with the same number of elements as this vector, but
+ /// with the element type converted to an integer type with the same
+ /// bitwidth.
+ MVT changeVectorElementTypeToInteger() const {
+ MVT EltTy = getVectorElementType();
+ MVT IntTy = MVT::getIntegerVT(EltTy.getSizeInBits());
+ MVT VecTy = MVT::getVectorVT(IntTy, getVectorElementCount());
+ assert(VecTy.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE &&
+ "Simple vector VT not representable by simple integer vector VT!");
+ return VecTy;
+ }
+
+ /// Return a VT for a vector type whose attributes match ourselves
+ /// with the exception of the element type that is chosen by the caller.
+ MVT changeVectorElementType(MVT EltVT) const {
+ MVT VecTy = MVT::getVectorVT(EltVT, getVectorElementCount());
+ assert(VecTy.SimpleTy != MVT::INVALID_SIMPLE_VALUE_TYPE &&
+ "Simple vector VT not representable by simple integer vector VT!");
+ return VecTy;
+ }
+
+ /// Return the type converted to an equivalently sized integer or vector
+ /// with integer element type. Similar to changeVectorElementTypeToInteger,
+ /// but also handles scalars.
+ MVT changeTypeToInteger() {
+ if (isVector())
+ return changeVectorElementTypeToInteger();
+ return MVT::getIntegerVT(getSizeInBits());
+ }
+
+ /// Return a VT for a vector type with the same element type but
+ /// half the number of elements.
+ MVT getHalfNumVectorElementsVT() const {
+ MVT EltVT = getVectorElementType();
+ auto EltCnt = getVectorElementCount();
+ assert(EltCnt.isKnownEven() && "Splitting vector, but not in half!");
+ return getVectorVT(EltVT, EltCnt.divideCoefficientBy(2));
+ }
+
+ /// Returns true if the given vector is a power of 2.
+ bool isPow2VectorType() const {
+ unsigned NElts = getVectorMinNumElements();
+ return !(NElts & (NElts - 1));
+ }
+
+ /// Widens the length of the given vector MVT up to the nearest power of 2
+ /// and returns that type.
+ MVT getPow2VectorType() const {
+ if (isPow2VectorType())
+ return *this;
+
+ ElementCount NElts = getVectorElementCount();
+ unsigned NewMinCount = 1 << Log2_32_Ceil(NElts.getKnownMinValue());
+ NElts = ElementCount::get(NewMinCount, NElts.isScalable());
+ return MVT::getVectorVT(getVectorElementType(), NElts);
+ }
+
+ /// If this is a vector, return the element type, otherwise return this.
+ MVT getScalarType() const {
+ return isVector() ? getVectorElementType() : *this;
+ }
+
+ MVT getVectorElementType() const {
+ // clang-format off
+ switch (SimpleTy) {
+ default:
+ llvm_unreachable("Not a vector MVT!");
+ case v1i1:
+ case v2i1:
+ case v4i1:
+ case v8i1:
+ case v16i1:
+ case v32i1:
+ case v64i1:
+ case v128i1:
+ case v256i1:
+ case v512i1:
+ case v1024i1:
+ case v2048i1:
+ case nxv1i1:
+ case nxv2i1:
+ case nxv4i1:
+ case nxv8i1:
+ case nxv16i1:
+ case nxv32i1:
+ case nxv64i1: return i1;
+ case v128i2:
+ case v256i2: return i2;
+ case v64i4:
+ case v128i4: return i4;
+ case v1i8:
+ case v2i8:
+ case v4i8:
+ case v8i8:
+ case v16i8:
+ case v32i8:
+ case v64i8:
+ case v128i8:
+ case v256i8:
+ case v512i8:
+ case v1024i8:
+ case nxv1i8:
+ case nxv2i8:
+ case nxv4i8:
+ case nxv8i8:
+ case nxv16i8:
+ case nxv32i8:
+ case nxv64i8: return i8;
+ case v1i16:
+ case v2i16:
+ case v3i16:
+ case v4i16:
+ case v8i16:
+ case v16i16:
+ case v32i16:
+ case v64i16:
+ case v128i16:
+ case v256i16:
+ case v512i16:
+ case nxv1i16:
+ case nxv2i16:
+ case nxv4i16:
+ case nxv8i16:
+ case nxv16i16:
+ case nxv32i16: return i16;
+ case v1i32:
+ case v2i32:
+ case v3i32:
+ case v4i32:
+ case v5i32:
+ case v6i32:
+ case v7i32:
+ case v8i32:
+ case v9i32:
+ case v10i32:
+ case v11i32:
+ case v12i32:
+ case v16i32:
+ case v32i32:
+ case v64i32:
+ case v128i32:
+ case v256i32:
+ case v512i32:
+ case v1024i32:
+ case v2048i32:
+ case nxv1i32:
+ case nxv2i32:
+ case nxv4i32:
+ case nxv8i32:
+ case nxv16i32:
+ case nxv32i32: return i32;
+ case v1i64:
+ case v2i64:
+ case v3i64:
+ case v4i64:
+ case v8i64:
+ case v16i64:
+ case v32i64:
+ case v64i64:
+ case v128i64:
+ case v256i64:
+ case nxv1i64:
+ case nxv2i64:
+ case nxv4i64:
+ case nxv8i64:
+ case nxv16i64:
+ case nxv32i64: return i64;
+ case v1i128: return i128;
+ case v1f16:
+ case v2f16:
+ case v3f16:
+ case v4f16:
+ case v8f16:
+ case v16f16:
+ case v32f16:
+ case v64f16:
+ case v128f16:
+ case v256f16:
+ case v512f16:
+ case nxv1f16:
+ case nxv2f16:
+ case nxv4f16:
+ case nxv8f16:
+ case nxv16f16:
+ case nxv32f16: return f16;
+ case v2bf16:
+ case v3bf16:
+ case v4bf16:
+ case v8bf16:
+ case v16bf16:
+ case v32bf16:
+ case v64bf16:
+ case v128bf16:
+ case nxv1bf16:
+ case nxv2bf16:
+ case nxv4bf16:
+ case nxv8bf16:
+ case nxv16bf16:
+ case nxv32bf16: return bf16;
+ case v1f32:
+ case v2f32:
+ case v3f32:
+ case v4f32:
+ case v5f32:
+ case v6f32:
+ case v7f32:
+ case v8f32:
+ case v9f32:
+ case v10f32:
+ case v11f32:
+ case v12f32:
+ case v16f32:
+ case v32f32:
+ case v64f32:
+ case v128f32:
+ case v256f32:
+ case v512f32:
+ case v1024f32:
+ case v2048f32:
+ case nxv1f32:
+ case nxv2f32:
+ case nxv4f32:
+ case nxv8f32:
+ case nxv16f32: return f32;
+ case v1f64:
+ case v2f64:
+ case v3f64:
+ case v4f64:
+ case v8f64:
+ case v16f64:
+ case v32f64:
+ case v64f64:
+ case v128f64:
+ case v256f64:
+ case nxv1f64:
+ case nxv2f64:
+ case nxv4f64:
+ case nxv8f64: return f64;
+ }
+ // clang-format on
+ }
+
+ /// Given a vector type, return the minimum number of elements it contains.
+ unsigned getVectorMinNumElements() const {
+ switch (SimpleTy) {
+ default:
+ llvm_unreachable("Not a vector MVT!");
+ case v2048i1:
+ case v2048i32:
+ case v2048f32: return 2048;
+ case v1024i1:
+ case v1024i8:
+ case v1024i32:
+ case v1024f32: return 1024;
+ case v512i1:
+ case v512i8:
+ case v512i16:
+ case v512i32:
+ case v512f16:
+ case v512f32: return 512;
+ case v256i1:
+ case v256i2:
+ case v256i8:
+ case v256i16:
+ case v256f16:
+ case v256i32:
+ case v256i64:
+ case v256f32:
+ case v256f64: return 256;
+ case v128i1:
+ case v128i2:
+ case v128i4:
+ case v128i8:
+ case v128i16:
+ case v128i32:
+ case v128i64:
+ case v128f16:
+ case v128bf16:
+ case v128f32:
+ case v128f64: return 128;
+ case v64i1:
+ case v64i4:
+ case v64i8:
+ case v64i16:
+ case v64i32:
+ case v64i64:
+ case v64f16:
+ case v64bf16:
+ case v64f32:
+ case v64f64:
+ case nxv64i1:
+ case nxv64i8: return 64;
+ case v32i1:
+ case v32i8:
+ case v32i16:
+ case v32i32:
+ case v32i64:
+ case v32f16:
+ case v32bf16:
+ case v32f32:
+ case v32f64:
+ case nxv32i1:
+ case nxv32i8:
+ case nxv32i16:
+ case nxv32i32:
+ case nxv32i64:
+ case nxv32f16:
+ case nxv32bf16: return 32;
+ case v16i1:
+ case v16i8:
+ case v16i16:
+ case v16i32:
+ case v16i64:
+ case v16f16:
+ case v16bf16:
+ case v16f32:
+ case v16f64:
+ case nxv16i1:
+ case nxv16i8:
+ case nxv16i16:
+ case nxv16i32:
+ case nxv16i64:
+ case nxv16f16:
+ case nxv16bf16:
+ case nxv16f32: return 16;
+ case v12i32:
+ case v12f32: return 12;
+ case v11i32:
+ case v11f32: return 11;
+ case v10i32:
+ case v10f32: return 10;
+ case v9i32:
+ case v9f32: return 9;
+ case v8i1:
+ case v8i8:
+ case v8i16:
+ case v8i32:
+ case v8i64:
+ case v8f16:
+ case v8bf16:
+ case v8f32:
+ case v8f64:
+ case nxv8i1:
+ case nxv8i8:
+ case nxv8i16:
+ case nxv8i32:
+ case nxv8i64:
+ case nxv8f16:
+ case nxv8bf16:
+ case nxv8f32:
+ case nxv8f64: return 8;
+ case v7i32:
+ case v7f32: return 7;
+ case v6i32:
+ case v6f32: return 6;
+ case v5i32:
+ case v5f32: return 5;
+ case v4i1:
+ case v4i8:
+ case v4i16:
+ case v4i32:
+ case v4i64:
+ case v4f16:
+ case v4bf16:
+ case v4f32:
+ case v4f64:
+ case nxv4i1:
+ case nxv4i8:
+ case nxv4i16:
+ case nxv4i32:
+ case nxv4i64:
+ case nxv4f16:
+ case nxv4bf16:
+ case nxv4f32:
+ case nxv4f64: return 4;
+ case v3i16:
+ case v3i32:
+ case v3i64:
+ case v3f16:
+ case v3bf16:
+ case v3f32:
+ case v3f64: return 3;
+ case v2i1:
+ case v2i8:
+ case v2i16:
+ case v2i32:
+ case v2i64:
+ case v2f16:
+ case v2bf16:
+ case v2f32:
+ case v2f64:
+ case nxv2i1:
+ case nxv2i8:
+ case nxv2i16:
+ case nxv2i32:
+ case nxv2i64:
+ case nxv2f16:
+ case nxv2bf16:
+ case nxv2f32:
+ case nxv2f64: return 2;
+ case v1i1:
+ case v1i8:
+ case v1i16:
+ case v1i32:
+ case v1i64:
+ case v1i128:
+ case v1f16:
+ case v1f32:
+ case v1f64:
+ case nxv1i1:
+ case nxv1i8:
+ case nxv1i16:
+ case nxv1i32:
+ case nxv1i64:
+ case nxv1f16:
+ case nxv1bf16:
+ case nxv1f32:
+ case nxv1f64: return 1;
+ }
+ }
+
+ ElementCount getVectorElementCount() const {
+ return ElementCount::get(getVectorMinNumElements(), isScalableVector());
+ }
+
+ unsigned getVectorNumElements() const {
+ if (isScalableVector())
+ llvm::reportInvalidSizeRequest(
+ "Possible incorrect use of MVT::getVectorNumElements() for "
+ "scalable vector. Scalable flag may be dropped, use "
+ "MVT::getVectorElementCount() instead");
+ return getVectorMinNumElements();
+ }
+
+ /// Returns the size of the specified MVT in bits.
+ ///
+ /// If the value type is a scalable vector type, the scalable property will
+ /// be set and the runtime size will be a positive integer multiple of the
+ /// base size.
+ TypeSize getSizeInBits() const {
+ switch (SimpleTy) {
+ default:
+ llvm_unreachable("getSizeInBits called on extended MVT.");
+ case Other:
+ llvm_unreachable("Value type is non-standard value, Other.");
+ case iPTR:
+ llvm_unreachable("Value type size is target-dependent. Ask TLI.");
+ case iPTRAny:
+ case iAny:
+ case fAny:
+ case vAny:
+ case Any:
+ llvm_unreachable("Value type is overloaded.");
+ case token:
+ llvm_unreachable("Token type is a sentinel that cannot be used "
+ "in codegen and has no size");
+ case Metadata:
+ llvm_unreachable("Value type is metadata.");
+ case i1:
+ case v1i1: return TypeSize::Fixed(1);
+ case nxv1i1: return TypeSize::Scalable(1);
+ case i2:
+ case v2i1: return TypeSize::Fixed(2);
+ case nxv2i1: return TypeSize::Scalable(2);
+ case i4:
+ case v4i1: return TypeSize::Fixed(4);
+ case nxv4i1: return TypeSize::Scalable(4);
+ case i8 :
+ case v1i8:
+ case v8i1: return TypeSize::Fixed(8);
+ case nxv1i8:
+ case nxv8i1: return TypeSize::Scalable(8);
+ case i16 :
+ case f16:
+ case bf16:
+ case v16i1:
+ case v2i8:
+ case v1i16:
+ case v1f16: return TypeSize::Fixed(16);
+ case nxv16i1:
+ case nxv2i8:
+ case nxv1i16:
+ case nxv1bf16:
+ case nxv1f16: return TypeSize::Scalable(16);
+ case f32 :
+ case i32 :
+ case v32i1:
+ case v4i8:
+ case v2i16:
+ case v2f16:
+ case v2bf16:
+ case v1f32:
+ case v1i32: return TypeSize::Fixed(32);
+ case nxv32i1:
+ case nxv4i8:
+ case nxv2i16:
+ case nxv1i32:
+ case nxv2f16:
+ case nxv2bf16:
+ case nxv1f32: return TypeSize::Scalable(32);
+ case v3i16:
+ case v3f16:
+ case v3bf16: return TypeSize::Fixed(48);
+ case x86mmx:
+ case f64 :
+ case i64 :
+ case v64i1:
+ case v8i8:
+ case v4i16:
+ case v2i32:
+ case v1i64:
+ case v4f16:
+ case v4bf16:
+ case v2f32:
+ case v1f64: return TypeSize::Fixed(64);
+ case nxv64i1:
+ case nxv8i8:
+ case nxv4i16:
+ case nxv2i32:
+ case nxv1i64:
+ case nxv4f16:
+ case nxv4bf16:
+ case nxv2f32:
+ case nxv1f64: return TypeSize::Scalable(64);
+ case f80 : return TypeSize::Fixed(80);
+ case v3i32:
+ case v3f32: return TypeSize::Fixed(96);
+ case f128:
+ case ppcf128:
+ case i128:
+ case v128i1:
+ case v16i8:
+ case v8i16:
+ case v4i32:
+ case v2i64:
+ case v1i128:
+ case v8f16:
+ case v8bf16:
+ case v4f32:
+ case v2f64: return TypeSize::Fixed(128);
+ case nxv16i8:
+ case nxv8i16:
+ case nxv4i32:
+ case nxv2i64:
+ case nxv8f16:
+ case nxv8bf16:
+ case nxv4f32:
+ case nxv2f64: return TypeSize::Scalable(128);
+ case v5i32:
+ case v5f32: return TypeSize::Fixed(160);
+ case v6i32:
+ case v3i64:
+ case v6f32:
+ case v3f64: return TypeSize::Fixed(192);
+ case v7i32:
+ case v7f32: return TypeSize::Fixed(224);
+ case v256i1:
+ case v128i2:
+ case v64i4:
+ case v32i8:
+ case v16i16:
+ case v8i32:
+ case v4i64:
+ case v16f16:
+ case v16bf16:
+ case v8f32:
+ case v4f64: return TypeSize::Fixed(256);
+ case nxv32i8:
+ case nxv16i16:
+ case nxv8i32:
+ case nxv4i64:
+ case nxv16f16:
+ case nxv16bf16:
+ case nxv8f32:
+ case nxv4f64: return TypeSize::Scalable(256);
+ case v9i32:
+ case v9f32: return TypeSize::Fixed(288);
+ case v10i32:
+ case v10f32: return TypeSize::Fixed(320);
+ case v11i32:
+ case v11f32: return TypeSize::Fixed(352);
+ case v12i32:
+ case v12f32: return TypeSize::Fixed(384);
+ case i64x8:
+ case v512i1:
+ case v256i2:
+ case v128i4:
+ case v64i8:
+ case v32i16:
+ case v16i32:
+ case v8i64:
+ case v32f16:
+ case v32bf16:
+ case v16f32:
+ case v8f64: return TypeSize::Fixed(512);
+ case nxv64i8:
+ case nxv32i16:
+ case nxv16i32:
+ case nxv8i64:
+ case nxv32f16:
+ case nxv32bf16:
+ case nxv16f32:
+ case nxv8f64: return TypeSize::Scalable(512);
+ case v1024i1:
+ case v128i8:
+ case v64i16:
+ case v32i32:
+ case v16i64:
+ case v64f16:
+ case v64bf16:
+ case v32f32:
+ case v16f64: return TypeSize::Fixed(1024);
+ case nxv32i32:
+ case nxv16i64: return TypeSize::Scalable(1024);
+ case v2048i1:
+ case v256i8:
+ case v128i16:
+ case v64i32:
+ case v32i64:
+ case v128f16:
+ case v128bf16:
+ case v64f32:
+ case v32f64: return TypeSize::Fixed(2048);
+ case nxv32i64: return TypeSize::Scalable(2048);
+ case v512i8:
+ case v256i16:
+ case v128i32:
+ case v64i64:
+ case v256f16:
+ case v128f32:
+ case v64f64: return TypeSize::Fixed(4096);
+ case v1024i8:
+ case v512i16:
+ case v256i32:
+ case v128i64:
+ case v512f16:
+ case v256f32:
+ case x86amx:
+ case v128f64: return TypeSize::Fixed(8192);
+ case v512i32:
+ case v256i64:
+ case v512f32:
+ case v256f64: return TypeSize::Fixed(16384);
+ case v1024i32:
+ case v1024f32: return TypeSize::Fixed(32768);
+ case v2048i32:
+ case v2048f32: return TypeSize::Fixed(65536);
+ case funcref:
+ case externref: return TypeSize::Fixed(0); // opaque type
+ }
+ }
+
+ /// Return the size of the specified fixed width value type in bits. The
+ /// function will assert if the type is scalable.
+ uint64_t getFixedSizeInBits() const {
+ return getSizeInBits().getFixedValue();
+ }
+
+ uint64_t getScalarSizeInBits() const {
+ return getScalarType().getSizeInBits().getFixedValue();
+ }
+
+ /// Return the number of bytes overwritten by a store of the specified value
+ /// type.
+ ///
+ /// If the value type is a scalable vector type, the scalable property will
+ /// be set and the runtime size will be a positive integer multiple of the
+ /// base size.
+ TypeSize getStoreSize() const {
+ TypeSize BaseSize = getSizeInBits();
+ return {(BaseSize.getKnownMinValue() + 7) / 8, BaseSize.isScalable()};
+ }
+
+ // Return the number of bytes overwritten by a store of this value type or
+ // this value type's element type in the case of a vector.
+ uint64_t getScalarStoreSize() const {
+ return getScalarType().getStoreSize().getFixedValue();
+ }
+
+ /// Return the number of bits overwritten by a store of the specified value
+ /// type.
+ ///
+ /// If the value type is a scalable vector type, the scalable property will
+ /// be set and the runtime size will be a positive integer multiple of the
+ /// base size.
+ TypeSize getStoreSizeInBits() const {
+ return getStoreSize() * 8;
+ }
+
+ /// Returns true if the number of bits for the type is a multiple of an
+ /// 8-bit byte.
+ bool isByteSized() const { return getSizeInBits().isKnownMultipleOf(8); }
+
+ /// Return true if we know at compile time this has more bits than VT.
+ bool knownBitsGT(MVT VT) const {
+ return TypeSize::isKnownGT(getSizeInBits(), VT.getSizeInBits());
+ }
+
+ /// Return true if we know at compile time this has more than or the same
+ /// bits as VT.
+ bool knownBitsGE(MVT VT) const {
+ return TypeSize::isKnownGE(getSizeInBits(), VT.getSizeInBits());
+ }
+
+ /// Return true if we know at compile time this has fewer bits than VT.
+ bool knownBitsLT(MVT VT) const {
+ return TypeSize::isKnownLT(getSizeInBits(), VT.getSizeInBits());
+ }
+
+ /// Return true if we know at compile time this has fewer than or the same
+ /// bits as VT.
+ bool knownBitsLE(MVT VT) const {
+ return TypeSize::isKnownLE(getSizeInBits(), VT.getSizeInBits());
+ }
+
+ /// Return true if this has more bits than VT.
+ bool bitsGT(MVT VT) const {
+ assert(isScalableVector() == VT.isScalableVector() &&
+ "Comparison between scalable and fixed types");
+ return knownBitsGT(VT);
+ }
+
+ /// Return true if this has no less bits than VT.
+ bool bitsGE(MVT VT) const {
+ assert(isScalableVector() == VT.isScalableVector() &&
+ "Comparison between scalable and fixed types");
+ return knownBitsGE(VT);
+ }
+
+ /// Return true if this has less bits than VT.
+ bool bitsLT(MVT VT) const {
+ assert(isScalableVector() == VT.isScalableVector() &&
+ "Comparison between scalable and fixed types");
+ return knownBitsLT(VT);
+ }
+
+ /// Return true if this has no more bits than VT.
+ bool bitsLE(MVT VT) const {
+ assert(isScalableVector() == VT.isScalableVector() &&
+ "Comparison between scalable and fixed types");
+ return knownBitsLE(VT);
+ }
+
+ static MVT getFloatingPointVT(unsigned BitWidth) {
+ switch (BitWidth) {
+ default:
+ llvm_unreachable("Bad bit width!");
+ case 16:
+ return MVT::f16;
+ case 32:
+ return MVT::f32;
+ case 64:
+ return MVT::f64;
+ case 80:
+ return MVT::f80;
+ case 128:
+ return MVT::f128;
+ }
+ }
+
+ static MVT getIntegerVT(unsigned BitWidth) {
+ switch (BitWidth) {
+ default:
+ return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE);
+ case 1:
+ return MVT::i1;
+ case 2:
+ return MVT::i2;
+ case 4:
+ return MVT::i4;
+ case 8:
+ return MVT::i8;
+ case 16:
+ return MVT::i16;
+ case 32:
+ return MVT::i32;
+ case 64:
+ return MVT::i64;
+ case 128:
+ return MVT::i128;
+ }
+ }
+
+ static MVT getVectorVT(MVT VT, unsigned NumElements) {
+ // clang-format off
+ switch (VT.SimpleTy) {
+ default:
+ break;
+ case MVT::i1:
+ if (NumElements == 1) return MVT::v1i1;
+ if (NumElements == 2) return MVT::v2i1;
+ if (NumElements == 4) return MVT::v4i1;
+ if (NumElements == 8) return MVT::v8i1;
+ if (NumElements == 16) return MVT::v16i1;
+ if (NumElements == 32) return MVT::v32i1;
+ if (NumElements == 64) return MVT::v64i1;
+ if (NumElements == 128) return MVT::v128i1;
+ if (NumElements == 256) return MVT::v256i1;
+ if (NumElements == 512) return MVT::v512i1;
+ if (NumElements == 1024) return MVT::v1024i1;
+ if (NumElements == 2048) return MVT::v2048i1;
+ break;
+ case MVT::i2:
+ if (NumElements == 128) return MVT::v128i2;
+ if (NumElements == 256) return MVT::v256i2;
+ break;
+ case MVT::i4:
+ if (NumElements == 64) return MVT::v64i4;
+ if (NumElements == 128) return MVT::v128i4;
+ break;
+ case MVT::i8:
+ if (NumElements == 1) return MVT::v1i8;
+ if (NumElements == 2) return MVT::v2i8;
+ if (NumElements == 4) return MVT::v4i8;
+ if (NumElements == 8) return MVT::v8i8;
+ if (NumElements == 16) return MVT::v16i8;
+ if (NumElements == 32) return MVT::v32i8;
+ if (NumElements == 64) return MVT::v64i8;
+ if (NumElements == 128) return MVT::v128i8;
+ if (NumElements == 256) return MVT::v256i8;
+ if (NumElements == 512) return MVT::v512i8;
+ if (NumElements == 1024) return MVT::v1024i8;
+ break;
+ case MVT::i16:
+ if (NumElements == 1) return MVT::v1i16;
+ if (NumElements == 2) return MVT::v2i16;
+ if (NumElements == 3) return MVT::v3i16;
+ if (NumElements == 4) return MVT::v4i16;
+ if (NumElements == 8) return MVT::v8i16;
+ if (NumElements == 16) return MVT::v16i16;
+ if (NumElements == 32) return MVT::v32i16;
+ if (NumElements == 64) return MVT::v64i16;
+ if (NumElements == 128) return MVT::v128i16;
+ if (NumElements == 256) return MVT::v256i16;
+ if (NumElements == 512) return MVT::v512i16;
+ break;
+ case MVT::i32:
+ if (NumElements == 1) return MVT::v1i32;
+ if (NumElements == 2) return MVT::v2i32;
+ if (NumElements == 3) return MVT::v3i32;
+ if (NumElements == 4) return MVT::v4i32;
+ if (NumElements == 5) return MVT::v5i32;
+ if (NumElements == 6) return MVT::v6i32;
+ if (NumElements == 7) return MVT::v7i32;
+ if (NumElements == 8) return MVT::v8i32;
+ if (NumElements == 9) return MVT::v9i32;
+ if (NumElements == 10) return MVT::v10i32;
+ if (NumElements == 11) return MVT::v11i32;
+ if (NumElements == 12) return MVT::v12i32;
+ if (NumElements == 16) return MVT::v16i32;
+ if (NumElements == 32) return MVT::v32i32;
+ if (NumElements == 64) return MVT::v64i32;
+ if (NumElements == 128) return MVT::v128i32;
+ if (NumElements == 256) return MVT::v256i32;
+ if (NumElements == 512) return MVT::v512i32;
+ if (NumElements == 1024) return MVT::v1024i32;
+ if (NumElements == 2048) return MVT::v2048i32;
+ break;
+ case MVT::i64:
+ if (NumElements == 1) return MVT::v1i64;
+ if (NumElements == 2) return MVT::v2i64;
+ if (NumElements == 3) return MVT::v3i64;
+ if (NumElements == 4) return MVT::v4i64;
+ if (NumElements == 8) return MVT::v8i64;
+ if (NumElements == 16) return MVT::v16i64;
+ if (NumElements == 32) return MVT::v32i64;
+ if (NumElements == 64) return MVT::v64i64;
+ if (NumElements == 128) return MVT::v128i64;
+ if (NumElements == 256) return MVT::v256i64;
+ break;
+ case MVT::i128:
+ if (NumElements == 1) return MVT::v1i128;
+ break;
+ case MVT::f16:
+ if (NumElements == 1) return MVT::v1f16;
+ if (NumElements == 2) return MVT::v2f16;
+ if (NumElements == 3) return MVT::v3f16;
+ if (NumElements == 4) return MVT::v4f16;
+ if (NumElements == 8) return MVT::v8f16;
+ if (NumElements == 16) return MVT::v16f16;
+ if (NumElements == 32) return MVT::v32f16;
+ if (NumElements == 64) return MVT::v64f16;
+ if (NumElements == 128) return MVT::v128f16;
+ if (NumElements == 256) return MVT::v256f16;
+ if (NumElements == 512) return MVT::v512f16;
+ break;
+ case MVT::bf16:
+ if (NumElements == 2) return MVT::v2bf16;
+ if (NumElements == 3) return MVT::v3bf16;
+ if (NumElements == 4) return MVT::v4bf16;
+ if (NumElements == 8) return MVT::v8bf16;
+ if (NumElements == 16) return MVT::v16bf16;
+ if (NumElements == 32) return MVT::v32bf16;
+ if (NumElements == 64) return MVT::v64bf16;
+ if (NumElements == 128) return MVT::v128bf16;
+ break;
+ case MVT::f32:
+ if (NumElements == 1) return MVT::v1f32;
+ if (NumElements == 2) return MVT::v2f32;
+ if (NumElements == 3) return MVT::v3f32;
+ if (NumElements == 4) return MVT::v4f32;
+ if (NumElements == 5) return MVT::v5f32;
+ if (NumElements == 6) return MVT::v6f32;
+ if (NumElements == 7) return MVT::v7f32;
+ if (NumElements == 8) return MVT::v8f32;
+ if (NumElements == 9) return MVT::v9f32;
+ if (NumElements == 10) return MVT::v10f32;
+ if (NumElements == 11) return MVT::v11f32;
+ if (NumElements == 12) return MVT::v12f32;
+ if (NumElements == 16) return MVT::v16f32;
+ if (NumElements == 32) return MVT::v32f32;
+ if (NumElements == 64) return MVT::v64f32;
+ if (NumElements == 128) return MVT::v128f32;
+ if (NumElements == 256) return MVT::v256f32;
+ if (NumElements == 512) return MVT::v512f32;
+ if (NumElements == 1024) return MVT::v1024f32;
+ if (NumElements == 2048) return MVT::v2048f32;
+ break;
+ case MVT::f64:
+ if (NumElements == 1) return MVT::v1f64;
+ if (NumElements == 2) return MVT::v2f64;
+ if (NumElements == 3) return MVT::v3f64;
+ if (NumElements == 4) return MVT::v4f64;
+ if (NumElements == 8) return MVT::v8f64;
+ if (NumElements == 16) return MVT::v16f64;
+ if (NumElements == 32) return MVT::v32f64;
+ if (NumElements == 64) return MVT::v64f64;
+ if (NumElements == 128) return MVT::v128f64;
+ if (NumElements == 256) return MVT::v256f64;
+ break;
+ }
+ return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE);
+ // clang-format on
+ }
+
+ static MVT getScalableVectorVT(MVT VT, unsigned NumElements) {
+ switch(VT.SimpleTy) {
+ default:
+ break;
+ case MVT::i1:
+ if (NumElements == 1) return MVT::nxv1i1;
+ if (NumElements == 2) return MVT::nxv2i1;
+ if (NumElements == 4) return MVT::nxv4i1;
+ if (NumElements == 8) return MVT::nxv8i1;
+ if (NumElements == 16) return MVT::nxv16i1;
+ if (NumElements == 32) return MVT::nxv32i1;
+ if (NumElements == 64) return MVT::nxv64i1;
+ break;
+ case MVT::i8:
+ if (NumElements == 1) return MVT::nxv1i8;
+ if (NumElements == 2) return MVT::nxv2i8;
+ if (NumElements == 4) return MVT::nxv4i8;
+ if (NumElements == 8) return MVT::nxv8i8;
+ if (NumElements == 16) return MVT::nxv16i8;
+ if (NumElements == 32) return MVT::nxv32i8;
+ if (NumElements == 64) return MVT::nxv64i8;
+ break;
+ case MVT::i16:
+ if (NumElements == 1) return MVT::nxv1i16;
+ if (NumElements == 2) return MVT::nxv2i16;
+ if (NumElements == 4) return MVT::nxv4i16;
+ if (NumElements == 8) return MVT::nxv8i16;
+ if (NumElements == 16) return MVT::nxv16i16;
+ if (NumElements == 32) return MVT::nxv32i16;
+ break;
+ case MVT::i32:
+ if (NumElements == 1) return MVT::nxv1i32;
+ if (NumElements == 2) return MVT::nxv2i32;
+ if (NumElements == 4) return MVT::nxv4i32;
+ if (NumElements == 8) return MVT::nxv8i32;
+ if (NumElements == 16) return MVT::nxv16i32;
+ if (NumElements == 32) return MVT::nxv32i32;
+ break;
+ case MVT::i64:
+ if (NumElements == 1) return MVT::nxv1i64;
+ if (NumElements == 2) return MVT::nxv2i64;
+ if (NumElements == 4) return MVT::nxv4i64;
+ if (NumElements == 8) return MVT::nxv8i64;
+ if (NumElements == 16) return MVT::nxv16i64;
+ if (NumElements == 32) return MVT::nxv32i64;
+ break;
+ case MVT::f16:
+ if (NumElements == 1) return MVT::nxv1f16;
+ if (NumElements == 2) return MVT::nxv2f16;
+ if (NumElements == 4) return MVT::nxv4f16;
+ if (NumElements == 8) return MVT::nxv8f16;
+ if (NumElements == 16) return MVT::nxv16f16;
+ if (NumElements == 32) return MVT::nxv32f16;
+ break;
+ case MVT::bf16:
+ if (NumElements == 1) return MVT::nxv1bf16;
+ if (NumElements == 2) return MVT::nxv2bf16;
+ if (NumElements == 4) return MVT::nxv4bf16;
+ if (NumElements == 8) return MVT::nxv8bf16;
+ if (NumElements == 16) return MVT::nxv16bf16;
+ if (NumElements == 32) return MVT::nxv32bf16;
+ break;
+ case MVT::f32:
+ if (NumElements == 1) return MVT::nxv1f32;
+ if (NumElements == 2) return MVT::nxv2f32;
+ if (NumElements == 4) return MVT::nxv4f32;
+ if (NumElements == 8) return MVT::nxv8f32;
+ if (NumElements == 16) return MVT::nxv16f32;
+ break;
+ case MVT::f64:
+ if (NumElements == 1) return MVT::nxv1f64;
+ if (NumElements == 2) return MVT::nxv2f64;
+ if (NumElements == 4) return MVT::nxv4f64;
+ if (NumElements == 8) return MVT::nxv8f64;
+ break;
+ }
+ return (MVT::SimpleValueType)(MVT::INVALID_SIMPLE_VALUE_TYPE);
+ }
+
+ static MVT getVectorVT(MVT VT, unsigned NumElements, bool IsScalable) {
+ if (IsScalable)
+ return getScalableVectorVT(VT, NumElements);
+ return getVectorVT(VT, NumElements);
+ }
+
+ static MVT getVectorVT(MVT VT, ElementCount EC) {
+ if (EC.isScalable())
+ return getScalableVectorVT(VT, EC.getKnownMinValue());
+ return getVectorVT(VT, EC.getKnownMinValue());
+ }
+
+ /// Return the value type corresponding to the specified type. This returns
+ /// all pointers as iPTR. If HandleUnknown is true, unknown types are
+ /// returned as Other, otherwise they are invalid.
+ static MVT getVT(Type *Ty, bool HandleUnknown = false);
+
+ public:
+ /// SimpleValueType Iteration
+ /// @{
+ static auto all_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_VALUETYPE, MVT::LAST_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto integer_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_INTEGER_VALUETYPE,
+ MVT::LAST_INTEGER_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto fp_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_FP_VALUETYPE, MVT::LAST_FP_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto vector_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_VECTOR_VALUETYPE,
+ MVT::LAST_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto fixedlen_vector_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_FIXEDLEN_VECTOR_VALUETYPE,
+ MVT::LAST_FIXEDLEN_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto scalable_vector_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_SCALABLE_VECTOR_VALUETYPE,
+ MVT::LAST_SCALABLE_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto integer_fixedlen_vector_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE,
+ MVT::LAST_INTEGER_FIXEDLEN_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto fp_fixedlen_vector_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_FP_FIXEDLEN_VECTOR_VALUETYPE,
+ MVT::LAST_FP_FIXEDLEN_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto integer_scalable_vector_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_INTEGER_SCALABLE_VECTOR_VALUETYPE,
+ MVT::LAST_INTEGER_SCALABLE_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+
+ static auto fp_scalable_vector_valuetypes() {
+ return enum_seq_inclusive(MVT::FIRST_FP_SCALABLE_VECTOR_VALUETYPE,
+ MVT::LAST_FP_SCALABLE_VECTOR_VALUETYPE,
+ force_iteration_on_noniterable_enum);
+ }
+ /// @}
+ };
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_MACHINEVALUETYPE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ManagedStatic.h b/contrib/libs/llvm16/include/llvm/Support/ManagedStatic.h
new file mode 100644
index 00000000000..6a16ad63045
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ManagedStatic.h
@@ -0,0 +1,136 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/ManagedStatic.h - Static Global wrapper ----*- 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 defines the ManagedStatic class and the llvm_shutdown() function.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MANAGEDSTATIC_H
+#define LLVM_SUPPORT_MANAGEDSTATIC_H
+
+#include <atomic>
+#include <cstddef>
+
+namespace llvm {
+
+/// object_creator - Helper method for ManagedStatic.
+template <class C> struct object_creator {
+ static void *call() { return new C(); }
+};
+
+/// object_deleter - Helper method for ManagedStatic.
+///
+template <typename T> struct object_deleter {
+ static void call(void *Ptr) { delete (T *)Ptr; }
+};
+template <typename T, size_t N> struct object_deleter<T[N]> {
+ static void call(void *Ptr) { delete[](T *)Ptr; }
+};
+
+// ManagedStatic must be initialized to zero, and it must *not* have a dynamic
+// initializer because managed statics are often created while running other
+// dynamic initializers. In standard C++11, the best way to accomplish this is
+// with a constexpr default constructor. However, different versions of the
+// Visual C++ compiler have had bugs where, even though the constructor may be
+// constexpr, a dynamic initializer may be emitted depending on optimization
+// settings. For the affected versions of MSVC, use the old linker
+// initialization pattern of not providing a constructor and leaving the fields
+// uninitialized. See http://llvm.org/PR41367 for details.
+#if !defined(_MSC_VER) || (_MSC_VER >= 1925) || defined(__clang__)
+#define LLVM_USE_CONSTEXPR_CTOR
+#endif
+
+/// ManagedStaticBase - Common base class for ManagedStatic instances.
+class ManagedStaticBase {
+protected:
+#ifdef LLVM_USE_CONSTEXPR_CTOR
+ mutable std::atomic<void *> Ptr{};
+ mutable void (*DeleterFn)(void *) = nullptr;
+ mutable const ManagedStaticBase *Next = nullptr;
+#else
+ // This should only be used as a static variable, which guarantees that this
+ // will be zero initialized.
+ mutable std::atomic<void *> Ptr;
+ mutable void (*DeleterFn)(void *);
+ mutable const ManagedStaticBase *Next;
+#endif
+
+ void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
+
+public:
+#ifdef LLVM_USE_CONSTEXPR_CTOR
+ constexpr ManagedStaticBase() = default;
+#endif
+
+ /// isConstructed - Return true if this object has not been created yet.
+ bool isConstructed() const { return Ptr != nullptr; }
+
+ void destroy() const;
+};
+
+/// ManagedStatic - This transparently changes the behavior of global statics to
+/// be lazily constructed on demand (good for reducing startup times of dynamic
+/// libraries that link in LLVM components) and for making destruction be
+/// explicit through the llvm_shutdown() function call.
+///
+template <class C, class Creator = object_creator<C>,
+ class Deleter = object_deleter<C>>
+class ManagedStatic : public ManagedStaticBase {
+public:
+ // Accessors.
+ C &operator*() {
+ void *Tmp = Ptr.load(std::memory_order_acquire);
+ if (!Tmp)
+ RegisterManagedStatic(Creator::call, Deleter::call);
+
+ return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
+ }
+
+ C *operator->() { return &**this; }
+
+ const C &operator*() const {
+ void *Tmp = Ptr.load(std::memory_order_acquire);
+ if (!Tmp)
+ RegisterManagedStatic(Creator::call, Deleter::call);
+
+ return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
+ }
+
+ const C *operator->() const { return &**this; }
+
+ // Extract the instance, leaving the ManagedStatic uninitialized. The
+ // user is then responsible for the lifetime of the returned instance.
+ C *claim() {
+ return static_cast<C *>(Ptr.exchange(nullptr));
+ }
+};
+
+/// llvm_shutdown - Deallocate and destroy all ManagedStatic variables.
+void llvm_shutdown();
+
+/// llvm_shutdown_obj - This is a simple helper class that calls
+/// llvm_shutdown() when it is destroyed.
+struct llvm_shutdown_obj {
+ llvm_shutdown_obj() = default;
+ ~llvm_shutdown_obj() { llvm_shutdown(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_MANAGEDSTATIC_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/MathExtras.h b/contrib/libs/llvm16/include/llvm/Support/MathExtras.h
new file mode 100644
index 00000000000..4c04aa41c76
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/MathExtras.h
@@ -0,0 +1,787 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/MathExtras.h - Useful math functions -------*- 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 some functions that are useful for math stuff.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MATHEXTRAS_H
+#define LLVM_SUPPORT_MATHEXTRAS_H
+
+#include "llvm/ADT/bit.h"
+#include "llvm/Support/Compiler.h"
+#include <cassert>
+#include <climits>
+#include <cstdint>
+#include <cstring>
+#include <limits>
+#include <type_traits>
+
+namespace llvm {
+
+/// The behavior an operation has on an input of 0.
+enum ZeroBehavior {
+ /// The returned value is undefined.
+ ZB_Undefined,
+ /// The returned value is numeric_limits<T>::max()
+ ZB_Max
+};
+
+/// Mathematical constants.
+namespace numbers {
+// TODO: Track C++20 std::numbers.
+// TODO: Favor using the hexadecimal FP constants (requires C++17).
+constexpr double e = 2.7182818284590452354, // (0x1.5bf0a8b145749P+1) https://oeis.org/A001113
+ egamma = .57721566490153286061, // (0x1.2788cfc6fb619P-1) https://oeis.org/A001620
+ ln2 = .69314718055994530942, // (0x1.62e42fefa39efP-1) https://oeis.org/A002162
+ ln10 = 2.3025850929940456840, // (0x1.24bb1bbb55516P+1) https://oeis.org/A002392
+ log2e = 1.4426950408889634074, // (0x1.71547652b82feP+0)
+ log10e = .43429448190325182765, // (0x1.bcb7b1526e50eP-2)
+ pi = 3.1415926535897932385, // (0x1.921fb54442d18P+1) https://oeis.org/A000796
+ inv_pi = .31830988618379067154, // (0x1.45f306bc9c883P-2) https://oeis.org/A049541
+ sqrtpi = 1.7724538509055160273, // (0x1.c5bf891b4ef6bP+0) https://oeis.org/A002161
+ inv_sqrtpi = .56418958354775628695, // (0x1.20dd750429b6dP-1) https://oeis.org/A087197
+ sqrt2 = 1.4142135623730950488, // (0x1.6a09e667f3bcdP+0) https://oeis.org/A00219
+ inv_sqrt2 = .70710678118654752440, // (0x1.6a09e667f3bcdP-1)
+ sqrt3 = 1.7320508075688772935, // (0x1.bb67ae8584caaP+0) https://oeis.org/A002194
+ inv_sqrt3 = .57735026918962576451, // (0x1.279a74590331cP-1)
+ phi = 1.6180339887498948482; // (0x1.9e3779b97f4a8P+0) https://oeis.org/A001622
+constexpr float ef = 2.71828183F, // (0x1.5bf0a8P+1) https://oeis.org/A001113
+ egammaf = .577215665F, // (0x1.2788d0P-1) https://oeis.org/A001620
+ ln2f = .693147181F, // (0x1.62e430P-1) https://oeis.org/A002162
+ ln10f = 2.30258509F, // (0x1.26bb1cP+1) https://oeis.org/A002392
+ log2ef = 1.44269504F, // (0x1.715476P+0)
+ log10ef = .434294482F, // (0x1.bcb7b2P-2)
+ pif = 3.14159265F, // (0x1.921fb6P+1) https://oeis.org/A000796
+ inv_pif = .318309886F, // (0x1.45f306P-2) https://oeis.org/A049541
+ sqrtpif = 1.77245385F, // (0x1.c5bf8aP+0) https://oeis.org/A002161
+ inv_sqrtpif = .564189584F, // (0x1.20dd76P-1) https://oeis.org/A087197
+ sqrt2f = 1.41421356F, // (0x1.6a09e6P+0) https://oeis.org/A002193
+ inv_sqrt2f = .707106781F, // (0x1.6a09e6P-1)
+ sqrt3f = 1.73205081F, // (0x1.bb67aeP+0) https://oeis.org/A002194
+ inv_sqrt3f = .577350269F, // (0x1.279a74P-1)
+ phif = 1.61803399F; // (0x1.9e377aP+0) https://oeis.org/A001622
+} // namespace numbers
+
+/// Count number of 0's from the least significant bit to the most
+/// stopping at the first 1.
+///
+/// Only unsigned integral types are allowed.
+///
+/// Returns std::numeric_limits<T>::digits on an input of 0.
+template <typename T> unsigned countTrailingZeros(T Val) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ return llvm::countr_zero(Val);
+}
+
+/// Count number of 0's from the most significant bit to the least
+/// stopping at the first 1.
+///
+/// Only unsigned integral types are allowed.
+///
+/// Returns std::numeric_limits<T>::digits on an input of 0.
+template <typename T> unsigned countLeadingZeros(T Val) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ return llvm::countl_zero(Val);
+}
+
+/// Get the index of the first set bit starting from the least
+/// significant bit.
+///
+/// Only unsigned integral types are allowed.
+///
+/// \param ZB the behavior on an input of 0.
+template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
+ if (ZB == ZB_Max && Val == 0)
+ return std::numeric_limits<T>::max();
+
+ return llvm::countr_zero(Val);
+}
+
+/// Create a bitmask with the N right-most bits set to 1, and all other
+/// bits set to 0. Only unsigned types are allowed.
+template <typename T> T maskTrailingOnes(unsigned N) {
+ static_assert(std::is_unsigned<T>::value, "Invalid type!");
+ const unsigned Bits = CHAR_BIT * sizeof(T);
+ assert(N <= Bits && "Invalid bit index");
+ return N == 0 ? 0 : (T(-1) >> (Bits - N));
+}
+
+/// Create a bitmask with the N left-most bits set to 1, and all other
+/// bits set to 0. Only unsigned types are allowed.
+template <typename T> T maskLeadingOnes(unsigned N) {
+ return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
+}
+
+/// Create a bitmask with the N right-most bits set to 0, and all other
+/// bits set to 1. Only unsigned types are allowed.
+template <typename T> T maskTrailingZeros(unsigned N) {
+ return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
+}
+
+/// Create a bitmask with the N left-most bits set to 0, and all other
+/// bits set to 1. Only unsigned types are allowed.
+template <typename T> T maskLeadingZeros(unsigned N) {
+ return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
+}
+
+/// Get the index of the last set bit starting from the least
+/// significant bit.
+///
+/// Only unsigned integral types are allowed.
+///
+/// \param ZB the behavior on an input of 0.
+template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
+ if (ZB == ZB_Max && Val == 0)
+ return std::numeric_limits<T>::max();
+
+ // Use ^ instead of - because both gcc and llvm can remove the associated ^
+ // in the __builtin_clz intrinsic on x86.
+ return llvm::countl_zero(Val) ^ (std::numeric_limits<T>::digits - 1);
+}
+
+/// Macro compressed bit reversal table for 256 bits.
+///
+/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
+static const unsigned char BitReverseTable256[256] = {
+#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
+#define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16)
+#define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4)
+ R6(0), R6(2), R6(1), R6(3)
+#undef R2
+#undef R4
+#undef R6
+};
+
+/// Reverse the bits in \p Val.
+template <typename T> T reverseBits(T Val) {
+#if __has_builtin(__builtin_bitreverse8)
+ if constexpr (std::is_same_v<T, uint8_t>)
+ return __builtin_bitreverse8(Val);
+#endif
+#if __has_builtin(__builtin_bitreverse16)
+ if constexpr (std::is_same_v<T, uint16_t>)
+ return __builtin_bitreverse16(Val);
+#endif
+#if __has_builtin(__builtin_bitreverse32)
+ if constexpr (std::is_same_v<T, uint32_t>)
+ return __builtin_bitreverse32(Val);
+#endif
+#if __has_builtin(__builtin_bitreverse64)
+ if constexpr (std::is_same_v<T, uint64_t>)
+ return __builtin_bitreverse64(Val);
+#endif
+
+ unsigned char in[sizeof(Val)];
+ unsigned char out[sizeof(Val)];
+ std::memcpy(in, &Val, sizeof(Val));
+ for (unsigned i = 0; i < sizeof(Val); ++i)
+ out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]];
+ std::memcpy(&Val, out, sizeof(Val));
+ return Val;
+}
+
+// NOTE: The following support functions use the _32/_64 extensions instead of
+// type overloading so that signed and unsigned integers can be used without
+// ambiguity.
+
+/// Return the high 32 bits of a 64 bit value.
+constexpr inline uint32_t Hi_32(uint64_t Value) {
+ return static_cast<uint32_t>(Value >> 32);
+}
+
+/// Return the low 32 bits of a 64 bit value.
+constexpr inline uint32_t Lo_32(uint64_t Value) {
+ return static_cast<uint32_t>(Value);
+}
+
+/// Make a 64-bit integer from a high / low pair of 32-bit integers.
+constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
+ return ((uint64_t)High << 32) | (uint64_t)Low;
+}
+
+/// Checks if an integer fits into the given bit width.
+template <unsigned N> constexpr inline bool isInt(int64_t x) {
+ if constexpr (N == 8)
+ return static_cast<int8_t>(x) == x;
+ if constexpr (N == 16)
+ return static_cast<int16_t>(x) == x;
+ if constexpr (N == 32)
+ return static_cast<int32_t>(x) == x;
+ if constexpr (N < 64)
+ return -(INT64_C(1) << (N - 1)) <= x && x < (INT64_C(1) << (N - 1));
+ (void)x; // MSVC v19.25 warns that x is unused.
+ return true;
+}
+
+/// Checks if a signed integer is an N bit number shifted left by S.
+template <unsigned N, unsigned S>
+constexpr inline bool isShiftedInt(int64_t x) {
+ static_assert(
+ N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
+ static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
+ return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
+}
+
+/// Checks if an unsigned integer fits into the given bit width.
+template <unsigned N> constexpr inline bool isUInt(uint64_t x) {
+ static_assert(N > 0, "isUInt<0> doesn't make sense");
+ if constexpr (N == 8)
+ return static_cast<uint8_t>(x) == x;
+ if constexpr (N == 16)
+ return static_cast<uint16_t>(x) == x;
+ if constexpr (N == 32)
+ return static_cast<uint32_t>(x) == x;
+ if constexpr (N < 64)
+ return x < (UINT64_C(1) << (N));
+ (void)x; // MSVC v19.25 warns that x is unused.
+ return true;
+}
+
+/// Checks if a unsigned integer is an N bit number shifted left by S.
+template <unsigned N, unsigned S>
+constexpr inline bool isShiftedUInt(uint64_t x) {
+ static_assert(
+ N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
+ static_assert(N + S <= 64,
+ "isShiftedUInt<N, S> with N + S > 64 is too wide.");
+ // Per the two static_asserts above, S must be strictly less than 64. So
+ // 1 << S is not undefined behavior.
+ return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
+}
+
+/// Gets the maximum value for a N-bit unsigned integer.
+inline uint64_t maxUIntN(uint64_t N) {
+ assert(N > 0 && N <= 64 && "integer width out of range");
+
+ // uint64_t(1) << 64 is undefined behavior, so we can't do
+ // (uint64_t(1) << N) - 1
+ // without checking first that N != 64. But this works and doesn't have a
+ // branch.
+ return UINT64_MAX >> (64 - N);
+}
+
+/// Gets the minimum value for a N-bit signed integer.
+inline int64_t minIntN(int64_t N) {
+ assert(N > 0 && N <= 64 && "integer width out of range");
+
+ return UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
+}
+
+/// Gets the maximum value for a N-bit signed integer.
+inline int64_t maxIntN(int64_t N) {
+ assert(N > 0 && N <= 64 && "integer width out of range");
+
+ // This relies on two's complement wraparound when N == 64, so we convert to
+ // int64_t only at the very end to avoid UB.
+ return (UINT64_C(1) << (N - 1)) - 1;
+}
+
+/// Checks if an unsigned integer fits into the given (dynamic) bit width.
+inline bool isUIntN(unsigned N, uint64_t x) {
+ return N >= 64 || x <= maxUIntN(N);
+}
+
+/// Checks if an signed integer fits into the given (dynamic) bit width.
+inline bool isIntN(unsigned N, int64_t x) {
+ return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
+}
+
+/// Return true if the argument is a non-empty sequence of ones starting at the
+/// least significant bit with the remainder zero (32 bit version).
+/// Ex. isMask_32(0x0000FFFFU) == true.
+constexpr inline bool isMask_32(uint32_t Value) {
+ return Value && ((Value + 1) & Value) == 0;
+}
+
+/// Return true if the argument is a non-empty sequence of ones starting at the
+/// least significant bit with the remainder zero (64 bit version).
+constexpr inline bool isMask_64(uint64_t Value) {
+ return Value && ((Value + 1) & Value) == 0;
+}
+
+/// Return true if the argument contains a non-empty sequence of ones with the
+/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
+constexpr inline bool isShiftedMask_32(uint32_t Value) {
+ return Value && isMask_32((Value - 1) | Value);
+}
+
+/// Return true if the argument contains a non-empty sequence of ones with the
+/// remainder zero (64 bit version.)
+constexpr inline bool isShiftedMask_64(uint64_t Value) {
+ return Value && isMask_64((Value - 1) | Value);
+}
+
+/// Return true if the argument is a power of two > 0.
+/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
+constexpr inline bool isPowerOf2_32(uint32_t Value) {
+ return llvm::has_single_bit(Value);
+}
+
+/// Return true if the argument is a power of two > 0 (64 bit edition.)
+constexpr inline bool isPowerOf2_64(uint64_t Value) {
+ return llvm::has_single_bit(Value);
+}
+
+/// Count the number of ones from the most significant bit to the first
+/// zero bit.
+///
+/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
+/// Only unsigned integral types are allowed.
+///
+/// Returns std::numeric_limits<T>::digits on an input of all ones.
+template <typename T> unsigned countLeadingOnes(T Value) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ return llvm::countl_one<T>(Value);
+}
+
+/// Count the number of ones from the least significant bit to the first
+/// zero bit.
+///
+/// Ex. countTrailingOnes(0x00FF00FF) == 8.
+/// Only unsigned integral types are allowed.
+///
+/// Returns std::numeric_limits<T>::digits on an input of all ones.
+template <typename T> unsigned countTrailingOnes(T Value) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ return llvm::countr_one<T>(Value);
+}
+
+/// Count the number of set bits in a value.
+/// Ex. countPopulation(0xF000F000) = 8
+/// Returns 0 if the word is zero.
+template <typename T>
+inline unsigned countPopulation(T Value) {
+ static_assert(std::is_unsigned_v<T>,
+ "Only unsigned integral types are allowed.");
+ return (unsigned)llvm::popcount(Value);
+}
+
+/// Return true if the argument contains a non-empty sequence of ones with the
+/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
+/// If true, \p MaskIdx will specify the index of the lowest set bit and \p
+/// MaskLen is updated to specify the length of the mask, else neither are
+/// updated.
+inline bool isShiftedMask_32(uint32_t Value, unsigned &MaskIdx,
+ unsigned &MaskLen) {
+ if (!isShiftedMask_32(Value))
+ return false;
+ MaskIdx = llvm::countr_zero(Value);
+ MaskLen = llvm::popcount(Value);
+ return true;
+}
+
+/// Return true if the argument contains a non-empty sequence of ones with the
+/// remainder zero (64 bit version.) If true, \p MaskIdx will specify the index
+/// of the lowest set bit and \p MaskLen is updated to specify the length of the
+/// mask, else neither are updated.
+inline bool isShiftedMask_64(uint64_t Value, unsigned &MaskIdx,
+ unsigned &MaskLen) {
+ if (!isShiftedMask_64(Value))
+ return false;
+ MaskIdx = llvm::countr_zero(Value);
+ MaskLen = llvm::popcount(Value);
+ return true;
+}
+
+/// Compile time Log2.
+/// Valid only for positive powers of two.
+template <size_t kValue> constexpr inline size_t CTLog2() {
+ static_assert(kValue > 0 && llvm::isPowerOf2_64(kValue),
+ "Value is not a valid power of 2");
+ return 1 + CTLog2<kValue / 2>();
+}
+
+template <> constexpr inline size_t CTLog2<1>() { return 0; }
+
+/// Return the floor log base 2 of the specified value, -1 if the value is zero.
+/// (32 bit edition.)
+/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
+inline unsigned Log2_32(uint32_t Value) {
+ return 31 - llvm::countl_zero(Value);
+}
+
+/// Return the floor log base 2 of the specified value, -1 if the value is zero.
+/// (64 bit edition.)
+inline unsigned Log2_64(uint64_t Value) {
+ return 63 - llvm::countl_zero(Value);
+}
+
+/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
+/// (32 bit edition).
+/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
+inline unsigned Log2_32_Ceil(uint32_t Value) {
+ return 32 - llvm::countl_zero(Value - 1);
+}
+
+/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
+/// (64 bit edition.)
+inline unsigned Log2_64_Ceil(uint64_t Value) {
+ return 64 - llvm::countl_zero(Value - 1);
+}
+
+/// This function takes a 64-bit integer and returns the bit equivalent double.
+inline double BitsToDouble(uint64_t Bits) {
+ static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
+ return llvm::bit_cast<double>(Bits);
+}
+
+/// This function takes a 32-bit integer and returns the bit equivalent float.
+inline float BitsToFloat(uint32_t Bits) {
+ static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
+ return llvm::bit_cast<float>(Bits);
+}
+
+/// This function takes a double and returns the bit equivalent 64-bit integer.
+/// Note that copying doubles around changes the bits of NaNs on some hosts,
+/// notably x86, so this routine cannot be used if these bits are needed.
+inline uint64_t DoubleToBits(double Double) {
+ static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
+ return llvm::bit_cast<uint64_t>(Double);
+}
+
+/// This function takes a float and returns the bit equivalent 32-bit integer.
+/// Note that copying floats around changes the bits of NaNs on some hosts,
+/// notably x86, so this routine cannot be used if these bits are needed.
+inline uint32_t FloatToBits(float Float) {
+ static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
+ return llvm::bit_cast<uint32_t>(Float);
+}
+
+/// A and B are either alignments or offsets. Return the minimum alignment that
+/// may be assumed after adding the two together.
+constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
+ // The largest power of 2 that divides both A and B.
+ //
+ // Replace "-Value" by "1+~Value" in the following commented code to avoid
+ // MSVC warning C4146
+ // return (A | B) & -(A | B);
+ return (A | B) & (1 + ~(A | B));
+}
+
+/// Returns the next power of two (in 64-bits) that is strictly greater than A.
+/// Returns zero on overflow.
+constexpr inline uint64_t NextPowerOf2(uint64_t A) {
+ A |= (A >> 1);
+ A |= (A >> 2);
+ A |= (A >> 4);
+ A |= (A >> 8);
+ A |= (A >> 16);
+ A |= (A >> 32);
+ return A + 1;
+}
+
+/// Returns the power of two which is less than or equal to the given value.
+/// Essentially, it is a floor operation across the domain of powers of two.
+inline uint64_t PowerOf2Floor(uint64_t A) {
+ return llvm::bit_floor(A);
+}
+
+/// Returns the power of two which is greater than or equal to the given value.
+/// Essentially, it is a ceil operation across the domain of powers of two.
+inline uint64_t PowerOf2Ceil(uint64_t A) {
+ if (!A)
+ return 0;
+ return NextPowerOf2(A - 1);
+}
+
+/// Returns the next integer (mod 2**64) that is greater than or equal to
+/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
+///
+/// Examples:
+/// \code
+/// alignTo(5, 8) = 8
+/// alignTo(17, 8) = 24
+/// alignTo(~0LL, 8) = 0
+/// alignTo(321, 255) = 510
+/// \endcode
+inline uint64_t alignTo(uint64_t Value, uint64_t Align) {
+ assert(Align != 0u && "Align can't be 0.");
+ return (Value + Align - 1) / Align * Align;
+}
+
+inline uint64_t alignToPowerOf2(uint64_t Value, uint64_t Align) {
+ assert(Align != 0 && (Align & (Align - 1)) == 0 &&
+ "Align must be a power of 2");
+ return (Value + Align - 1) & -Align;
+}
+
+/// If non-zero \p Skew is specified, the return value will be a minimal integer
+/// that is greater than or equal to \p Size and equal to \p A * N + \p Skew for
+/// some integer N. If \p Skew is larger than \p A, its value is adjusted to '\p
+/// Skew mod \p A'. \p Align must be non-zero.
+///
+/// Examples:
+/// \code
+/// alignTo(5, 8, 7) = 7
+/// alignTo(17, 8, 1) = 17
+/// alignTo(~0LL, 8, 3) = 3
+/// alignTo(321, 255, 42) = 552
+/// \endcode
+inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew) {
+ assert(Align != 0u && "Align can't be 0.");
+ Skew %= Align;
+ return alignTo(Value - Skew, Align) + Skew;
+}
+
+/// Returns the next integer (mod 2**64) that is greater than or equal to
+/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
+template <uint64_t Align> constexpr inline uint64_t alignTo(uint64_t Value) {
+ static_assert(Align != 0u, "Align must be non-zero");
+ return (Value + Align - 1) / Align * Align;
+}
+
+/// Returns the integer ceil(Numerator / Denominator).
+inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
+ return alignTo(Numerator, Denominator) / Denominator;
+}
+
+/// Returns the integer nearest(Numerator / Denominator).
+inline uint64_t divideNearest(uint64_t Numerator, uint64_t Denominator) {
+ return (Numerator + (Denominator / 2)) / Denominator;
+}
+
+/// Returns the largest uint64_t less than or equal to \p Value and is
+/// \p Skew mod \p Align. \p Align must be non-zero
+inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
+ assert(Align != 0u && "Align can't be 0.");
+ Skew %= Align;
+ return (Value - Skew) / Align * Align + Skew;
+}
+
+/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
+/// Requires 0 < B <= 32.
+template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
+ static_assert(B > 0, "Bit width can't be 0.");
+ static_assert(B <= 32, "Bit width out of range.");
+ return int32_t(X << (32 - B)) >> (32 - B);
+}
+
+/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
+/// Requires 0 < B <= 32.
+inline int32_t SignExtend32(uint32_t X, unsigned B) {
+ assert(B > 0 && "Bit width can't be 0.");
+ assert(B <= 32 && "Bit width out of range.");
+ return int32_t(X << (32 - B)) >> (32 - B);
+}
+
+/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
+/// Requires 0 < B <= 64.
+template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
+ static_assert(B > 0, "Bit width can't be 0.");
+ static_assert(B <= 64, "Bit width out of range.");
+ return int64_t(x << (64 - B)) >> (64 - B);
+}
+
+/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
+/// Requires 0 < B <= 64.
+inline int64_t SignExtend64(uint64_t X, unsigned B) {
+ assert(B > 0 && "Bit width can't be 0.");
+ assert(B <= 64 && "Bit width out of range.");
+ return int64_t(X << (64 - B)) >> (64 - B);
+}
+
+/// Subtract two unsigned integers, X and Y, of type T and return the absolute
+/// value of the result.
+template <typename T>
+std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) {
+ return X > Y ? (X - Y) : (Y - X);
+}
+
+/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
+/// maximum representable value of T on overflow. ResultOverflowed indicates if
+/// the result is larger than the maximum representable value of type T.
+template <typename T>
+std::enable_if_t<std::is_unsigned<T>::value, T>
+SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
+ bool Dummy;
+ bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
+ // Hacker's Delight, p. 29
+ T Z = X + Y;
+ Overflowed = (Z < X || Z < Y);
+ if (Overflowed)
+ return std::numeric_limits<T>::max();
+ else
+ return Z;
+}
+
+/// Add multiple unsigned integers of type T. Clamp the result to the
+/// maximum representable value of T on overflow.
+template <class T, class... Ts>
+std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(T X, T Y, T Z,
+ Ts... Args) {
+ bool Overflowed = false;
+ T XY = SaturatingAdd(X, Y, &Overflowed);
+ if (Overflowed)
+ return SaturatingAdd(std::numeric_limits<T>::max(), T(1), Args...);
+ return SaturatingAdd(XY, Z, Args...);
+}
+
+/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the
+/// maximum representable value of T on overflow. ResultOverflowed indicates if
+/// the result is larger than the maximum representable value of type T.
+template <typename T>
+std::enable_if_t<std::is_unsigned<T>::value, T>
+SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
+ bool Dummy;
+ bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
+
+ // Hacker's Delight, p. 30 has a different algorithm, but we don't use that
+ // because it fails for uint16_t (where multiplication can have undefined
+ // behavior due to promotion to int), and requires a division in addition
+ // to the multiplication.
+
+ Overflowed = false;
+
+ // Log2(Z) would be either Log2Z or Log2Z + 1.
+ // Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z
+ // will necessarily be less than Log2Max as desired.
+ int Log2Z = Log2_64(X) + Log2_64(Y);
+ const T Max = std::numeric_limits<T>::max();
+ int Log2Max = Log2_64(Max);
+ if (Log2Z < Log2Max) {
+ return X * Y;
+ }
+ if (Log2Z > Log2Max) {
+ Overflowed = true;
+ return Max;
+ }
+
+ // We're going to use the top bit, and maybe overflow one
+ // bit past it. Multiply all but the bottom bit then add
+ // that on at the end.
+ T Z = (X >> 1) * Y;
+ if (Z & ~(Max >> 1)) {
+ Overflowed = true;
+ return Max;
+ }
+ Z <<= 1;
+ if (X & 1)
+ return SaturatingAdd(Z, Y, ResultOverflowed);
+
+ return Z;
+}
+
+/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to
+/// the product. Clamp the result to the maximum representable value of T on
+/// overflow. ResultOverflowed indicates if the result is larger than the
+/// maximum representable value of type T.
+template <typename T>
+std::enable_if_t<std::is_unsigned<T>::value, T>
+SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
+ bool Dummy;
+ bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
+
+ T Product = SaturatingMultiply(X, Y, &Overflowed);
+ if (Overflowed)
+ return Product;
+
+ return SaturatingAdd(A, Product, &Overflowed);
+}
+
+/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
+extern const float huge_valf;
+
+
+/// Add two signed integers, computing the two's complement truncated result,
+/// returning true if overflow occurred.
+template <typename T>
+std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) {
+#if __has_builtin(__builtin_add_overflow)
+ return __builtin_add_overflow(X, Y, &Result);
+#else
+ // Perform the unsigned addition.
+ using U = std::make_unsigned_t<T>;
+ const U UX = static_cast<U>(X);
+ const U UY = static_cast<U>(Y);
+ const U UResult = UX + UY;
+
+ // Convert to signed.
+ Result = static_cast<T>(UResult);
+
+ // Adding two positive numbers should result in a positive number.
+ if (X > 0 && Y > 0)
+ return Result <= 0;
+ // Adding two negatives should result in a negative number.
+ if (X < 0 && Y < 0)
+ return Result >= 0;
+ return false;
+#endif
+}
+
+/// Subtract two signed integers, computing the two's complement truncated
+/// result, returning true if an overflow ocurred.
+template <typename T>
+std::enable_if_t<std::is_signed<T>::value, T> SubOverflow(T X, T Y, T &Result) {
+#if __has_builtin(__builtin_sub_overflow)
+ return __builtin_sub_overflow(X, Y, &Result);
+#else
+ // Perform the unsigned addition.
+ using U = std::make_unsigned_t<T>;
+ const U UX = static_cast<U>(X);
+ const U UY = static_cast<U>(Y);
+ const U UResult = UX - UY;
+
+ // Convert to signed.
+ Result = static_cast<T>(UResult);
+
+ // Subtracting a positive number from a negative results in a negative number.
+ if (X <= 0 && Y > 0)
+ return Result >= 0;
+ // Subtracting a negative number from a positive results in a positive number.
+ if (X >= 0 && Y < 0)
+ return Result <= 0;
+ return false;
+#endif
+}
+
+/// Multiply two signed integers, computing the two's complement truncated
+/// result, returning true if an overflow ocurred.
+template <typename T>
+std::enable_if_t<std::is_signed<T>::value, T> MulOverflow(T X, T Y, T &Result) {
+ // Perform the unsigned multiplication on absolute values.
+ using U = std::make_unsigned_t<T>;
+ const U UX = X < 0 ? (0 - static_cast<U>(X)) : static_cast<U>(X);
+ const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y);
+ const U UResult = UX * UY;
+
+ // Convert to signed.
+ const bool IsNegative = (X < 0) ^ (Y < 0);
+ Result = IsNegative ? (0 - UResult) : UResult;
+
+ // If any of the args was 0, result is 0 and no overflow occurs.
+ if (UX == 0 || UY == 0)
+ return false;
+
+ // UX and UY are in [1, 2^n], where n is the number of digits.
+ // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
+ // positive) divided by an argument compares to the other.
+ if (IsNegative)
+ return UX > (static_cast<U>(std::numeric_limits<T>::max()) + U(1)) / UY;
+ else
+ return UX > (static_cast<U>(std::numeric_limits<T>::max())) / UY;
+}
+
+} // End llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/MemAlloc.h b/contrib/libs/llvm16/include/llvm/Support/MemAlloc.h
new file mode 100644
index 00000000000..b39554baf8b
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/MemAlloc.h
@@ -0,0 +1,98 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines counterparts of C library allocation functions defined in
+/// the namespace 'std'. The new allocation functions crash on allocation
+/// failure instead of returning null pointer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MEMALLOC_H
+#define LLVM_SUPPORT_MEMALLOC_H
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstdlib>
+
+namespace llvm {
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
+ void *Result = std::malloc(Sz);
+ if (Result == nullptr) {
+ // It is implementation-defined whether allocation occurs if the space
+ // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+ // non-zero, if the space requested was zero.
+ if (Sz == 0)
+ return safe_malloc(1);
+ report_bad_alloc_error("Allocation failed");
+ }
+ return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
+ size_t Sz) {
+ void *Result = std::calloc(Count, Sz);
+ if (Result == nullptr) {
+ // It is implementation-defined whether allocation occurs if the space
+ // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+ // non-zero, if the space requested was zero.
+ if (Count == 0 || Sz == 0)
+ return safe_malloc(1);
+ report_bad_alloc_error("Allocation failed");
+ }
+ return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
+ void *Result = std::realloc(Ptr, Sz);
+ if (Result == nullptr) {
+ // It is implementation-defined whether allocation occurs if the space
+ // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+ // non-zero, if the space requested was zero.
+ if (Sz == 0)
+ return safe_malloc(1);
+ report_bad_alloc_error("Allocation failed");
+ }
+ return Result;
+}
+
+/// Allocate a buffer of memory with the given size and alignment.
+///
+/// When the compiler supports aligned operator new, this will use it to to
+/// handle even over-aligned allocations.
+///
+/// However, this doesn't make any attempt to leverage the fancier techniques
+/// like posix_memalign due to portability. It is mostly intended to allow
+/// compatibility with platforms that, after aligned allocation was added, use
+/// reduced default alignment.
+LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
+allocate_buffer(size_t Size, size_t Alignment);
+
+/// Deallocate a buffer of memory with the given size and alignment.
+///
+/// If supported, this will used the sized delete operator. Also if supported,
+/// this will pass the alignment to the delete operator.
+///
+/// The pointer must have been allocated with the corresponding new operator,
+/// most likely using the above helper.
+void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment);
+
+} // namespace llvm
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Memory.h b/contrib/libs/llvm16/include/llvm/Support/Memory.h
new file mode 100644
index 00000000000..3556eeed6f7
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Memory.h
@@ -0,0 +1,192 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Memory.h - Memory Support -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::Memory class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MEMORY_H
+#define LLVM_SUPPORT_MEMORY_H
+
+#include "llvm/Support/DataTypes.h"
+#include <system_error>
+
+namespace llvm {
+
+// Forward declare raw_ostream: it is used for debug dumping below.
+class raw_ostream;
+
+namespace sys {
+
+ /// This class encapsulates the notion of a memory block which has an address
+ /// and a size. It is used by the Memory class (a friend) as the result of
+ /// various memory allocation operations.
+ /// @see Memory
+ /// Memory block abstraction.
+ class MemoryBlock {
+ public:
+ MemoryBlock() : Address(nullptr), AllocatedSize(0) {}
+ MemoryBlock(void *addr, size_t allocatedSize)
+ : Address(addr), AllocatedSize(allocatedSize) {}
+ void *base() const { return Address; }
+ /// The size as it was allocated. This is always greater or equal to the
+ /// size that was originally requested.
+ size_t allocatedSize() const { return AllocatedSize; }
+
+ private:
+ void *Address; ///< Address of first byte of memory area
+ size_t AllocatedSize; ///< Size, in bytes of the memory area
+ unsigned Flags = 0;
+ friend class Memory;
+ };
+
+ /// This class provides various memory handling functions that manipulate
+ /// MemoryBlock instances.
+ /// @since 1.4
+ /// An abstraction for memory operations.
+ class Memory {
+ public:
+ enum ProtectionFlags {
+ MF_READ = 0x1000000,
+ MF_WRITE = 0x2000000,
+ MF_EXEC = 0x4000000,
+ MF_RWE_MASK = 0x7000000,
+
+ /// The \p MF_HUGE_HINT flag is used to indicate that the request for
+ /// a memory block should be satisfied with large pages if possible.
+ /// This is only a hint and small pages will be used as fallback.
+ ///
+ /// The presence or absence of this flag in the returned memory block
+ /// is (at least currently) *not* a reliable indicator that the memory
+ /// block will use or will not use large pages. On some systems a request
+ /// without this flag can be backed by large pages without this flag being
+ /// set, and on some other systems a request with this flag can fallback
+ /// to small pages without this flag being cleared.
+ MF_HUGE_HINT = 0x0000001
+ };
+
+ /// This method allocates a block of memory that is suitable for loading
+ /// dynamically generated code (e.g. JIT). An attempt to allocate
+ /// \p NumBytes bytes of virtual memory is made.
+ /// \p NearBlock may point to an existing allocation in which case
+ /// an attempt is made to allocate more memory near the existing block.
+ /// The actual allocated address is not guaranteed to be near the requested
+ /// address.
+ /// \p Flags is used to set the initial protection flags for the block
+ /// of the memory.
+ /// \p EC [out] returns an object describing any error that occurs.
+ ///
+ /// This method may allocate more than the number of bytes requested. The
+ /// actual number of bytes allocated is indicated in the returned
+ /// MemoryBlock.
+ ///
+ /// The start of the allocated block must be aligned with the
+ /// system allocation granularity (64K on Windows, page size on Linux).
+ /// If the address following \p NearBlock is not so aligned, it will be
+ /// rounded up to the next allocation granularity boundary.
+ ///
+ /// \r a non-null MemoryBlock if the function was successful,
+ /// otherwise a null MemoryBlock is with \p EC describing the error.
+ ///
+ /// Allocate mapped memory.
+ static MemoryBlock allocateMappedMemory(size_t NumBytes,
+ const MemoryBlock *const NearBlock,
+ unsigned Flags,
+ std::error_code &EC);
+
+ /// This method releases a block of memory that was allocated with the
+ /// allocateMappedMemory method. It should not be used to release any
+ /// memory block allocated any other way.
+ /// \p Block describes the memory to be released.
+ ///
+ /// \r error_success if the function was successful, or an error_code
+ /// describing the failure if an error occurred.
+ ///
+ /// Release mapped memory.
+ static std::error_code releaseMappedMemory(MemoryBlock &Block);
+
+ /// This method sets the protection flags for a block of memory to the
+ /// state specified by /p Flags. The behavior is not specified if the
+ /// memory was not allocated using the allocateMappedMemory method.
+ /// \p Block describes the memory block to be protected.
+ /// \p Flags specifies the new protection state to be assigned to the block.
+ ///
+ /// If \p Flags is MF_WRITE, the actual behavior varies
+ /// with the operating system (i.e. MF_READ | MF_WRITE on Windows) and the
+ /// target architecture (i.e. MF_WRITE -> MF_READ | MF_WRITE on i386).
+ ///
+ /// \r error_success if the function was successful, or an error_code
+ /// describing the failure if an error occurred.
+ ///
+ /// Set memory protection state.
+ static std::error_code protectMappedMemory(const MemoryBlock &Block,
+ unsigned Flags);
+
+ /// InvalidateInstructionCache - Before the JIT can run a block of code
+ /// that has been emitted it must invalidate the instruction cache on some
+ /// platforms.
+ static void InvalidateInstructionCache(const void *Addr, size_t Len);
+ };
+
+ /// Owning version of MemoryBlock.
+ class OwningMemoryBlock {
+ public:
+ OwningMemoryBlock() = default;
+ explicit OwningMemoryBlock(MemoryBlock M) : M(M) {}
+ OwningMemoryBlock(OwningMemoryBlock &&Other) {
+ M = Other.M;
+ Other.M = MemoryBlock();
+ }
+ OwningMemoryBlock& operator=(OwningMemoryBlock &&Other) {
+ M = Other.M;
+ Other.M = MemoryBlock();
+ return *this;
+ }
+ ~OwningMemoryBlock() {
+ if (M.base())
+ Memory::releaseMappedMemory(M);
+ }
+ void *base() const { return M.base(); }
+ /// The size as it was allocated. This is always greater or equal to the
+ /// size that was originally requested.
+ size_t allocatedSize() const { return M.allocatedSize(); }
+ MemoryBlock getMemoryBlock() const { return M; }
+ std::error_code release() {
+ std::error_code EC;
+ if (M.base()) {
+ EC = Memory::releaseMappedMemory(M);
+ M = MemoryBlock();
+ }
+ return EC;
+ }
+ private:
+ MemoryBlock M;
+ };
+
+#ifndef NDEBUG
+ /// Debugging output for Memory::ProtectionFlags.
+ raw_ostream &operator<<(raw_ostream &OS, const Memory::ProtectionFlags &PF);
+
+ /// Debugging output for MemoryBlock.
+ raw_ostream &operator<<(raw_ostream &OS, const MemoryBlock &MB);
+#endif // ifndef NDEBUG
+ } // end namespace sys
+ } // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/MemoryBuffer.h b/contrib/libs/llvm16/include/llvm/Support/MemoryBuffer.h
new file mode 100644
index 00000000000..7b6a4fe8ed6
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/MemoryBuffer.h
@@ -0,0 +1,302 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- MemoryBuffer.h - Memory Buffer Interface ---------------*- 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 defines the MemoryBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MEMORYBUFFER_H
+#define LLVM_SUPPORT_MEMORYBUFFER_H
+
+#include "llvm-c/Types.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/CBindingWrapping.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MemoryBufferRef.h"
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+
+namespace llvm {
+namespace sys {
+namespace fs {
+// Duplicated from FileSystem.h to avoid a dependency.
+#if defined(_WIN32)
+// A Win32 HANDLE is a typedef of void*
+using file_t = void *;
+#else
+using file_t = int;
+#endif
+} // namespace fs
+} // namespace sys
+
+/// This interface provides simple read-only access to a block of memory, and
+/// provides simple methods for reading files and standard input into a memory
+/// buffer. In addition to basic access to the characters in the file, this
+/// interface guarantees you can read one character past the end of the file,
+/// and that this character will read as '\0'.
+///
+/// The '\0' guarantee is needed to support an optimization -- it's intended to
+/// be more efficient for clients which are reading all the data to stop
+/// reading when they encounter a '\0' than to continually check the file
+/// position to see if it has reached the end of the file.
+class MemoryBuffer {
+ const char *BufferStart; // Start of the buffer.
+ const char *BufferEnd; // End of the buffer.
+
+protected:
+ MemoryBuffer() = default;
+
+ void init(const char *BufStart, const char *BufEnd,
+ bool RequiresNullTerminator);
+
+public:
+ MemoryBuffer(const MemoryBuffer &) = delete;
+ MemoryBuffer &operator=(const MemoryBuffer &) = delete;
+ virtual ~MemoryBuffer();
+
+ const char *getBufferStart() const { return BufferStart; }
+ const char *getBufferEnd() const { return BufferEnd; }
+ size_t getBufferSize() const { return BufferEnd-BufferStart; }
+
+ StringRef getBuffer() const {
+ return StringRef(BufferStart, getBufferSize());
+ }
+
+ /// Return an identifier for this buffer, typically the filename it was read
+ /// from.
+ virtual StringRef getBufferIdentifier() const { return "Unknown buffer"; }
+
+ /// For read-only MemoryBuffer_MMap, mark the buffer as unused in the near
+ /// future and the kernel can free resources associated with it. Further
+ /// access is supported but may be expensive. This calls
+ /// madvise(MADV_DONTNEED) on read-only file mappings on *NIX systems. This
+ /// function should not be called on a writable buffer.
+ virtual void dontNeedIfMmap() {}
+
+ /// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer
+ /// if successful, otherwise returning null.
+ ///
+ /// \param IsText Set to true to indicate that the file should be read in
+ /// text mode.
+ ///
+ /// \param IsVolatile Set to true to indicate that the contents of the file
+ /// can change outside the user's control, e.g. when libclang tries to parse
+ /// while the user is editing/updating the file or if the file is on an NFS.
+ ///
+ /// \param Alignment Set to indicate that the buffer should be aligned to at
+ /// least the specified alignment.
+ static ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getFile(const Twine &Filename, bool IsText = false,
+ bool RequiresNullTerminator = true, bool IsVolatile = false,
+ std::optional<Align> Alignment = std::nullopt);
+
+ /// Read all of the specified file into a MemoryBuffer as a stream
+ /// (i.e. until EOF reached). This is useful for special files that
+ /// look like a regular file but have 0 size (e.g. /proc/cpuinfo on Linux).
+ static ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getFileAsStream(const Twine &Filename);
+
+ /// Given an already-open file descriptor, map some slice of it into a
+ /// MemoryBuffer. The slice is specified by an \p Offset and \p MapSize.
+ /// Since this is in the middle of a file, the buffer is not null terminated.
+ static ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getOpenFileSlice(sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize,
+ int64_t Offset, bool IsVolatile = false,
+ std::optional<Align> Alignment = std::nullopt);
+
+ /// Given an already-open file descriptor, read the file and return a
+ /// MemoryBuffer.
+ ///
+ /// \param IsVolatile Set to true to indicate that the contents of the file
+ /// can change outside the user's control, e.g. when libclang tries to parse
+ /// while the user is editing/updating the file or if the file is on an NFS.
+ ///
+ /// \param Alignment Set to indicate that the buffer should be aligned to at
+ /// least the specified alignment.
+ static ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
+ bool RequiresNullTerminator = true, bool IsVolatile = false,
+ std::optional<Align> Alignment = std::nullopt);
+
+ /// Open the specified memory range as a MemoryBuffer. Note that InputData
+ /// must be null terminated if RequiresNullTerminator is true.
+ static std::unique_ptr<MemoryBuffer>
+ getMemBuffer(StringRef InputData, StringRef BufferName = "",
+ bool RequiresNullTerminator = true);
+
+ static std::unique_ptr<MemoryBuffer>
+ getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator = true);
+
+ /// Open the specified memory range as a MemoryBuffer, copying the contents
+ /// and taking ownership of it. InputData does not have to be null terminated.
+ static std::unique_ptr<MemoryBuffer>
+ getMemBufferCopy(StringRef InputData, const Twine &BufferName = "");
+
+ /// Read all of stdin into a file buffer, and return it.
+ static ErrorOr<std::unique_ptr<MemoryBuffer>> getSTDIN();
+
+ /// Open the specified file as a MemoryBuffer, or open stdin if the Filename
+ /// is "-".
+ static ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getFileOrSTDIN(const Twine &Filename, bool IsText = false,
+ bool RequiresNullTerminator = true,
+ std::optional<Align> Alignment = std::nullopt);
+
+ /// Map a subrange of the specified file as a MemoryBuffer.
+ static ErrorOr<std::unique_ptr<MemoryBuffer>>
+ getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
+ bool IsVolatile = false,
+ std::optional<Align> Alignment = std::nullopt);
+
+ //===--------------------------------------------------------------------===//
+ // Provided for performance analysis.
+ //===--------------------------------------------------------------------===//
+
+ /// The kind of memory backing used to support the MemoryBuffer.
+ enum BufferKind {
+ MemoryBuffer_Malloc,
+ MemoryBuffer_MMap
+ };
+
+ /// Return information on the memory mechanism used to support the
+ /// MemoryBuffer.
+ virtual BufferKind getBufferKind() const = 0;
+
+ MemoryBufferRef getMemBufferRef() const;
+};
+
+/// This class is an extension of MemoryBuffer, which allows copy-on-write
+/// access to the underlying contents. It only supports creation methods that
+/// are guaranteed to produce a writable buffer. For example, mapping a file
+/// read-only is not supported.
+class WritableMemoryBuffer : public MemoryBuffer {
+protected:
+ WritableMemoryBuffer() = default;
+
+public:
+ using MemoryBuffer::getBuffer;
+ using MemoryBuffer::getBufferEnd;
+ using MemoryBuffer::getBufferStart;
+
+ // const_cast is well-defined here, because the underlying buffer is
+ // guaranteed to have been initialized with a mutable buffer.
+ char *getBufferStart() {
+ return const_cast<char *>(MemoryBuffer::getBufferStart());
+ }
+ char *getBufferEnd() {
+ return const_cast<char *>(MemoryBuffer::getBufferEnd());
+ }
+ MutableArrayRef<char> getBuffer() {
+ return {getBufferStart(), getBufferEnd()};
+ }
+
+ static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
+ getFile(const Twine &Filename, bool IsVolatile = false,
+ std::optional<Align> Alignment = std::nullopt);
+
+ /// Map a subrange of the specified file as a WritableMemoryBuffer.
+ static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
+ getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
+ bool IsVolatile = false,
+ std::optional<Align> Alignment = std::nullopt);
+
+ /// Allocate a new MemoryBuffer of the specified size that is not initialized.
+ /// Note that the caller should initialize the memory allocated by this
+ /// method. The memory is owned by the MemoryBuffer object.
+ ///
+ /// \param Alignment Set to indicate that the buffer should be aligned to at
+ /// least the specified alignment.
+ static std::unique_ptr<WritableMemoryBuffer>
+ getNewUninitMemBuffer(size_t Size, const Twine &BufferName = "",
+ std::optional<Align> Alignment = std::nullopt);
+
+ /// Allocate a new zero-initialized MemoryBuffer of the specified size. Note
+ /// that the caller need not initialize the memory allocated by this method.
+ /// The memory is owned by the MemoryBuffer object.
+ static std::unique_ptr<WritableMemoryBuffer>
+ getNewMemBuffer(size_t Size, const Twine &BufferName = "");
+
+private:
+ // Hide these base class factory function so one can't write
+ // WritableMemoryBuffer::getXXX()
+ // and be surprised that he got a read-only Buffer.
+ using MemoryBuffer::getFileAsStream;
+ using MemoryBuffer::getFileOrSTDIN;
+ using MemoryBuffer::getMemBuffer;
+ using MemoryBuffer::getMemBufferCopy;
+ using MemoryBuffer::getOpenFile;
+ using MemoryBuffer::getOpenFileSlice;
+ using MemoryBuffer::getSTDIN;
+};
+
+/// This class is an extension of MemoryBuffer, which allows write access to
+/// the underlying contents and committing those changes to the original source.
+/// It only supports creation methods that are guaranteed to produce a writable
+/// buffer. For example, mapping a file read-only is not supported.
+class WriteThroughMemoryBuffer : public MemoryBuffer {
+protected:
+ WriteThroughMemoryBuffer() = default;
+
+public:
+ using MemoryBuffer::getBuffer;
+ using MemoryBuffer::getBufferEnd;
+ using MemoryBuffer::getBufferStart;
+
+ // const_cast is well-defined here, because the underlying buffer is
+ // guaranteed to have been initialized with a mutable buffer.
+ char *getBufferStart() {
+ return const_cast<char *>(MemoryBuffer::getBufferStart());
+ }
+ char *getBufferEnd() {
+ return const_cast<char *>(MemoryBuffer::getBufferEnd());
+ }
+ MutableArrayRef<char> getBuffer() {
+ return {getBufferStart(), getBufferEnd()};
+ }
+
+ static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+ getFile(const Twine &Filename, int64_t FileSize = -1);
+
+ /// Map a subrange of the specified file as a ReadWriteMemoryBuffer.
+ static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
+ getFileSlice(const Twine &Filename, uint64_t MapSize, uint64_t Offset);
+
+private:
+ // Hide these base class factory function so one can't write
+ // WritableMemoryBuffer::getXXX()
+ // and be surprised that he got a read-only Buffer.
+ using MemoryBuffer::getFileAsStream;
+ using MemoryBuffer::getFileOrSTDIN;
+ using MemoryBuffer::getMemBuffer;
+ using MemoryBuffer::getMemBufferCopy;
+ using MemoryBuffer::getOpenFile;
+ using MemoryBuffer::getOpenFileSlice;
+ using MemoryBuffer::getSTDIN;
+};
+
+// Create wrappers for C Binding types (see CBindingWrapping.h).
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(MemoryBuffer, LLVMMemoryBufferRef)
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_MEMORYBUFFER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/MemoryBufferRef.h b/contrib/libs/llvm16/include/llvm/Support/MemoryBufferRef.h
new file mode 100644
index 00000000000..cc387b7fb7f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/MemoryBufferRef.h
@@ -0,0 +1,67 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- MemoryBufferRef.h - Memory Buffer Reference --------------*- 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 defines the MemoryBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MEMORYBUFFERREF_H
+#define LLVM_SUPPORT_MEMORYBUFFERREF_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+class MemoryBuffer;
+
+class MemoryBufferRef {
+ StringRef Buffer;
+ StringRef Identifier;
+
+public:
+ MemoryBufferRef() = default;
+ MemoryBufferRef(const MemoryBuffer &Buffer);
+ MemoryBufferRef(StringRef Buffer, StringRef Identifier)
+ : Buffer(Buffer), Identifier(Identifier) {}
+
+ StringRef getBuffer() const { return Buffer; }
+ StringRef getBufferIdentifier() const { return Identifier; }
+
+ const char *getBufferStart() const { return Buffer.begin(); }
+ const char *getBufferEnd() const { return Buffer.end(); }
+ size_t getBufferSize() const { return Buffer.size(); }
+
+ /// Check pointer identity (not value) of identifier and data.
+ friend bool operator==(const MemoryBufferRef &LHS,
+ const MemoryBufferRef &RHS) {
+ return LHS.Buffer.begin() == RHS.Buffer.begin() &&
+ LHS.Buffer.end() == RHS.Buffer.end() &&
+ LHS.Identifier.begin() == RHS.Identifier.begin() &&
+ LHS.Identifier.end() == RHS.Identifier.end();
+ }
+
+ friend bool operator!=(const MemoryBufferRef &LHS,
+ const MemoryBufferRef &RHS) {
+ return !(LHS == RHS);
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_MEMORYBUFFERREF_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ModRef.h b/contrib/libs/llvm16/include/llvm/Support/ModRef.h
new file mode 100644
index 00000000000..0cb74cb4caf
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ModRef.h
@@ -0,0 +1,272 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- ModRef.h - Memory effect modelling ---------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Definitions of ModRefInfo and MemoryEffects, which are used to
+// describe the memory effects of instructions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_MODREF_H
+#define LLVM_IR_MODREF_H
+
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/Sequence.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+/// Flags indicating whether a memory access modifies or references memory.
+///
+/// This is no access at all, a modification, a reference, or both
+/// a modification and a reference.
+enum class ModRefInfo : uint8_t {
+ /// The access neither references nor modifies the value stored in memory.
+ NoModRef = 0,
+ /// The access may reference the value stored in memory.
+ Ref = 1,
+ /// The access may modify the value stored in memory.
+ Mod = 2,
+ /// The access may reference and may modify the value stored in memory.
+ ModRef = Ref | Mod,
+ LLVM_MARK_AS_BITMASK_ENUM(ModRef),
+};
+
+[[nodiscard]] inline bool isNoModRef(const ModRefInfo MRI) {
+ return MRI == ModRefInfo::NoModRef;
+}
+[[nodiscard]] inline bool isModOrRefSet(const ModRefInfo MRI) {
+ return MRI != ModRefInfo::NoModRef;
+}
+[[nodiscard]] inline bool isModAndRefSet(const ModRefInfo MRI) {
+ return MRI == ModRefInfo::ModRef;
+}
+[[nodiscard]] inline bool isModSet(const ModRefInfo MRI) {
+ return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Mod);
+}
+[[nodiscard]] inline bool isRefSet(const ModRefInfo MRI) {
+ return static_cast<int>(MRI) & static_cast<int>(ModRefInfo::Ref);
+}
+
+/// Debug print ModRefInfo.
+raw_ostream &operator<<(raw_ostream &OS, ModRefInfo MR);
+
+/// Summary of how a function affects memory in the program.
+///
+/// Loads from constant globals are not considered memory accesses for this
+/// interface. Also, functions may freely modify stack space local to their
+/// invocation without having to report it through these interfaces.
+class MemoryEffects {
+public:
+ /// The locations at which a function might access memory.
+ enum Location {
+ /// Access to memory via argument pointers.
+ ArgMem = 0,
+ /// Memory that is inaccessible via LLVM IR.
+ InaccessibleMem = 1,
+ /// Any other memory.
+ Other = 2,
+ };
+
+private:
+ uint32_t Data = 0;
+
+ static constexpr uint32_t BitsPerLoc = 2;
+ static constexpr uint32_t LocMask = (1 << BitsPerLoc) - 1;
+
+ static uint32_t getLocationPos(Location Loc) {
+ return (uint32_t)Loc * BitsPerLoc;
+ }
+
+ MemoryEffects(uint32_t Data) : Data(Data) {}
+
+ void setModRef(Location Loc, ModRefInfo MR) {
+ Data &= ~(LocMask << getLocationPos(Loc));
+ Data |= static_cast<uint32_t>(MR) << getLocationPos(Loc);
+ }
+
+ friend raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB);
+
+public:
+ /// Returns iterator over all supported location kinds.
+ static auto locations() {
+ return enum_seq_inclusive(Location::ArgMem, Location::Other,
+ force_iteration_on_noniterable_enum);
+ }
+
+ /// Create MemoryEffects that can access only the given location with the
+ /// given ModRefInfo.
+ MemoryEffects(Location Loc, ModRefInfo MR) { setModRef(Loc, MR); }
+
+ /// Create MemoryEffects that can access any location with the given
+ /// ModRefInfo.
+ explicit MemoryEffects(ModRefInfo MR) {
+ for (Location Loc : locations())
+ setModRef(Loc, MR);
+ }
+
+ /// Create MemoryEffects that can read and write any memory.
+ static MemoryEffects unknown() {
+ return MemoryEffects(ModRefInfo::ModRef);
+ }
+
+ /// Create MemoryEffects that cannot read or write any memory.
+ static MemoryEffects none() {
+ return MemoryEffects(ModRefInfo::NoModRef);
+ }
+
+ /// Create MemoryEffects that can read any memory.
+ static MemoryEffects readOnly() {
+ return MemoryEffects(ModRefInfo::Ref);
+ }
+
+ /// Create MemoryEffects that can write any memory.
+ static MemoryEffects writeOnly() {
+ return MemoryEffects(ModRefInfo::Mod);
+ }
+
+ /// Create MemoryEffects that can only access argument memory.
+ static MemoryEffects argMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
+ return MemoryEffects(ArgMem, MR);
+ }
+
+ /// Create MemoryEffects that can only access inaccessible memory.
+ static MemoryEffects inaccessibleMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
+ return MemoryEffects(InaccessibleMem, MR);
+ }
+
+ /// Create MemoryEffects that can only access inaccessible or argument memory.
+ static MemoryEffects
+ inaccessibleOrArgMemOnly(ModRefInfo MR = ModRefInfo::ModRef) {
+ MemoryEffects FRMB = none();
+ FRMB.setModRef(ArgMem, MR);
+ FRMB.setModRef(InaccessibleMem, MR);
+ return FRMB;
+ }
+
+ /// Create MemoryEffects from an encoded integer value (used by memory
+ /// attribute).
+ static MemoryEffects createFromIntValue(uint32_t Data) {
+ return MemoryEffects(Data);
+ }
+
+ /// Convert MemoryEffects into an encoded integer value (used by memory
+ /// attribute).
+ uint32_t toIntValue() const {
+ return Data;
+ }
+
+ /// Get ModRefInfo for the given Location.
+ ModRefInfo getModRef(Location Loc) const {
+ return ModRefInfo((Data >> getLocationPos(Loc)) & LocMask);
+ }
+
+ /// Get new MemoryEffects with modified ModRefInfo for Loc.
+ MemoryEffects getWithModRef(Location Loc, ModRefInfo MR) const {
+ MemoryEffects ME = *this;
+ ME.setModRef(Loc, MR);
+ return ME;
+ }
+
+ /// Get new MemoryEffects with NoModRef on the given Loc.
+ MemoryEffects getWithoutLoc(Location Loc) const {
+ MemoryEffects ME = *this;
+ ME.setModRef(Loc, ModRefInfo::NoModRef);
+ return ME;
+ }
+
+ /// Get ModRefInfo for any location.
+ ModRefInfo getModRef() const {
+ ModRefInfo MR = ModRefInfo::NoModRef;
+ for (Location Loc : locations())
+ MR |= getModRef(Loc);
+ return MR;
+ }
+
+ /// Whether this function accesses no memory.
+ bool doesNotAccessMemory() const { return Data == 0; }
+
+ /// Whether this function only (at most) reads memory.
+ bool onlyReadsMemory() const { return !isModSet(getModRef()); }
+
+ /// Whether this function only (at most) writes memory.
+ bool onlyWritesMemory() const { return !isRefSet(getModRef()); }
+
+ /// Whether this function only (at most) accesses argument memory.
+ bool onlyAccessesArgPointees() const {
+ return getWithoutLoc(ArgMem).doesNotAccessMemory();
+ }
+
+ /// Whether this function may access argument memory.
+ bool doesAccessArgPointees() const {
+ return isModOrRefSet(getModRef(ArgMem));
+ }
+
+ /// Whether this function only (at most) accesses inaccessible memory.
+ bool onlyAccessesInaccessibleMem() const {
+ return getWithoutLoc(InaccessibleMem).doesNotAccessMemory();
+ }
+
+ /// Whether this function only (at most) accesses argument and inaccessible
+ /// memory.
+ bool onlyAccessesInaccessibleOrArgMem() const {
+ return isNoModRef(getModRef(Other));
+ }
+
+ /// Intersect with other MemoryEffects.
+ MemoryEffects operator&(MemoryEffects Other) const {
+ return MemoryEffects(Data & Other.Data);
+ }
+
+ /// Intersect (in-place) with other MemoryEffects.
+ MemoryEffects &operator&=(MemoryEffects Other) {
+ Data &= Other.Data;
+ return *this;
+ }
+
+ /// Union with other MemoryEffects.
+ MemoryEffects operator|(MemoryEffects Other) const {
+ return MemoryEffects(Data | Other.Data);
+ }
+
+ /// Union (in-place) with other MemoryEffects.
+ MemoryEffects &operator|=(MemoryEffects Other) {
+ Data |= Other.Data;
+ return *this;
+ }
+
+ /// Check whether this is the same as other MemoryEffects.
+ bool operator==(MemoryEffects Other) const {
+ return Data == Other.Data;
+ }
+
+ /// Check whether this is different from other MemoryEffects.
+ bool operator!=(MemoryEffects Other) const {
+ return !operator==(Other);
+ }
+};
+
+/// Debug print MemoryEffects.
+raw_ostream &operator<<(raw_ostream &OS, MemoryEffects RMRB);
+
+// Legacy alias.
+using FunctionModRefBehavior = MemoryEffects;
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Mutex.h b/contrib/libs/llvm16/include/llvm/Support/Mutex.h
new file mode 100644
index 00000000000..bda13ed60b3
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Mutex.h
@@ -0,0 +1,86 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Mutex.h - Mutex Operating System Concept -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::Mutex class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_MUTEX_H
+#define LLVM_SUPPORT_MUTEX_H
+
+#include "llvm/Support/Threading.h"
+#include <cassert>
+#include <mutex>
+
+namespace llvm
+{
+ namespace sys
+ {
+ /// SmartMutex - A mutex with a compile time constant parameter that
+ /// indicates whether this mutex should become a no-op when we're not
+ /// running in multithreaded mode.
+ template<bool mt_only>
+ class SmartMutex {
+ std::recursive_mutex impl;
+ unsigned acquired = 0;
+
+ public:
+ bool lock() {
+ if (!mt_only || llvm_is_multithreaded()) {
+ impl.lock();
+ return true;
+ }
+ // Single-threaded debugging code. This would be racy in
+ // multithreaded mode, but provides not basic checks in single
+ // threaded mode.
+ ++acquired;
+ return true;
+ }
+
+ bool unlock() {
+ if (!mt_only || llvm_is_multithreaded()) {
+ impl.unlock();
+ return true;
+ }
+ // Single-threaded debugging code. This would be racy in
+ // multithreaded mode, but provides not basic checks in single
+ // threaded mode.
+ assert(acquired && "Lock not acquired before release!");
+ --acquired;
+ return true;
+ }
+
+ bool try_lock() {
+ if (!mt_only || llvm_is_multithreaded())
+ return impl.try_lock();
+ return true;
+ }
+ };
+
+ /// Mutex - A standard, always enforced mutex.
+ typedef SmartMutex<false> Mutex;
+
+ template <bool mt_only>
+ using SmartScopedLock = std::lock_guard<SmartMutex<mt_only>>;
+
+ typedef SmartScopedLock<false> ScopedLock;
+ }
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/NativeFormatting.h b/contrib/libs/llvm16/include/llvm/Support/NativeFormatting.h
new file mode 100644
index 00000000000..62f2d0c517a
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/NativeFormatting.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- NativeFormatting.h - Low level formatting helpers ---------*- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_NATIVEFORMATTING_H
+#define LLVM_SUPPORT_NATIVEFORMATTING_H
+
+#include <cstdint>
+#include <optional>
+
+namespace llvm {
+class raw_ostream;
+enum class FloatStyle { Exponent, ExponentUpper, Fixed, Percent };
+enum class IntegerStyle {
+ Integer,
+ Number,
+};
+enum class HexPrintStyle { Upper, Lower, PrefixUpper, PrefixLower };
+
+size_t getDefaultPrecision(FloatStyle Style);
+
+bool isPrefixedHexStyle(HexPrintStyle S);
+
+void write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
+ IntegerStyle Style);
+void write_integer(raw_ostream &S, int N, size_t MinDigits, IntegerStyle Style);
+void write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
+ IntegerStyle Style);
+void write_integer(raw_ostream &S, long N, size_t MinDigits,
+ IntegerStyle Style);
+void write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
+ IntegerStyle Style);
+void write_integer(raw_ostream &S, long long N, size_t MinDigits,
+ IntegerStyle Style);
+
+void write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
+ std::optional<size_t> Width = std::nullopt);
+void write_double(raw_ostream &S, double D, FloatStyle Style,
+ std::optional<size_t> Precision = std::nullopt);
+}
+
+#endif
+
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/OnDiskHashTable.h b/contrib/libs/llvm16/include/llvm/Support/OnDiskHashTable.h
new file mode 100644
index 00000000000..e3f98064244
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/OnDiskHashTable.h
@@ -0,0 +1,626 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- OnDiskHashTable.h - On-Disk Hash Table Implementation --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines facilities for reading and writing on-disk hash tables.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_ONDISKHASHTABLE_H
+#define LLVM_SUPPORT_ONDISKHASHTABLE_H
+
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdlib>
+
+namespace llvm {
+
+/// Generates an on disk hash table.
+///
+/// This needs an \c Info that handles storing values into the hash table's
+/// payload and computes the hash for a given key. This should provide the
+/// following interface:
+///
+/// \code
+/// class ExampleInfo {
+/// public:
+/// typedef ExampleKey key_type; // Must be copy constructible
+/// typedef ExampleKey &key_type_ref;
+/// typedef ExampleData data_type; // Must be copy constructible
+/// typedef ExampleData &data_type_ref;
+/// typedef uint32_t hash_value_type; // The type the hash function returns.
+/// typedef uint32_t offset_type; // The type for offsets into the table.
+///
+/// /// Calculate the hash for Key
+/// static hash_value_type ComputeHash(key_type_ref Key);
+/// /// Return the lengths, in bytes, of the given Key/Data pair.
+/// static std::pair<offset_type, offset_type>
+/// EmitKeyDataLength(raw_ostream &Out, key_type_ref Key, data_type_ref Data);
+/// /// Write Key to Out. KeyLen is the length from EmitKeyDataLength.
+/// static void EmitKey(raw_ostream &Out, key_type_ref Key,
+/// offset_type KeyLen);
+/// /// Write Data to Out. DataLen is the length from EmitKeyDataLength.
+/// static void EmitData(raw_ostream &Out, key_type_ref Key,
+/// data_type_ref Data, offset_type DataLen);
+/// /// Determine if two keys are equal. Optional, only needed by contains.
+/// static bool EqualKey(key_type_ref Key1, key_type_ref Key2);
+/// };
+/// \endcode
+template <typename Info> class OnDiskChainedHashTableGenerator {
+ /// A single item in the hash table.
+ class Item {
+ public:
+ typename Info::key_type Key;
+ typename Info::data_type Data;
+ Item *Next;
+ const typename Info::hash_value_type Hash;
+
+ Item(typename Info::key_type_ref Key, typename Info::data_type_ref Data,
+ Info &InfoObj)
+ : Key(Key), Data(Data), Next(nullptr), Hash(InfoObj.ComputeHash(Key)) {}
+ };
+
+ typedef typename Info::offset_type offset_type;
+ offset_type NumBuckets;
+ offset_type NumEntries;
+ llvm::SpecificBumpPtrAllocator<Item> BA;
+
+ /// A linked list of values in a particular hash bucket.
+ struct Bucket {
+ offset_type Off;
+ unsigned Length;
+ Item *Head;
+ };
+
+ Bucket *Buckets;
+
+private:
+ /// Insert an item into the appropriate hash bucket.
+ void insert(Bucket *Buckets, size_t Size, Item *E) {
+ Bucket &B = Buckets[E->Hash & (Size - 1)];
+ E->Next = B.Head;
+ ++B.Length;
+ B.Head = E;
+ }
+
+ /// Resize the hash table, moving the old entries into the new buckets.
+ void resize(size_t NewSize) {
+ Bucket *NewBuckets = static_cast<Bucket *>(
+ safe_calloc(NewSize, sizeof(Bucket)));
+ // Populate NewBuckets with the old entries.
+ for (size_t I = 0; I < NumBuckets; ++I)
+ for (Item *E = Buckets[I].Head; E;) {
+ Item *N = E->Next;
+ E->Next = nullptr;
+ insert(NewBuckets, NewSize, E);
+ E = N;
+ }
+
+ free(Buckets);
+ NumBuckets = NewSize;
+ Buckets = NewBuckets;
+ }
+
+public:
+ /// Insert an entry into the table.
+ void insert(typename Info::key_type_ref Key,
+ typename Info::data_type_ref Data) {
+ Info InfoObj;
+ insert(Key, Data, InfoObj);
+ }
+
+ /// Insert an entry into the table.
+ ///
+ /// Uses the provided Info instead of a stack allocated one.
+ void insert(typename Info::key_type_ref Key,
+ typename Info::data_type_ref Data, Info &InfoObj) {
+ ++NumEntries;
+ if (4 * NumEntries >= 3 * NumBuckets)
+ resize(NumBuckets * 2);
+ insert(Buckets, NumBuckets, new (BA.Allocate()) Item(Key, Data, InfoObj));
+ }
+
+ /// Determine whether an entry has been inserted.
+ bool contains(typename Info::key_type_ref Key, Info &InfoObj) {
+ unsigned Hash = InfoObj.ComputeHash(Key);
+ for (Item *I = Buckets[Hash & (NumBuckets - 1)].Head; I; I = I->Next)
+ if (I->Hash == Hash && InfoObj.EqualKey(I->Key, Key))
+ return true;
+ return false;
+ }
+
+ /// Emit the table to Out, which must not be at offset 0.
+ offset_type Emit(raw_ostream &Out) {
+ Info InfoObj;
+ return Emit(Out, InfoObj);
+ }
+
+ /// Emit the table to Out, which must not be at offset 0.
+ ///
+ /// Uses the provided Info instead of a stack allocated one.
+ offset_type Emit(raw_ostream &Out, Info &InfoObj) {
+ using namespace llvm::support;
+ endian::Writer LE(Out, little);
+
+ // Now we're done adding entries, resize the bucket list if it's
+ // significantly too large. (This only happens if the number of
+ // entries is small and we're within our initial allocation of
+ // 64 buckets.) We aim for an occupancy ratio in [3/8, 3/4).
+ //
+ // As a special case, if there are two or fewer entries, just
+ // form a single bucket. A linear scan is fine in that case, and
+ // this is very common in C++ class lookup tables. This also
+ // guarantees we produce at least one bucket for an empty table.
+ //
+ // FIXME: Try computing a perfect hash function at this point.
+ unsigned TargetNumBuckets =
+ NumEntries <= 2 ? 1 : NextPowerOf2(NumEntries * 4 / 3);
+ if (TargetNumBuckets != NumBuckets)
+ resize(TargetNumBuckets);
+
+ // Emit the payload of the table.
+ for (offset_type I = 0; I < NumBuckets; ++I) {
+ Bucket &B = Buckets[I];
+ if (!B.Head)
+ continue;
+
+ // Store the offset for the data of this bucket.
+ B.Off = Out.tell();
+ assert(B.Off && "Cannot write a bucket at offset 0. Please add padding.");
+
+ // Write out the number of items in the bucket.
+ LE.write<uint16_t>(B.Length);
+ assert(B.Length != 0 && "Bucket has a head but zero length?");
+
+ // Write out the entries in the bucket.
+ for (Item *I = B.Head; I; I = I->Next) {
+ LE.write<typename Info::hash_value_type>(I->Hash);
+ const std::pair<offset_type, offset_type> &Len =
+ InfoObj.EmitKeyDataLength(Out, I->Key, I->Data);
+#ifdef NDEBUG
+ InfoObj.EmitKey(Out, I->Key, Len.first);
+ InfoObj.EmitData(Out, I->Key, I->Data, Len.second);
+#else
+ // In asserts mode, check that the users length matches the data they
+ // wrote.
+ uint64_t KeyStart = Out.tell();
+ InfoObj.EmitKey(Out, I->Key, Len.first);
+ uint64_t DataStart = Out.tell();
+ InfoObj.EmitData(Out, I->Key, I->Data, Len.second);
+ uint64_t End = Out.tell();
+ assert(offset_type(DataStart - KeyStart) == Len.first &&
+ "key length does not match bytes written");
+ assert(offset_type(End - DataStart) == Len.second &&
+ "data length does not match bytes written");
+#endif
+ }
+ }
+
+ // Pad with zeros so that we can start the hashtable at an aligned address.
+ offset_type TableOff = Out.tell();
+ uint64_t N = offsetToAlignment(TableOff, Align(alignof(offset_type)));
+ TableOff += N;
+ while (N--)
+ LE.write<uint8_t>(0);
+
+ // Emit the hashtable itself.
+ LE.write<offset_type>(NumBuckets);
+ LE.write<offset_type>(NumEntries);
+ for (offset_type I = 0; I < NumBuckets; ++I)
+ LE.write<offset_type>(Buckets[I].Off);
+
+ return TableOff;
+ }
+
+ OnDiskChainedHashTableGenerator() {
+ NumEntries = 0;
+ NumBuckets = 64;
+ // Note that we do not need to run the constructors of the individual
+ // Bucket objects since 'calloc' returns bytes that are all 0.
+ Buckets = static_cast<Bucket *>(safe_calloc(NumBuckets, sizeof(Bucket)));
+ }
+
+ ~OnDiskChainedHashTableGenerator() { std::free(Buckets); }
+};
+
+/// Provides lookup on an on disk hash table.
+///
+/// This needs an \c Info that handles reading values from the hash table's
+/// payload and computes the hash for a given key. This should provide the
+/// following interface:
+///
+/// \code
+/// class ExampleLookupInfo {
+/// public:
+/// typedef ExampleData data_type;
+/// typedef ExampleInternalKey internal_key_type; // The stored key type.
+/// typedef ExampleKey external_key_type; // The type to pass to find().
+/// typedef uint32_t hash_value_type; // The type the hash function returns.
+/// typedef uint32_t offset_type; // The type for offsets into the table.
+///
+/// /// Compare two keys for equality.
+/// static bool EqualKey(internal_key_type &Key1, internal_key_type &Key2);
+/// /// Calculate the hash for the given key.
+/// static hash_value_type ComputeHash(internal_key_type &IKey);
+/// /// Translate from the semantic type of a key in the hash table to the
+/// /// type that is actually stored and used for hashing and comparisons.
+/// /// The internal and external types are often the same, in which case this
+/// /// can simply return the passed in value.
+/// static const internal_key_type &GetInternalKey(external_key_type &EKey);
+/// /// Read the key and data length from Buffer, leaving it pointing at the
+/// /// following byte.
+/// static std::pair<offset_type, offset_type>
+/// ReadKeyDataLength(const unsigned char *&Buffer);
+/// /// Read the key from Buffer, given the KeyLen as reported from
+/// /// ReadKeyDataLength.
+/// const internal_key_type &ReadKey(const unsigned char *Buffer,
+/// offset_type KeyLen);
+/// /// Read the data for Key from Buffer, given the DataLen as reported from
+/// /// ReadKeyDataLength.
+/// data_type ReadData(StringRef Key, const unsigned char *Buffer,
+/// offset_type DataLen);
+/// };
+/// \endcode
+template <typename Info> class OnDiskChainedHashTable {
+ const typename Info::offset_type NumBuckets;
+ const typename Info::offset_type NumEntries;
+ const unsigned char *const Buckets;
+ const unsigned char *const Base;
+ Info InfoObj;
+
+public:
+ typedef Info InfoType;
+ typedef typename Info::internal_key_type internal_key_type;
+ typedef typename Info::external_key_type external_key_type;
+ typedef typename Info::data_type data_type;
+ typedef typename Info::hash_value_type hash_value_type;
+ typedef typename Info::offset_type offset_type;
+
+ OnDiskChainedHashTable(offset_type NumBuckets, offset_type NumEntries,
+ const unsigned char *Buckets,
+ const unsigned char *Base,
+ const Info &InfoObj = Info())
+ : NumBuckets(NumBuckets), NumEntries(NumEntries), Buckets(Buckets),
+ Base(Base), InfoObj(InfoObj) {
+ assert((reinterpret_cast<uintptr_t>(Buckets) & 0x3) == 0 &&
+ "'buckets' must have a 4-byte alignment");
+ }
+
+ /// Read the number of buckets and the number of entries from a hash table
+ /// produced by OnDiskHashTableGenerator::Emit, and advance the Buckets
+ /// pointer past them.
+ static std::pair<offset_type, offset_type>
+ readNumBucketsAndEntries(const unsigned char *&Buckets) {
+ assert((reinterpret_cast<uintptr_t>(Buckets) & 0x3) == 0 &&
+ "buckets should be 4-byte aligned.");
+ using namespace llvm::support;
+ offset_type NumBuckets =
+ endian::readNext<offset_type, little, aligned>(Buckets);
+ offset_type NumEntries =
+ endian::readNext<offset_type, little, aligned>(Buckets);
+ return std::make_pair(NumBuckets, NumEntries);
+ }
+
+ offset_type getNumBuckets() const { return NumBuckets; }
+ offset_type getNumEntries() const { return NumEntries; }
+ const unsigned char *getBase() const { return Base; }
+ const unsigned char *getBuckets() const { return Buckets; }
+
+ bool isEmpty() const { return NumEntries == 0; }
+
+ class iterator {
+ internal_key_type Key;
+ const unsigned char *const Data;
+ const offset_type Len;
+ Info *InfoObj;
+
+ public:
+ iterator() : Key(), Data(nullptr), Len(0), InfoObj(nullptr) {}
+ iterator(const internal_key_type K, const unsigned char *D, offset_type L,
+ Info *InfoObj)
+ : Key(K), Data(D), Len(L), InfoObj(InfoObj) {}
+
+ data_type operator*() const { return InfoObj->ReadData(Key, Data, Len); }
+
+ const unsigned char *getDataPtr() const { return Data; }
+ offset_type getDataLen() const { return Len; }
+
+ bool operator==(const iterator &X) const { return X.Data == Data; }
+ bool operator!=(const iterator &X) const { return X.Data != Data; }
+ };
+
+ /// Look up the stored data for a particular key.
+ iterator find(const external_key_type &EKey, Info *InfoPtr = nullptr) {
+ const internal_key_type &IKey = InfoObj.GetInternalKey(EKey);
+ hash_value_type KeyHash = InfoObj.ComputeHash(IKey);
+ return find_hashed(IKey, KeyHash, InfoPtr);
+ }
+
+ /// Look up the stored data for a particular key with a known hash.
+ iterator find_hashed(const internal_key_type &IKey, hash_value_type KeyHash,
+ Info *InfoPtr = nullptr) {
+ using namespace llvm::support;
+
+ if (!InfoPtr)
+ InfoPtr = &InfoObj;
+
+ // Each bucket is just an offset into the hash table file.
+ offset_type Idx = KeyHash & (NumBuckets - 1);
+ const unsigned char *Bucket = Buckets + sizeof(offset_type) * Idx;
+
+ offset_type Offset = endian::readNext<offset_type, little, aligned>(Bucket);
+ if (Offset == 0)
+ return iterator(); // Empty bucket.
+ const unsigned char *Items = Base + Offset;
+
+ // 'Items' starts with a 16-bit unsigned integer representing the
+ // number of items in this bucket.
+ unsigned Len = endian::readNext<uint16_t, little, unaligned>(Items);
+
+ for (unsigned i = 0; i < Len; ++i) {
+ // Read the hash.
+ hash_value_type ItemHash =
+ endian::readNext<hash_value_type, little, unaligned>(Items);
+
+ // Determine the length of the key and the data.
+ const std::pair<offset_type, offset_type> &L =
+ Info::ReadKeyDataLength(Items);
+ offset_type ItemLen = L.first + L.second;
+
+ // Compare the hashes. If they are not the same, skip the entry entirely.
+ if (ItemHash != KeyHash) {
+ Items += ItemLen;
+ continue;
+ }
+
+ // Read the key.
+ const internal_key_type &X =
+ InfoPtr->ReadKey((const unsigned char *const)Items, L.first);
+
+ // If the key doesn't match just skip reading the value.
+ if (!InfoPtr->EqualKey(X, IKey)) {
+ Items += ItemLen;
+ continue;
+ }
+
+ // The key matches!
+ return iterator(X, Items + L.first, L.second, InfoPtr);
+ }
+
+ return iterator();
+ }
+
+ iterator end() const { return iterator(); }
+
+ Info &getInfoObj() { return InfoObj; }
+
+ /// Create the hash table.
+ ///
+ /// \param Buckets is the beginning of the hash table itself, which follows
+ /// the payload of entire structure. This is the value returned by
+ /// OnDiskHashTableGenerator::Emit.
+ ///
+ /// \param Base is the point from which all offsets into the structure are
+ /// based. This is offset 0 in the stream that was used when Emitting the
+ /// table.
+ static OnDiskChainedHashTable *Create(const unsigned char *Buckets,
+ const unsigned char *const Base,
+ const Info &InfoObj = Info()) {
+ assert(Buckets > Base);
+ auto NumBucketsAndEntries = readNumBucketsAndEntries(Buckets);
+ return new OnDiskChainedHashTable<Info>(NumBucketsAndEntries.first,
+ NumBucketsAndEntries.second,
+ Buckets, Base, InfoObj);
+ }
+};
+
+/// Provides lookup and iteration over an on disk hash table.
+///
+/// \copydetails llvm::OnDiskChainedHashTable
+template <typename Info>
+class OnDiskIterableChainedHashTable : public OnDiskChainedHashTable<Info> {
+ const unsigned char *Payload;
+
+public:
+ typedef OnDiskChainedHashTable<Info> base_type;
+ typedef typename base_type::internal_key_type internal_key_type;
+ typedef typename base_type::external_key_type external_key_type;
+ typedef typename base_type::data_type data_type;
+ typedef typename base_type::hash_value_type hash_value_type;
+ typedef typename base_type::offset_type offset_type;
+
+private:
+ /// Iterates over all of the keys in the table.
+ class iterator_base {
+ const unsigned char *Ptr;
+ offset_type NumItemsInBucketLeft;
+ offset_type NumEntriesLeft;
+
+ public:
+ typedef external_key_type value_type;
+
+ iterator_base(const unsigned char *const Ptr, offset_type NumEntries)
+ : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries) {}
+ iterator_base()
+ : Ptr(nullptr), NumItemsInBucketLeft(0), NumEntriesLeft(0) {}
+
+ friend bool operator==(const iterator_base &X, const iterator_base &Y) {
+ return X.NumEntriesLeft == Y.NumEntriesLeft;
+ }
+ friend bool operator!=(const iterator_base &X, const iterator_base &Y) {
+ return X.NumEntriesLeft != Y.NumEntriesLeft;
+ }
+
+ /// Move to the next item.
+ void advance() {
+ using namespace llvm::support;
+ if (!NumItemsInBucketLeft) {
+ // 'Items' starts with a 16-bit unsigned integer representing the
+ // number of items in this bucket.
+ NumItemsInBucketLeft =
+ endian::readNext<uint16_t, little, unaligned>(Ptr);
+ }
+ Ptr += sizeof(hash_value_type); // Skip the hash.
+ // Determine the length of the key and the data.
+ const std::pair<offset_type, offset_type> &L =
+ Info::ReadKeyDataLength(Ptr);
+ Ptr += L.first + L.second;
+ assert(NumItemsInBucketLeft);
+ --NumItemsInBucketLeft;
+ assert(NumEntriesLeft);
+ --NumEntriesLeft;
+ }
+
+ /// Get the start of the item as written by the trait (after the hash and
+ /// immediately before the key and value length).
+ const unsigned char *getItem() const {
+ return Ptr + (NumItemsInBucketLeft ? 0 : 2) + sizeof(hash_value_type);
+ }
+ };
+
+public:
+ OnDiskIterableChainedHashTable(offset_type NumBuckets, offset_type NumEntries,
+ const unsigned char *Buckets,
+ const unsigned char *Payload,
+ const unsigned char *Base,
+ const Info &InfoObj = Info())
+ : base_type(NumBuckets, NumEntries, Buckets, Base, InfoObj),
+ Payload(Payload) {}
+
+ /// Iterates over all of the keys in the table.
+ class key_iterator : public iterator_base {
+ Info *InfoObj;
+
+ public:
+ typedef external_key_type value_type;
+
+ key_iterator(const unsigned char *const Ptr, offset_type NumEntries,
+ Info *InfoObj)
+ : iterator_base(Ptr, NumEntries), InfoObj(InfoObj) {}
+ key_iterator() : iterator_base(), InfoObj() {}
+
+ key_iterator &operator++() {
+ this->advance();
+ return *this;
+ }
+ key_iterator operator++(int) { // Postincrement
+ key_iterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ internal_key_type getInternalKey() const {
+ auto *LocalPtr = this->getItem();
+
+ // Determine the length of the key and the data.
+ auto L = Info::ReadKeyDataLength(LocalPtr);
+
+ // Read the key.
+ return InfoObj->ReadKey(LocalPtr, L.first);
+ }
+
+ value_type operator*() const {
+ return InfoObj->GetExternalKey(getInternalKey());
+ }
+ };
+
+ key_iterator key_begin() {
+ return key_iterator(Payload, this->getNumEntries(), &this->getInfoObj());
+ }
+ key_iterator key_end() { return key_iterator(); }
+
+ iterator_range<key_iterator> keys() {
+ return make_range(key_begin(), key_end());
+ }
+
+ /// Iterates over all the entries in the table, returning the data.
+ class data_iterator : public iterator_base {
+ Info *InfoObj;
+
+ public:
+ typedef data_type value_type;
+
+ data_iterator(const unsigned char *const Ptr, offset_type NumEntries,
+ Info *InfoObj)
+ : iterator_base(Ptr, NumEntries), InfoObj(InfoObj) {}
+ data_iterator() : iterator_base(), InfoObj() {}
+
+ data_iterator &operator++() { // Preincrement
+ this->advance();
+ return *this;
+ }
+ data_iterator operator++(int) { // Postincrement
+ data_iterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ value_type operator*() const {
+ auto *LocalPtr = this->getItem();
+
+ // Determine the length of the key and the data.
+ auto L = Info::ReadKeyDataLength(LocalPtr);
+
+ // Read the key.
+ const internal_key_type &Key = InfoObj->ReadKey(LocalPtr, L.first);
+ return InfoObj->ReadData(Key, LocalPtr + L.first, L.second);
+ }
+ };
+
+ data_iterator data_begin() {
+ return data_iterator(Payload, this->getNumEntries(), &this->getInfoObj());
+ }
+ data_iterator data_end() { return data_iterator(); }
+
+ iterator_range<data_iterator> data() {
+ return make_range(data_begin(), data_end());
+ }
+
+ /// Create the hash table.
+ ///
+ /// \param Buckets is the beginning of the hash table itself, which follows
+ /// the payload of entire structure. This is the value returned by
+ /// OnDiskHashTableGenerator::Emit.
+ ///
+ /// \param Payload is the beginning of the data contained in the table. This
+ /// is Base plus any padding or header data that was stored, ie, the offset
+ /// that the stream was at when calling Emit.
+ ///
+ /// \param Base is the point from which all offsets into the structure are
+ /// based. This is offset 0 in the stream that was used when Emitting the
+ /// table.
+ static OnDiskIterableChainedHashTable *
+ Create(const unsigned char *Buckets, const unsigned char *const Payload,
+ const unsigned char *const Base, const Info &InfoObj = Info()) {
+ assert(Buckets > Base);
+ auto NumBucketsAndEntries =
+ OnDiskIterableChainedHashTable<Info>::readNumBucketsAndEntries(Buckets);
+ return new OnDiskIterableChainedHashTable<Info>(
+ NumBucketsAndEntries.first, NumBucketsAndEntries.second,
+ Buckets, Payload, Base, InfoObj);
+ }
+};
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/OptimizedStructLayout.h b/contrib/libs/llvm16/include/llvm/Support/OptimizedStructLayout.h
new file mode 100644
index 00000000000..eff64a12a12
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/OptimizedStructLayout.h
@@ -0,0 +1,154 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- OptimizedStructLayout.h - Struct layout algorithm ---------*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides an interface for laying out a sequence of fields
+/// as a struct in a way that attempts to minimizes the total space
+/// requirements of the struct while still satisfying the layout
+/// requirements of the individual fields. The resulting layout may be
+/// substantially more compact than simply laying out the fields in their
+/// original order.
+///
+/// Fields may be pre-assigned fixed offsets. They may also be given sizes
+/// that are not multiples of their alignments. There is no currently no
+/// way to describe that a field has interior padding that other fields may
+/// be allocated into.
+///
+/// This algorithm does not claim to be "optimal" for several reasons:
+///
+/// - First, it does not guarantee that the result is minimal in size.
+/// There is no known efficient algoorithm to achieve minimality for
+/// unrestricted inputs. Nonetheless, this algorithm
+///
+/// - Second, there are other ways that a struct layout could be optimized
+/// besides space usage, such as locality. This layout may have a mixed
+/// impact on locality: less overall memory may be used, but adjacent
+/// fields in the original array may be moved further from one another.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H
+#define LLVM_SUPPORT_OPTIMIZEDSTRUCTLAYOUT_H
+
+#include "llvm/Support/Alignment.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <utility>
+
+namespace llvm {
+
+/// A field in a structure.
+struct OptimizedStructLayoutField {
+ /// A special value for Offset indicating that the field can be moved
+ /// anywhere.
+ static constexpr uint64_t FlexibleOffset = ~(uint64_t)0;
+
+ OptimizedStructLayoutField(const void *Id, uint64_t Size, Align Alignment,
+ uint64_t FixedOffset = FlexibleOffset)
+ : Offset(FixedOffset), Size(Size), Id(Id), Alignment(Alignment) {
+ assert(Size > 0 && "adding an empty field to the layout");
+ }
+
+ /// The offset of this field in the final layout. If this is
+ /// initialized to FlexibleOffset, layout will overwrite it with
+ /// the assigned offset of the field.
+ uint64_t Offset;
+
+ /// The required size of this field in bytes. Does not have to be
+ /// a multiple of Alignment. Must be non-zero.
+ uint64_t Size;
+
+ /// A opaque value which uniquely identifies this field.
+ const void *Id;
+
+ /// Private scratch space for the algorithm. The implementation
+ /// must treat this as uninitialized memory on entry.
+ void *Scratch;
+
+ /// The required alignment of this field.
+ Align Alignment;
+
+ /// Return true if this field has been assigned a fixed offset.
+ /// After layout, this will be true of all the fields.
+ bool hasFixedOffset() const {
+ return (Offset != FlexibleOffset);
+ }
+
+ /// Given that this field has a fixed offset, return the offset
+ /// of the first byte following it.
+ uint64_t getEndOffset() const {
+ assert(hasFixedOffset());
+ return Offset + Size;
+ }
+};
+
+/// Compute a layout for a struct containing the given fields, making a
+/// best-effort attempt to minimize the amount of space required.
+///
+/// Two features are supported which require a more careful solution
+/// than the well-known "sort by decreasing alignment" solution:
+///
+/// - Fields may be assigned a fixed offset in the layout. If there are
+/// gaps among the fixed-offset fields, the algorithm may attempt
+/// to allocate flexible-offset fields into those gaps. If that's
+/// undesirable, the caller should "block out" those gaps by e.g.
+/// just creating a single fixed-offset field that represents the
+/// entire "header".
+///
+/// - The size of a field is not required to be a multiple of, or even
+/// greater than, the field's required alignment. The only constraint
+/// on fields is that they must not be zero-sized.
+///
+/// To simplify the implementation, any fixed-offset fields in the
+/// layout must appear at the start of the field array, and they must
+/// be ordered by increasing offset.
+///
+/// The algorithm will produce a guaranteed-minimal layout with no
+/// interior padding in the following "C-style" case:
+///
+/// - every field's size is a multiple of its required alignment and
+/// - either no fields have initially fixed offsets, or the fixed-offset
+/// fields have no interior padding and end at an offset that is at
+/// least as aligned as all the flexible-offset fields.
+///
+/// Otherwise, while the algorithm will make a best-effort attempt to
+/// avoid padding, it cannot guarantee a minimal layout, as there is
+/// no known efficient algorithm for doing so.
+///
+/// The layout produced by this algorithm may not be stable across LLVM
+/// releases. Do not use this anywhere where ABI stability is required.
+///
+/// Flexible-offset fields with the same size and alignment will be ordered
+/// the same way they were in the initial array. Otherwise the current
+/// algorithm makes no effort to preserve the initial order of
+/// flexible-offset fields.
+///
+/// On return, all fields will have been assigned a fixed offset, and the
+/// array will be sorted in order of ascending offsets. Note that this
+/// means that the fixed-offset fields may no longer form a strict prefix
+/// if there's any padding before they end.
+///
+/// The return value is the total size of the struct and its required
+/// alignment. Note that the total size is not rounded up to a multiple
+/// of the required alignment; clients which require this can do so easily.
+std::pair<uint64_t, Align> performOptimizedStructLayout(
+ MutableArrayRef<OptimizedStructLayoutField> Fields);
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/PGOOptions.h b/contrib/libs/llvm16/include/llvm/Support/PGOOptions.h
new file mode 100644
index 00000000000..4a65ebd4621
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/PGOOptions.h
@@ -0,0 +1,76 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===------ PGOOptions.h -- PGO option tunables ----------------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// Define option tunables for PGO.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PGOOPTIONS_H
+#define LLVM_SUPPORT_PGOOPTIONS_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+/// A struct capturing PGO tunables.
+struct PGOOptions {
+ enum PGOAction { NoAction, IRInstr, IRUse, SampleUse };
+ enum CSPGOAction { NoCSAction, CSIRInstr, CSIRUse };
+ PGOOptions(std::string ProfileFile = "", std::string CSProfileGenFile = "",
+ std::string ProfileRemappingFile = "", PGOAction Action = NoAction,
+ CSPGOAction CSAction = NoCSAction,
+ bool DebugInfoForProfiling = false,
+ bool PseudoProbeForProfiling = false)
+ : ProfileFile(ProfileFile), CSProfileGenFile(CSProfileGenFile),
+ ProfileRemappingFile(ProfileRemappingFile), Action(Action),
+ CSAction(CSAction), DebugInfoForProfiling(DebugInfoForProfiling ||
+ (Action == SampleUse &&
+ !PseudoProbeForProfiling)),
+ PseudoProbeForProfiling(PseudoProbeForProfiling) {
+ // Note, we do allow ProfileFile.empty() for Action=IRUse LTO can
+ // callback with IRUse action without ProfileFile.
+
+ // If there is a CSAction, PGOAction cannot be IRInstr or SampleUse.
+ assert(this->CSAction == NoCSAction ||
+ (this->Action != IRInstr && this->Action != SampleUse));
+
+ // For CSIRInstr, CSProfileGenFile also needs to be nonempty.
+ assert(this->CSAction != CSIRInstr || !this->CSProfileGenFile.empty());
+
+ // If CSAction is CSIRUse, PGOAction needs to be IRUse as they share
+ // a profile.
+ assert(this->CSAction != CSIRUse || this->Action == IRUse);
+
+ // If neither Action nor CSAction, DebugInfoForProfiling or
+ // PseudoProbeForProfiling needs to be true.
+ assert(this->Action != NoAction || this->CSAction != NoCSAction ||
+ this->DebugInfoForProfiling || this->PseudoProbeForProfiling);
+ }
+ std::string ProfileFile;
+ std::string CSProfileGenFile;
+ std::string ProfileRemappingFile;
+ PGOAction Action;
+ CSPGOAction CSAction;
+ bool DebugInfoForProfiling;
+ bool PseudoProbeForProfiling;
+};
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Parallel.h b/contrib/libs/llvm16/include/llvm/Support/Parallel.h
new file mode 100644
index 00000000000..c3b729e55ca
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Parallel.h
@@ -0,0 +1,303 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Parallel.h - Parallel algorithms ----------------------===//
+//
+// 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 LLVM_SUPPORT_PARALLEL_H
+#define LLVM_SUPPORT_PARALLEL_H
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Threading.h"
+
+#include <algorithm>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+
+namespace llvm {
+
+namespace parallel {
+
+// Strategy for the default executor used by the parallel routines provided by
+// this file. It defaults to using all hardware threads and should be
+// initialized before the first use of parallel routines.
+extern ThreadPoolStrategy strategy;
+
+#if LLVM_ENABLE_THREADS
+#ifdef _WIN32
+// Direct access to thread_local variables from a different DLL isn't
+// possible with Windows Native TLS.
+unsigned getThreadIndex();
+#else
+// Don't access this directly, use the getThreadIndex wrapper.
+extern thread_local unsigned threadIndex;
+
+inline unsigned getThreadIndex() { return threadIndex; }
+#endif
+#else
+inline unsigned getThreadIndex() { return 0; }
+#endif
+
+namespace detail {
+class Latch {
+ uint32_t Count;
+ mutable std::mutex Mutex;
+ mutable std::condition_variable Cond;
+
+public:
+ explicit Latch(uint32_t Count = 0) : Count(Count) {}
+ ~Latch() {
+ // Ensure at least that sync() was called.
+ assert(Count == 0);
+ }
+
+ void inc() {
+ std::lock_guard<std::mutex> lock(Mutex);
+ ++Count;
+ }
+
+ void dec() {
+ std::lock_guard<std::mutex> lock(Mutex);
+ if (--Count == 0)
+ Cond.notify_all();
+ }
+
+ void sync() const {
+ std::unique_lock<std::mutex> lock(Mutex);
+ Cond.wait(lock, [&] { return Count == 0; });
+ }
+};
+} // namespace detail
+
+class TaskGroup {
+ detail::Latch L;
+ bool Parallel;
+
+public:
+ TaskGroup();
+ ~TaskGroup();
+
+ // Spawn a task, but does not wait for it to finish.
+ void spawn(std::function<void()> f);
+
+ // Similar to spawn, but execute the task immediately when ThreadsRequested ==
+ // 1. The difference is to give the following pattern a more intuitive order
+ // when single threading is requested.
+ //
+ // for (size_t begin = 0, i = 0, taskSize = 0;;) {
+ // taskSize += ...
+ // bool done = ++i == end;
+ // if (done || taskSize >= taskSizeLimit) {
+ // tg.execute([=] { fn(begin, i); });
+ // if (done)
+ // break;
+ // begin = i;
+ // taskSize = 0;
+ // }
+ // }
+ void execute(std::function<void()> f);
+
+ void sync() const { L.sync(); }
+};
+
+namespace detail {
+
+#if LLVM_ENABLE_THREADS
+const ptrdiff_t MinParallelSize = 1024;
+
+/// Inclusive median.
+template <class RandomAccessIterator, class Comparator>
+RandomAccessIterator medianOf3(RandomAccessIterator Start,
+ RandomAccessIterator End,
+ const Comparator &Comp) {
+ RandomAccessIterator Mid = Start + (std::distance(Start, End) / 2);
+ return Comp(*Start, *(End - 1))
+ ? (Comp(*Mid, *(End - 1)) ? (Comp(*Start, *Mid) ? Mid : Start)
+ : End - 1)
+ : (Comp(*Mid, *Start) ? (Comp(*(End - 1), *Mid) ? Mid : End - 1)
+ : Start);
+}
+
+template <class RandomAccessIterator, class Comparator>
+void parallel_quick_sort(RandomAccessIterator Start, RandomAccessIterator End,
+ const Comparator &Comp, TaskGroup &TG, size_t Depth) {
+ // Do a sequential sort for small inputs.
+ if (std::distance(Start, End) < detail::MinParallelSize || Depth == 0) {
+ llvm::sort(Start, End, Comp);
+ return;
+ }
+
+ // Partition.
+ auto Pivot = medianOf3(Start, End, Comp);
+ // Move Pivot to End.
+ std::swap(*(End - 1), *Pivot);
+ Pivot = std::partition(Start, End - 1, [&Comp, End](decltype(*Start) V) {
+ return Comp(V, *(End - 1));
+ });
+ // Move Pivot to middle of partition.
+ std::swap(*Pivot, *(End - 1));
+
+ // Recurse.
+ TG.spawn([=, &Comp, &TG] {
+ parallel_quick_sort(Start, Pivot, Comp, TG, Depth - 1);
+ });
+ parallel_quick_sort(Pivot + 1, End, Comp, TG, Depth - 1);
+}
+
+template <class RandomAccessIterator, class Comparator>
+void parallel_sort(RandomAccessIterator Start, RandomAccessIterator End,
+ const Comparator &Comp) {
+ TaskGroup TG;
+ parallel_quick_sort(Start, End, Comp, TG,
+ llvm::Log2_64(std::distance(Start, End)) + 1);
+}
+
+// TaskGroup has a relatively high overhead, so we want to reduce
+// the number of spawn() calls. We'll create up to 1024 tasks here.
+// (Note that 1024 is an arbitrary number. This code probably needs
+// improving to take the number of available cores into account.)
+enum { MaxTasksPerGroup = 1024 };
+
+template <class IterTy, class ResultTy, class ReduceFuncTy,
+ class TransformFuncTy>
+ResultTy parallel_transform_reduce(IterTy Begin, IterTy End, ResultTy Init,
+ ReduceFuncTy Reduce,
+ TransformFuncTy Transform) {
+ // Limit the number of tasks to MaxTasksPerGroup to limit job scheduling
+ // overhead on large inputs.
+ size_t NumInputs = std::distance(Begin, End);
+ if (NumInputs == 0)
+ return std::move(Init);
+ size_t NumTasks = std::min(static_cast<size_t>(MaxTasksPerGroup), NumInputs);
+ std::vector<ResultTy> Results(NumTasks, Init);
+ {
+ // Each task processes either TaskSize or TaskSize+1 inputs. Any inputs
+ // remaining after dividing them equally amongst tasks are distributed as
+ // one extra input over the first tasks.
+ TaskGroup TG;
+ size_t TaskSize = NumInputs / NumTasks;
+ size_t RemainingInputs = NumInputs % NumTasks;
+ IterTy TBegin = Begin;
+ for (size_t TaskId = 0; TaskId < NumTasks; ++TaskId) {
+ IterTy TEnd = TBegin + TaskSize + (TaskId < RemainingInputs ? 1 : 0);
+ TG.spawn([=, &Transform, &Reduce, &Results] {
+ // Reduce the result of transformation eagerly within each task.
+ ResultTy R = Init;
+ for (IterTy It = TBegin; It != TEnd; ++It)
+ R = Reduce(R, Transform(*It));
+ Results[TaskId] = R;
+ });
+ TBegin = TEnd;
+ }
+ assert(TBegin == End);
+ }
+
+ // Do a final reduction. There are at most 1024 tasks, so this only adds
+ // constant single-threaded overhead for large inputs. Hopefully most
+ // reductions are cheaper than the transformation.
+ ResultTy FinalResult = std::move(Results.front());
+ for (ResultTy &PartialResult :
+ MutableArrayRef(Results.data() + 1, Results.size() - 1))
+ FinalResult = Reduce(FinalResult, std::move(PartialResult));
+ return std::move(FinalResult);
+}
+
+#endif
+
+} // namespace detail
+} // namespace parallel
+
+template <class RandomAccessIterator,
+ class Comparator = std::less<
+ typename std::iterator_traits<RandomAccessIterator>::value_type>>
+void parallelSort(RandomAccessIterator Start, RandomAccessIterator End,
+ const Comparator &Comp = Comparator()) {
+#if LLVM_ENABLE_THREADS
+ if (parallel::strategy.ThreadsRequested != 1) {
+ parallel::detail::parallel_sort(Start, End, Comp);
+ return;
+ }
+#endif
+ llvm::sort(Start, End, Comp);
+}
+
+void parallelFor(size_t Begin, size_t End, function_ref<void(size_t)> Fn);
+
+template <class IterTy, class FuncTy>
+void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn) {
+ parallelFor(0, End - Begin, [&](size_t I) { Fn(Begin[I]); });
+}
+
+template <class IterTy, class ResultTy, class ReduceFuncTy,
+ class TransformFuncTy>
+ResultTy parallelTransformReduce(IterTy Begin, IterTy End, ResultTy Init,
+ ReduceFuncTy Reduce,
+ TransformFuncTy Transform) {
+#if LLVM_ENABLE_THREADS
+ if (parallel::strategy.ThreadsRequested != 1) {
+ return parallel::detail::parallel_transform_reduce(Begin, End, Init, Reduce,
+ Transform);
+ }
+#endif
+ for (IterTy I = Begin; I != End; ++I)
+ Init = Reduce(std::move(Init), Transform(*I));
+ return std::move(Init);
+}
+
+// Range wrappers.
+template <class RangeTy,
+ class Comparator = std::less<decltype(*std::begin(RangeTy()))>>
+void parallelSort(RangeTy &&R, const Comparator &Comp = Comparator()) {
+ parallelSort(std::begin(R), std::end(R), Comp);
+}
+
+template <class RangeTy, class FuncTy>
+void parallelForEach(RangeTy &&R, FuncTy Fn) {
+ parallelForEach(std::begin(R), std::end(R), Fn);
+}
+
+template <class RangeTy, class ResultTy, class ReduceFuncTy,
+ class TransformFuncTy>
+ResultTy parallelTransformReduce(RangeTy &&R, ResultTy Init,
+ ReduceFuncTy Reduce,
+ TransformFuncTy Transform) {
+ return parallelTransformReduce(std::begin(R), std::end(R), Init, Reduce,
+ Transform);
+}
+
+// Parallel for-each, but with error handling.
+template <class RangeTy, class FuncTy>
+Error parallelForEachError(RangeTy &&R, FuncTy Fn) {
+ // The transform_reduce algorithm requires that the initial value be copyable.
+ // Error objects are uncopyable. We only need to copy initial success values,
+ // so work around this mismatch via the C API. The C API represents success
+ // values with a null pointer. The joinErrors discards null values and joins
+ // multiple errors into an ErrorList.
+ return unwrap(parallelTransformReduce(
+ std::begin(R), std::end(R), wrap(Error::success()),
+ [](LLVMErrorRef Lhs, LLVMErrorRef Rhs) {
+ return wrap(joinErrors(unwrap(Lhs), unwrap(Rhs)));
+ },
+ [&Fn](auto &&V) { return wrap(Fn(V)); }));
+}
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_PARALLEL_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Path.h b/contrib/libs/llvm16/include/llvm/Support/Path.h
new file mode 100644
index 00000000000..0e2dd79c737
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Path.h
@@ -0,0 +1,564 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Path.h - Path Operating System Concept ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::path namespace. It is designed after
+// TR2/boost filesystem (v3), but modified to remove exception handling and the
+// path class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PATH_H
+#define LLVM_SUPPORT_PATH_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/Support/DataTypes.h"
+#include <iterator>
+
+namespace llvm {
+namespace sys {
+namespace path {
+
+enum class Style {
+ native,
+ posix,
+ windows_slash,
+ windows_backslash,
+ windows = windows_backslash, // deprecated
+};
+
+/// Check if \p S uses POSIX path rules.
+constexpr bool is_style_posix(Style S) {
+ if (S == Style::posix)
+ return true;
+ if (S != Style::native)
+ return false;
+#if defined(_WIN32)
+ return false;
+#else
+ return true;
+#endif
+}
+
+/// Check if \p S uses Windows path rules.
+constexpr bool is_style_windows(Style S) { return !is_style_posix(S); }
+
+/// @name Lexical Component Iterator
+/// @{
+
+/// Path iterator.
+///
+/// This is an input iterator that iterates over the individual components in
+/// \a path. The traversal order is as follows:
+/// * The root-name element, if present.
+/// * The root-directory element, if present.
+/// * Each successive filename element, if present.
+/// * Dot, if one or more trailing non-root slash characters are present.
+/// Traversing backwards is possible with \a reverse_iterator
+///
+/// Iteration examples. Each component is separated by ',':
+/// @code
+/// / => /
+/// /foo => /,foo
+/// foo/ => foo,.
+/// /foo/bar => /,foo,bar
+/// ../ => ..,.
+/// C:\foo\bar => C:,\,foo,bar
+/// @endcode
+class const_iterator
+ : public iterator_facade_base<const_iterator, std::input_iterator_tag,
+ const StringRef> {
+ StringRef Path; ///< The entire path.
+ StringRef Component; ///< The current component. Not necessarily in Path.
+ size_t Position = 0; ///< The iterators current position within Path.
+ Style S = Style::native; ///< The path style to use.
+
+ // An end iterator has Position = Path.size() + 1.
+ friend const_iterator begin(StringRef path, Style style);
+ friend const_iterator end(StringRef path);
+
+public:
+ reference operator*() const { return Component; }
+ const_iterator &operator++(); // preincrement
+ bool operator==(const const_iterator &RHS) const;
+
+ /// Difference in bytes between this and RHS.
+ ptrdiff_t operator-(const const_iterator &RHS) const;
+};
+
+/// Reverse path iterator.
+///
+/// This is an input iterator that iterates over the individual components in
+/// \a path in reverse order. The traversal order is exactly reversed from that
+/// of \a const_iterator
+class reverse_iterator
+ : public iterator_facade_base<reverse_iterator, std::input_iterator_tag,
+ const StringRef> {
+ StringRef Path; ///< The entire path.
+ StringRef Component; ///< The current component. Not necessarily in Path.
+ size_t Position = 0; ///< The iterators current position within Path.
+ Style S = Style::native; ///< The path style to use.
+
+ friend reverse_iterator rbegin(StringRef path, Style style);
+ friend reverse_iterator rend(StringRef path);
+
+public:
+ reference operator*() const { return Component; }
+ reverse_iterator &operator++(); // preincrement
+ bool operator==(const reverse_iterator &RHS) const;
+
+ /// Difference in bytes between this and RHS.
+ ptrdiff_t operator-(const reverse_iterator &RHS) const;
+};
+
+/// Get begin iterator over \a path.
+/// @param path Input path.
+/// @returns Iterator initialized with the first component of \a path.
+const_iterator begin(StringRef path, Style style = Style::native);
+
+/// Get end iterator over \a path.
+/// @param path Input path.
+/// @returns Iterator initialized to the end of \a path.
+const_iterator end(StringRef path);
+
+/// Get reverse begin iterator over \a path.
+/// @param path Input path.
+/// @returns Iterator initialized with the first reverse component of \a path.
+reverse_iterator rbegin(StringRef path, Style style = Style::native);
+
+/// Get reverse end iterator over \a path.
+/// @param path Input path.
+/// @returns Iterator initialized to the reverse end of \a path.
+reverse_iterator rend(StringRef path);
+
+/// @}
+/// @name Lexical Modifiers
+/// @{
+
+/// Remove the last component from \a path unless it is the root dir.
+///
+/// Similar to the POSIX "dirname" utility.
+///
+/// @code
+/// directory/filename.cpp => directory/
+/// directory/ => directory
+/// filename.cpp => <empty>
+/// / => /
+/// @endcode
+///
+/// @param path A path that is modified to not have a file component.
+void remove_filename(SmallVectorImpl<char> &path, Style style = Style::native);
+
+/// Replace the file extension of \a path with \a extension.
+///
+/// @code
+/// ./filename.cpp => ./filename.extension
+/// ./filename => ./filename.extension
+/// ./ => ./.extension
+/// @endcode
+///
+/// @param path A path that has its extension replaced with \a extension.
+/// @param extension The extension to be added. It may be empty. It may also
+/// optionally start with a '.', if it does not, one will be
+/// prepended.
+void replace_extension(SmallVectorImpl<char> &path, const Twine &extension,
+ Style style = Style::native);
+
+/// Replace matching path prefix with another path.
+///
+/// @code
+/// /foo, /old, /new => /foo
+/// /old, /old, /new => /new
+/// /old, /old/, /new => /old
+/// /old/foo, /old, /new => /new/foo
+/// /old/foo, /old/, /new => /new/foo
+/// /old/foo, /old/, /new/ => /new/foo
+/// /oldfoo, /old, /new => /oldfoo
+/// /foo, <empty>, /new => /new/foo
+/// /foo, <empty>, new => new/foo
+/// /old/foo, /old, <empty> => /foo
+/// @endcode
+///
+/// @param Path If \a Path starts with \a OldPrefix modify to instead
+/// start with \a NewPrefix.
+/// @param OldPrefix The path prefix to strip from \a Path.
+/// @param NewPrefix The path prefix to replace \a NewPrefix with.
+/// @param style The style used to match the prefix. Exact match using
+/// Posix style, case/separator insensitive match for Windows style.
+/// @result true if \a Path begins with OldPrefix
+bool replace_path_prefix(SmallVectorImpl<char> &Path, StringRef OldPrefix,
+ StringRef NewPrefix,
+ Style style = Style::native);
+
+/// Remove redundant leading "./" pieces and consecutive separators.
+///
+/// @param path Input path.
+/// @result The cleaned-up \a path.
+StringRef remove_leading_dotslash(StringRef path, Style style = Style::native);
+
+/// In-place remove any './' and optionally '../' components from a path.
+///
+/// @param path processed path
+/// @param remove_dot_dot specify if '../' (except for leading "../") should be
+/// removed
+/// @result True if path was changed
+bool remove_dots(SmallVectorImpl<char> &path, bool remove_dot_dot = false,
+ Style style = Style::native);
+
+/// Append to path.
+///
+/// @code
+/// /foo + bar/f => /foo/bar/f
+/// /foo/ + bar/f => /foo/bar/f
+/// foo + bar/f => foo/bar/f
+/// @endcode
+///
+/// @param path Set to \a path + \a component.
+/// @param a The component to be appended to \a path.
+void append(SmallVectorImpl<char> &path, const Twine &a,
+ const Twine &b = "",
+ const Twine &c = "",
+ const Twine &d = "");
+
+void append(SmallVectorImpl<char> &path, Style style, const Twine &a,
+ const Twine &b = "", const Twine &c = "", const Twine &d = "");
+
+/// Append to path.
+///
+/// @code
+/// /foo + [bar,f] => /foo/bar/f
+/// /foo/ + [bar,f] => /foo/bar/f
+/// foo + [bar,f] => foo/bar/f
+/// @endcode
+///
+/// @param path Set to \a path + [\a begin, \a end).
+/// @param begin Start of components to append.
+/// @param end One past the end of components to append.
+void append(SmallVectorImpl<char> &path, const_iterator begin,
+ const_iterator end, Style style = Style::native);
+
+/// @}
+/// @name Transforms (or some other better name)
+/// @{
+
+/// Convert path to the native form. This is used to give paths to users and
+/// operating system calls in the platform's normal way. For example, on Windows
+/// all '/' are converted to '\'. On Unix, it converts all '\' to '/'.
+///
+/// @param path A path that is transformed to native format.
+/// @param result Holds the result of the transformation.
+void native(const Twine &path, SmallVectorImpl<char> &result,
+ Style style = Style::native);
+
+/// Convert path to the native form in place. This is used to give paths to
+/// users and operating system calls in the platform's normal way. For example,
+/// on Windows all '/' are converted to '\'.
+///
+/// @param path A path that is transformed to native format.
+void native(SmallVectorImpl<char> &path, Style style = Style::native);
+
+/// For Windows path styles, convert path to use the preferred path separators.
+/// For other styles, do nothing.
+///
+/// @param path A path that is transformed to preferred format.
+inline void make_preferred(SmallVectorImpl<char> &path,
+ Style style = Style::native) {
+ if (!is_style_windows(style))
+ return;
+ native(path, style);
+}
+
+/// Replaces backslashes with slashes if Windows.
+///
+/// @param path processed path
+/// @result The result of replacing backslashes with forward slashes if Windows.
+/// On Unix, this function is a no-op because backslashes are valid path
+/// chracters.
+std::string convert_to_slash(StringRef path, Style style = Style::native);
+
+/// @}
+/// @name Lexical Observers
+/// @{
+
+/// Get root name.
+///
+/// @code
+/// //net/hello => //net
+/// c:/hello => c: (on Windows, on other platforms nothing)
+/// /hello => <empty>
+/// @endcode
+///
+/// @param path Input path.
+/// @result The root name of \a path if it has one, otherwise "".
+StringRef root_name(StringRef path, Style style = Style::native);
+
+/// Get root directory.
+///
+/// @code
+/// /goo/hello => /
+/// c:/hello => /
+/// d/file.txt => <empty>
+/// @endcode
+///
+/// @param path Input path.
+/// @result The root directory of \a path if it has one, otherwise
+/// "".
+StringRef root_directory(StringRef path, Style style = Style::native);
+
+/// Get root path.
+///
+/// Equivalent to root_name + root_directory.
+///
+/// @param path Input path.
+/// @result The root path of \a path if it has one, otherwise "".
+StringRef root_path(StringRef path, Style style = Style::native);
+
+/// Get relative path.
+///
+/// @code
+/// C:\hello\world => hello\world
+/// foo/bar => foo/bar
+/// /foo/bar => foo/bar
+/// @endcode
+///
+/// @param path Input path.
+/// @result The path starting after root_path if one exists, otherwise "".
+StringRef relative_path(StringRef path, Style style = Style::native);
+
+/// Get parent path.
+///
+/// @code
+/// / => <empty>
+/// /foo => /
+/// foo/../bar => foo/..
+/// @endcode
+///
+/// @param path Input path.
+/// @result The parent path of \a path if one exists, otherwise "".
+StringRef parent_path(StringRef path, Style style = Style::native);
+
+/// Get filename.
+///
+/// @code
+/// /foo.txt => foo.txt
+/// . => .
+/// .. => ..
+/// / => /
+/// @endcode
+///
+/// @param path Input path.
+/// @result The filename part of \a path. This is defined as the last component
+/// of \a path. Similar to the POSIX "basename" utility.
+StringRef filename(StringRef path, Style style = Style::native);
+
+/// Get stem.
+///
+/// If filename contains a dot but not solely one or two dots, result is the
+/// substring of filename ending at (but not including) the last dot. Otherwise
+/// it is filename.
+///
+/// @code
+/// /foo/bar.txt => bar
+/// /foo/bar => bar
+/// /foo/.txt => <empty>
+/// /foo/. => .
+/// /foo/.. => ..
+/// @endcode
+///
+/// @param path Input path.
+/// @result The stem of \a path.
+StringRef stem(StringRef path, Style style = Style::native);
+
+/// Get extension.
+///
+/// If filename contains a dot but not solely one or two dots, result is the
+/// substring of filename starting at (and including) the last dot, and ending
+/// at the end of \a path. Otherwise "".
+///
+/// @code
+/// /foo/bar.txt => .txt
+/// /foo/bar => <empty>
+/// /foo/.txt => .txt
+/// @endcode
+///
+/// @param path Input path.
+/// @result The extension of \a path.
+StringRef extension(StringRef path, Style style = Style::native);
+
+/// Check whether the given char is a path separator on the host OS.
+///
+/// @param value a character
+/// @result true if \a value is a path separator character on the host OS
+bool is_separator(char value, Style style = Style::native);
+
+/// Return the preferred separator for this platform.
+///
+/// @result StringRef of the preferred separator, null-terminated.
+StringRef get_separator(Style style = Style::native);
+
+/// Get the typical temporary directory for the system, e.g.,
+/// "/var/tmp" or "C:/TEMP"
+///
+/// @param erasedOnReboot Whether to favor a path that is erased on reboot
+/// rather than one that potentially persists longer. This parameter will be
+/// ignored if the user or system has set the typical environment variable
+/// (e.g., TEMP on Windows, TMPDIR on *nix) to specify a temporary directory.
+///
+/// @param result Holds the resulting path name.
+void system_temp_directory(bool erasedOnReboot, SmallVectorImpl<char> &result);
+
+/// Get the user's home directory.
+///
+/// @param result Holds the resulting path name.
+/// @result True if a home directory is set, false otherwise.
+bool home_directory(SmallVectorImpl<char> &result);
+
+/// Get the directory where packages should read user-specific configurations.
+/// e.g. $XDG_CONFIG_HOME.
+///
+/// @param result Holds the resulting path name.
+/// @result True if the appropriate path was determined, it need not exist.
+bool user_config_directory(SmallVectorImpl<char> &result);
+
+/// Get the directory where installed packages should put their
+/// machine-local cache, e.g. $XDG_CACHE_HOME.
+///
+/// @param result Holds the resulting path name.
+/// @result True if the appropriate path was determined, it need not exist.
+bool cache_directory(SmallVectorImpl<char> &result);
+
+/// Has root name?
+///
+/// root_name != ""
+///
+/// @param path Input path.
+/// @result True if the path has a root name, false otherwise.
+bool has_root_name(const Twine &path, Style style = Style::native);
+
+/// Has root directory?
+///
+/// root_directory != ""
+///
+/// @param path Input path.
+/// @result True if the path has a root directory, false otherwise.
+bool has_root_directory(const Twine &path, Style style = Style::native);
+
+/// Has root path?
+///
+/// root_path != ""
+///
+/// @param path Input path.
+/// @result True if the path has a root path, false otherwise.
+bool has_root_path(const Twine &path, Style style = Style::native);
+
+/// Has relative path?
+///
+/// relative_path != ""
+///
+/// @param path Input path.
+/// @result True if the path has a relative path, false otherwise.
+bool has_relative_path(const Twine &path, Style style = Style::native);
+
+/// Has parent path?
+///
+/// parent_path != ""
+///
+/// @param path Input path.
+/// @result True if the path has a parent path, false otherwise.
+bool has_parent_path(const Twine &path, Style style = Style::native);
+
+/// Has filename?
+///
+/// filename != ""
+///
+/// @param path Input path.
+/// @result True if the path has a filename, false otherwise.
+bool has_filename(const Twine &path, Style style = Style::native);
+
+/// Has stem?
+///
+/// stem != ""
+///
+/// @param path Input path.
+/// @result True if the path has a stem, false otherwise.
+bool has_stem(const Twine &path, Style style = Style::native);
+
+/// Has extension?
+///
+/// extension != ""
+///
+/// @param path Input path.
+/// @result True if the path has a extension, false otherwise.
+bool has_extension(const Twine &path, Style style = Style::native);
+
+/// Is path absolute?
+///
+/// According to cppreference.com, C++17 states: "An absolute path is a path
+/// that unambiguously identifies the location of a file without reference to
+/// an additional starting location."
+///
+/// In other words, the rules are:
+/// 1) POSIX style paths with nonempty root directory are absolute.
+/// 2) Windows style paths with nonempty root name and root directory are
+/// absolute.
+/// 3) No other paths are absolute.
+///
+/// \see has_root_name
+/// \see has_root_directory
+///
+/// @param path Input path.
+/// @result True if the path is absolute, false if it is not.
+bool is_absolute(const Twine &path, Style style = Style::native);
+
+/// Is path absolute using GNU rules?
+///
+/// GNU rules are:
+/// 1) Paths starting with a path separator are absolute.
+/// 2) Windows style paths are also absolute if they start with a character
+/// followed by ':'.
+/// 3) No other paths are absolute.
+///
+/// On Windows style the path "C:\Users\Default" has "C:" as root name and "\"
+/// as root directory.
+///
+/// Hence "C:" on Windows is absolute under GNU rules and not absolute under
+/// C++17 because it has no root directory. Likewise "/" and "\" on Windows are
+/// absolute under GNU and are not absolute under C++17 due to empty root name.
+///
+/// \see has_root_name
+/// \see has_root_directory
+///
+/// @param path Input path.
+/// @param style The style of \p path (e.g. Windows or POSIX). "native" style
+/// means to derive the style from the host.
+/// @result True if the path is absolute following GNU rules, false if it is
+/// not.
+bool is_absolute_gnu(const Twine &path, Style style = Style::native);
+
+/// Is path relative?
+///
+/// @param path Input path.
+/// @result True if the path is relative, false if it is not.
+bool is_relative(const Twine &path, Style style = Style::native);
+
+} // end namespace path
+} // end namespace sys
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/PluginLoader.h b/contrib/libs/llvm16/include/llvm/Support/PluginLoader.h
new file mode 100644
index 00000000000..2a502e99c4e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/PluginLoader.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/PluginLoader.h - Plugin Loader for Tools ---*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A tool can #include this file to get a -load option that allows the user to
+// load arbitrary shared objects into the tool's address space. Note that this
+// header can only be included by a program ONCE, so it should never to used by
+// library authors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PLUGINLOADER_H
+#define LLVM_SUPPORT_PLUGINLOADER_H
+
+#ifndef DONT_GET_PLUGIN_LOADER_OPTION
+#include "llvm/Support/CommandLine.h"
+#endif
+
+#include <string>
+
+namespace llvm {
+ struct PluginLoader {
+ void operator=(const std::string &Filename);
+ static unsigned getNumPlugins();
+ static std::string& getPlugin(unsigned num);
+ };
+
+#ifndef DONT_GET_PLUGIN_LOADER_OPTION
+ // This causes operator= above to be invoked for every -load option.
+ static cl::opt<PluginLoader, false, cl::parser<std::string>>
+ LoadOpt("load", cl::value_desc("pluginfilename"),
+ cl::desc("Load the specified plugin"));
+#endif
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/PointerLikeTypeTraits.h b/contrib/libs/llvm16/include/llvm/Support/PointerLikeTypeTraits.h
new file mode 100644
index 00000000000..1766deb45c0
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/PointerLikeTypeTraits.h
@@ -0,0 +1,163 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- 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 defines the PointerLikeTypeTraits class. This allows data
+// structures to reason about pointers and other things that are pointer sized.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
+#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
+
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+#include <type_traits>
+
+namespace llvm {
+
+/// A traits type that is used to handle pointer types and things that are just
+/// wrappers for pointers as a uniform entity.
+template <typename T> struct PointerLikeTypeTraits;
+
+namespace detail {
+/// A tiny meta function to compute the log2 of a compile time constant.
+template <size_t N>
+struct ConstantLog2
+ : std::integral_constant<size_t, ConstantLog2<N / 2>::value + 1> {};
+template <> struct ConstantLog2<1> : std::integral_constant<size_t, 0> {};
+
+// Provide a trait to check if T is pointer-like.
+template <typename T, typename U = void> struct HasPointerLikeTypeTraits {
+ static const bool value = false;
+};
+
+// sizeof(T) is valid only for a complete T.
+template <typename T>
+struct HasPointerLikeTypeTraits<
+ T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
+ static const bool value = true;
+};
+
+template <typename T> struct IsPointerLike {
+ static const bool value = HasPointerLikeTypeTraits<T>::value;
+};
+
+template <typename T> struct IsPointerLike<T *> {
+ static const bool value = true;
+};
+} // namespace detail
+
+// Provide PointerLikeTypeTraits for non-cvr pointers.
+template <typename T> struct PointerLikeTypeTraits<T *> {
+ static inline void *getAsVoidPointer(T *P) { return P; }
+ static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
+
+ static constexpr int NumLowBitsAvailable =
+ detail::ConstantLog2<alignof(T)>::value;
+};
+
+template <> struct PointerLikeTypeTraits<void *> {
+ static inline void *getAsVoidPointer(void *P) { return P; }
+ static inline void *getFromVoidPointer(void *P) { return P; }
+
+ /// Note, we assume here that void* is related to raw malloc'ed memory and
+ /// that malloc returns objects at least 4-byte aligned. However, this may be
+ /// wrong, or pointers may be from something other than malloc. In this case,
+ /// you should specify a real typed pointer or avoid this template.
+ ///
+ /// All clients should use assertions to do a run-time check to ensure that
+ /// this is actually true.
+ static constexpr int NumLowBitsAvailable = 2;
+};
+
+// Provide PointerLikeTypeTraits for const things.
+template <typename T> struct PointerLikeTypeTraits<const T> {
+ typedef PointerLikeTypeTraits<T> NonConst;
+
+ static inline const void *getAsVoidPointer(const T P) {
+ return NonConst::getAsVoidPointer(P);
+ }
+ static inline const T getFromVoidPointer(const void *P) {
+ return NonConst::getFromVoidPointer(const_cast<void *>(P));
+ }
+ static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
+};
+
+// Provide PointerLikeTypeTraits for const pointers.
+template <typename T> struct PointerLikeTypeTraits<const T *> {
+ typedef PointerLikeTypeTraits<T *> NonConst;
+
+ static inline const void *getAsVoidPointer(const T *P) {
+ return NonConst::getAsVoidPointer(const_cast<T *>(P));
+ }
+ static inline const T *getFromVoidPointer(const void *P) {
+ return NonConst::getFromVoidPointer(const_cast<void *>(P));
+ }
+ static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
+};
+
+// Provide PointerLikeTypeTraits for uintptr_t.
+template <> struct PointerLikeTypeTraits<uintptr_t> {
+ static inline void *getAsVoidPointer(uintptr_t P) {
+ return reinterpret_cast<void *>(P);
+ }
+ static inline uintptr_t getFromVoidPointer(void *P) {
+ return reinterpret_cast<uintptr_t>(P);
+ }
+ // No bits are available!
+ static constexpr int NumLowBitsAvailable = 0;
+};
+
+/// Provide suitable custom traits struct for function pointers.
+///
+/// Function pointers can't be directly given these traits as functions can't
+/// have their alignment computed with `alignof` and we need different casting.
+///
+/// To rely on higher alignment for a specialized use, you can provide a
+/// customized form of this template explicitly with higher alignment, and
+/// potentially use alignment attributes on functions to satisfy that.
+template <int Alignment, typename FunctionPointerT>
+struct FunctionPointerLikeTypeTraits {
+ static constexpr int NumLowBitsAvailable =
+ detail::ConstantLog2<Alignment>::value;
+ static inline void *getAsVoidPointer(FunctionPointerT P) {
+ assert((reinterpret_cast<uintptr_t>(P) &
+ ~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 &&
+ "Alignment not satisfied for an actual function pointer!");
+ return reinterpret_cast<void *>(P);
+ }
+ static inline FunctionPointerT getFromVoidPointer(void *P) {
+ return reinterpret_cast<FunctionPointerT>(P);
+ }
+};
+
+/// Provide a default specialization for function pointers that assumes 4-byte
+/// alignment.
+///
+/// We assume here that functions used with this are always at least 4-byte
+/// aligned. This means that, for example, thumb functions won't work or systems
+/// with weird unaligned function pointers won't work. But all practical systems
+/// we support satisfy this requirement.
+template <typename ReturnT, typename... ParamTs>
+struct PointerLikeTypeTraits<ReturnT (*)(ParamTs...)>
+ : FunctionPointerLikeTypeTraits<4, ReturnT (*)(ParamTs...)> {};
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/PrettyStackTrace.h b/contrib/libs/llvm16/include/llvm/Support/PrettyStackTrace.h
new file mode 100644
index 00000000000..eea84d187d2
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/PrettyStackTrace.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/PrettyStackTrace.h - Pretty Crash Handling --*- 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 defines the PrettyStackTraceEntry class, which is used to make
+// crashes give more contextual information about what the program was doing
+// when it crashed.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PRETTYSTACKTRACE_H
+#define LLVM_SUPPORT_PRETTYSTACKTRACE_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Compiler.h"
+
+namespace llvm {
+ class raw_ostream;
+
+ /// Enables dumping a "pretty" stack trace when the program crashes.
+ ///
+ /// \see PrettyStackTraceEntry
+ void EnablePrettyStackTrace();
+
+ /// Enables (or disables) dumping a "pretty" stack trace when the user sends
+ /// SIGINFO or SIGUSR1 to the current process.
+ ///
+ /// This is a per-thread decision so that a program can choose to print stack
+ /// traces only on a primary thread, or on all threads that use
+ /// PrettyStackTraceEntry.
+ ///
+ /// \see EnablePrettyStackTrace
+ /// \see PrettyStackTraceEntry
+ void EnablePrettyStackTraceOnSigInfoForThisThread(bool ShouldEnable = true);
+
+ /// Replaces the generic bug report message that is output upon
+ /// a crash.
+ void setBugReportMsg(const char *Msg);
+
+ /// Get the bug report message that will be output upon a crash.
+ const char *getBugReportMsg();
+
+ /// PrettyStackTraceEntry - This class is used to represent a frame of the
+ /// "pretty" stack trace that is dumped when a program crashes. You can define
+ /// subclasses of this and declare them on the program stack: when they are
+ /// constructed and destructed, they will add their symbolic frames to a
+ /// virtual stack trace. This gets dumped out if the program crashes.
+ class PrettyStackTraceEntry {
+ friend PrettyStackTraceEntry *ReverseStackTrace(PrettyStackTraceEntry *);
+
+ PrettyStackTraceEntry *NextEntry;
+ PrettyStackTraceEntry(const PrettyStackTraceEntry &) = delete;
+ void operator=(const PrettyStackTraceEntry &) = delete;
+ public:
+ PrettyStackTraceEntry();
+ virtual ~PrettyStackTraceEntry();
+
+ /// print - Emit information about this stack frame to OS.
+ virtual void print(raw_ostream &OS) const = 0;
+
+ /// getNextEntry - Return the next entry in the list of frames.
+ const PrettyStackTraceEntry *getNextEntry() const { return NextEntry; }
+ };
+
+ /// PrettyStackTraceString - This object prints a specified string (which
+ /// should not contain newlines) to the stream as the stack trace when a crash
+ /// occurs.
+ class PrettyStackTraceString : public PrettyStackTraceEntry {
+ const char *Str;
+ public:
+ PrettyStackTraceString(const char *str) : Str(str) {}
+ void print(raw_ostream &OS) const override;
+ };
+
+ /// PrettyStackTraceFormat - This object prints a string (which may use
+ /// printf-style formatting but should not contain newlines) to the stream
+ /// as the stack trace when a crash occurs.
+ class PrettyStackTraceFormat : public PrettyStackTraceEntry {
+ llvm::SmallVector<char, 32> Str;
+ public:
+ PrettyStackTraceFormat(const char *Format, ...);
+ void print(raw_ostream &OS) const override;
+ };
+
+ /// PrettyStackTraceProgram - This object prints a specified program arguments
+ /// to the stream as the stack trace when a crash occurs.
+ class PrettyStackTraceProgram : public PrettyStackTraceEntry {
+ int ArgC;
+ const char *const *ArgV;
+ public:
+ PrettyStackTraceProgram(int argc, const char * const*argv)
+ : ArgC(argc), ArgV(argv) {
+ EnablePrettyStackTrace();
+ }
+ void print(raw_ostream &OS) const override;
+ };
+
+ /// Returns the topmost element of the "pretty" stack state.
+ const void *SavePrettyStackState();
+
+ /// Restores the topmost element of the "pretty" stack state to State, which
+ /// should come from a previous call to SavePrettyStackState(). This is
+ /// useful when using a CrashRecoveryContext in code that also uses
+ /// PrettyStackTraceEntries, to make sure the stack that's printed if a crash
+ /// happens after a crash that's been recovered by CrashRecoveryContext
+ /// doesn't have frames on it that were added in code unwound by the
+ /// CrashRecoveryContext.
+ void RestorePrettyStackState(const void *State);
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Printable.h b/contrib/libs/llvm16/include/llvm/Support/Printable.h
new file mode 100644
index 00000000000..33d0918a4c2
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Printable.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- Printable.h - Print function helpers -------------------*- 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 defines the Printable struct.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PRINTABLE_H
+#define LLVM_SUPPORT_PRINTABLE_H
+
+#include <functional>
+#include <utility>
+
+namespace llvm {
+
+class raw_ostream;
+
+/// Simple wrapper around std::function<void(raw_ostream&)>.
+/// This class is useful to construct print helpers for raw_ostream.
+///
+/// Example:
+/// Printable printRegister(unsigned Register) {
+/// return Printable([Register](raw_ostream &OS) {
+/// OS << getRegisterName(Register);
+/// });
+/// }
+/// ... OS << printRegister(Register); ...
+///
+/// Implementation note: Ideally this would just be a typedef, but doing so
+/// leads to operator << being ambiguous as function has matching constructors
+/// in some STL versions. I have seen the problem on gcc 4.6 libstdc++ and
+/// microsoft STL.
+class Printable {
+public:
+ std::function<void(raw_ostream &OS)> Print;
+ Printable(std::function<void(raw_ostream &OS)> Print)
+ : Print(std::move(Print)) {}
+};
+
+inline raw_ostream &operator<<(raw_ostream &OS, const Printable &P) {
+ P.Print(OS);
+ return OS;
+}
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Process.h b/contrib/libs/llvm16/include/llvm/Support/Process.h
new file mode 100644
index 00000000000..b562d59b4ec
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Process.h
@@ -0,0 +1,236 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Process.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// Provides a library for accessing information about this process and other
+/// processes on the operating system. Also provides means of spawning
+/// subprocess for commands. The design of this library is modeled after the
+/// proposed design of the Boost.Process library, and is design specifically to
+/// follow the style of standard libraries and potentially become a proposal
+/// for a standard library.
+///
+/// This file declares the llvm::sys::Process class which contains a collection
+/// of legacy static interfaces for extracting various information about the
+/// current process. The goal is to migrate users of this API over to the new
+/// interfaces.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PROCESS_H
+#define LLVM_SUPPORT_PROCESS_H
+
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Program.h"
+#include <optional>
+#include <system_error>
+
+namespace llvm {
+template <typename T> class ArrayRef;
+class StringRef;
+
+namespace sys {
+
+
+/// A collection of legacy interfaces for querying information about the
+/// current executing process.
+class Process {
+public:
+ using Pid = int32_t;
+
+ /// Get the process's identifier.
+ static Pid getProcessId();
+
+ /// Get the process's page size.
+ /// This may fail if the underlying syscall returns an error. In most cases,
+ /// page size information is used for optimization, and this error can be
+ /// safely discarded by calling consumeError, and an estimated page size
+ /// substituted instead.
+ static Expected<unsigned> getPageSize();
+
+ /// Get the process's estimated page size.
+ /// This function always succeeds, but if the underlying syscall to determine
+ /// the page size fails then this will silently return an estimated page size.
+ /// The estimated page size is guaranteed to be a power of 2.
+ static unsigned getPageSizeEstimate() {
+ if (auto PageSize = getPageSize())
+ return *PageSize;
+ else {
+ consumeError(PageSize.takeError());
+ return 4096;
+ }
+ }
+
+ /// Return process memory usage.
+ /// This static function will return the total amount of memory allocated
+ /// by the process. This only counts the memory allocated via the malloc,
+ /// calloc and realloc functions and includes any "free" holes in the
+ /// allocated space.
+ static size_t GetMallocUsage();
+
+ /// This static function will set \p user_time to the amount of CPU time
+ /// spent in user (non-kernel) mode and \p sys_time to the amount of CPU
+ /// time spent in system (kernel) mode. If the operating system does not
+ /// support collection of these metrics, a zero duration will be for both
+ /// values.
+ /// \param elapsed Returns the system_clock::now() giving current time
+ /// \param user_time Returns the current amount of user time for the process
+ /// \param sys_time Returns the current amount of system time for the process
+ static void GetTimeUsage(TimePoint<> &elapsed,
+ std::chrono::nanoseconds &user_time,
+ std::chrono::nanoseconds &sys_time);
+
+ /// This function makes the necessary calls to the operating system to
+ /// prevent core files or any other kind of large memory dumps that can
+ /// occur when a program fails.
+ /// Prevent core file generation.
+ static void PreventCoreFiles();
+
+ /// true if PreventCoreFiles has been called, false otherwise.
+ static bool AreCoreFilesPrevented();
+
+ // This function returns the environment variable \arg name's value as a UTF-8
+ // string. \arg Name is assumed to be in UTF-8 encoding too.
+ static std::optional<std::string> GetEnv(StringRef name);
+
+ /// This function searches for an existing file in the list of directories
+ /// in a PATH like environment variable, and returns the first file found,
+ /// according to the order of the entries in the PATH like environment
+ /// variable. If an ignore list is specified, then any folder which is in
+ /// the PATH like environment variable but is also in IgnoreList is not
+ /// considered.
+ static std::optional<std::string>
+ FindInEnvPath(StringRef EnvName, StringRef FileName,
+ ArrayRef<std::string> IgnoreList,
+ char Separator = EnvPathSeparator);
+
+ static std::optional<std::string>
+ FindInEnvPath(StringRef EnvName, StringRef FileName,
+ char Separator = EnvPathSeparator);
+
+ // This functions ensures that the standard file descriptors (input, output,
+ // and error) are properly mapped to a file descriptor before we use any of
+ // them. This should only be called by standalone programs, library
+ // components should not call this.
+ static std::error_code FixupStandardFileDescriptors();
+
+ // This function safely closes a file descriptor. It is not safe to retry
+ // close(2) when it returns with errno equivalent to EINTR; this is because
+ // *nixen cannot agree if the file descriptor is, in fact, closed when this
+ // occurs.
+ //
+ // N.B. Some operating systems, due to thread cancellation, cannot properly
+ // guarantee that it will or will not be closed one way or the other!
+ static std::error_code SafelyCloseFileDescriptor(int FD);
+
+ /// This function determines if the standard input is connected directly
+ /// to a user's input (keyboard probably), rather than coming from a file
+ /// or pipe.
+ static bool StandardInIsUserInput();
+
+ /// This function determines if the standard output is connected to a
+ /// "tty" or "console" window. That is, the output would be displayed to
+ /// the user rather than being put on a pipe or stored in a file.
+ static bool StandardOutIsDisplayed();
+
+ /// This function determines if the standard error is connected to a
+ /// "tty" or "console" window. That is, the output would be displayed to
+ /// the user rather than being put on a pipe or stored in a file.
+ static bool StandardErrIsDisplayed();
+
+ /// This function determines if the given file descriptor is connected to
+ /// a "tty" or "console" window. That is, the output would be displayed to
+ /// the user rather than being put on a pipe or stored in a file.
+ static bool FileDescriptorIsDisplayed(int fd);
+
+ /// This function determines if the given file descriptor is displayd and
+ /// supports colors.
+ static bool FileDescriptorHasColors(int fd);
+
+ /// This function determines the number of columns in the window
+ /// if standard output is connected to a "tty" or "console"
+ /// window. If standard output is not connected to a tty or
+ /// console, or if the number of columns cannot be determined,
+ /// this routine returns zero.
+ static unsigned StandardOutColumns();
+
+ /// This function determines the number of columns in the window
+ /// if standard error is connected to a "tty" or "console"
+ /// window. If standard error is not connected to a tty or
+ /// console, or if the number of columns cannot be determined,
+ /// this routine returns zero.
+ static unsigned StandardErrColumns();
+
+ /// This function determines whether the terminal connected to standard
+ /// output supports colors. If standard output is not connected to a
+ /// terminal, this function returns false.
+ static bool StandardOutHasColors();
+
+ /// This function determines whether the terminal connected to standard
+ /// error supports colors. If standard error is not connected to a
+ /// terminal, this function returns false.
+ static bool StandardErrHasColors();
+
+ /// Enables or disables whether ANSI escape sequences are used to output
+ /// colors. This only has an effect on Windows.
+ /// Note: Setting this option is not thread-safe and should only be done
+ /// during initialization.
+ static void UseANSIEscapeCodes(bool enable);
+
+ /// Whether changing colors requires the output to be flushed.
+ /// This is needed on systems that don't support escape sequences for
+ /// changing colors.
+ static bool ColorNeedsFlush();
+
+ /// This function returns the colorcode escape sequences.
+ /// If ColorNeedsFlush() is true then this function will change the colors
+ /// and return an empty escape sequence. In that case it is the
+ /// responsibility of the client to flush the output stream prior to
+ /// calling this function.
+ static const char *OutputColor(char c, bool bold, bool bg);
+
+ /// Same as OutputColor, but only enables the bold attribute.
+ static const char *OutputBold(bool bg);
+
+ /// This function returns the escape sequence to reverse forground and
+ /// background colors.
+ static const char *OutputReverse();
+
+ /// Resets the terminals colors, or returns an escape sequence to do so.
+ static const char *ResetColor();
+
+ /// Get the result of a process wide random number generator. The
+ /// generator will be automatically seeded in non-deterministic fashion.
+ static unsigned GetRandomNumber();
+
+ /// Equivalent to ::exit(), except when running inside a CrashRecoveryContext.
+ /// In that case, the control flow will resume after RunSafely(), like for a
+ /// crash, rather than exiting the current process.
+ /// Use \arg NoCleanup for calling _exit() instead of exit().
+ [[noreturn]] static void Exit(int RetCode, bool NoCleanup = false);
+
+private:
+ [[noreturn]] static void ExitNoCleanup(int RetCode);
+};
+
+}
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Program.h b/contrib/libs/llvm16/include/llvm/Support/Program.h
new file mode 100644
index 00000000000..9a464bd73fa
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Program.h
@@ -0,0 +1,255 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Program.h ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::Program class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_PROGRAM_H
+#define LLVM_SUPPORT_PROGRAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include <chrono>
+#include <optional>
+#include <system_error>
+
+namespace llvm {
+class BitVector;
+namespace sys {
+
+ /// This is the OS-specific separator for PATH like environment variables:
+ // a colon on Unix or a semicolon on Windows.
+#if defined(LLVM_ON_UNIX)
+ const char EnvPathSeparator = ':';
+#elif defined (_WIN32)
+ const char EnvPathSeparator = ';';
+#endif
+
+#if defined(_WIN32)
+ typedef unsigned long procid_t; // Must match the type of DWORD on Windows.
+ typedef void *process_t; // Must match the type of HANDLE on Windows.
+#else
+ typedef ::pid_t procid_t;
+ typedef procid_t process_t;
+#endif
+
+ /// This struct encapsulates information about a process.
+ struct ProcessInfo {
+ enum : procid_t { InvalidPid = 0 };
+
+ procid_t Pid; /// The process identifier.
+ process_t Process; /// Platform-dependent process object.
+
+ /// The return code, set after execution.
+ int ReturnCode;
+
+ ProcessInfo();
+ };
+
+ /// This struct encapsulates information about a process execution.
+ struct ProcessStatistics {
+ std::chrono::microseconds TotalTime;
+ std::chrono::microseconds UserTime;
+ uint64_t PeakMemory = 0; ///< Maximum resident set size in KiB.
+ };
+
+ /// Find the first executable file \p Name in \p Paths.
+ ///
+ /// This does not perform hashing as a shell would but instead stats each PATH
+ /// entry individually so should generally be avoided. Core LLVM library
+ /// functions and options should instead require fully specified paths.
+ ///
+ /// \param Name name of the executable to find. If it contains any system
+ /// slashes, it will be returned as is.
+ /// \param Paths optional list of paths to search for \p Name. If empty it
+ /// will use the system PATH environment instead.
+ ///
+ /// \returns The fully qualified path to the first \p Name in \p Paths if it
+ /// exists. \p Name if \p Name has slashes in it. Otherwise an error.
+ ErrorOr<std::string>
+ findProgramByName(StringRef Name, ArrayRef<StringRef> Paths = {});
+
+ // These functions change the specified standard stream (stdin or stdout) mode
+ // based on the Flags. They return errc::success if the specified stream was
+ // changed. Otherwise, a platform dependent error is returned.
+ std::error_code ChangeStdinMode(fs::OpenFlags Flags);
+ std::error_code ChangeStdoutMode(fs::OpenFlags Flags);
+
+ // These functions change the specified standard stream (stdin or stdout) to
+ // binary mode. They return errc::success if the specified stream
+ // was changed. Otherwise a platform dependent error is returned.
+ std::error_code ChangeStdinToBinary();
+ std::error_code ChangeStdoutToBinary();
+
+ /// This function executes the program using the arguments provided. The
+ /// invoked program will inherit the stdin, stdout, and stderr file
+ /// descriptors, the environment and other configuration settings of the
+ /// invoking program.
+ /// This function waits for the program to finish, so should be avoided in
+ /// library functions that aren't expected to block. Consider using
+ /// ExecuteNoWait() instead.
+ /// \returns an integer result code indicating the status of the program.
+ /// A zero or positive value indicates the result code of the program.
+ /// -1 indicates failure to execute
+ /// -2 indicates a crash during execution or timeout
+ int ExecuteAndWait(
+ StringRef Program, ///< Path of the program to be executed. It is
+ ///< presumed this is the result of the findProgramByName method.
+ ArrayRef<StringRef> Args, ///< An array of strings that are passed to the
+ ///< program. The first element should be the name of the program.
+ ///< The array should **not** be terminated by an empty StringRef.
+ std::optional<ArrayRef<StringRef>> Env =
+ std::nullopt, ///< An optional vector of
+ ///< strings to use for the program's environment. If not provided, the
+ ///< current program's environment will be used. If specified, the
+ ///< vector should **not** be terminated by an empty StringRef.
+ ArrayRef<std::optional<StringRef>> Redirects = {}, ///<
+ ///< An array of optional paths. Should have a size of zero or three.
+ ///< If the array is empty, no redirections are performed.
+ ///< Otherwise, the inferior process's stdin(0), stdout(1), and stderr(2)
+ ///< will be redirected to the corresponding paths, if the optional path
+ ///< is present (not \c std::nullopt).
+ ///< When an empty path is passed in, the corresponding file descriptor
+ ///< will be disconnected (ie, /dev/null'd) in a portable way.
+ unsigned SecondsToWait = 0, ///< If non-zero, this specifies the amount
+ ///< of time to wait for the child process to exit. If the time
+ ///< expires, the child is killed and this call returns. If zero,
+ ///< this function will wait until the child finishes or forever if
+ ///< it doesn't.
+ unsigned MemoryLimit = 0, ///< If non-zero, this specifies max. amount
+ ///< of memory can be allocated by process. If memory usage will be
+ ///< higher limit, the child is killed and this call returns. If zero
+ ///< - no memory limit.
+ std::string *ErrMsg = nullptr, ///< If non-zero, provides a pointer to a
+ ///< string instance in which error messages will be returned. If the
+ ///< string is non-empty upon return an error occurred while invoking the
+ ///< program.
+ bool *ExecutionFailed = nullptr,
+ std::optional<ProcessStatistics> *ProcStat = nullptr, ///< If non-zero,
+ /// provides a pointer to a structure in which process execution
+ /// statistics will be stored.
+ BitVector *AffinityMask = nullptr ///< CPUs or processors the new
+ /// program shall run on.
+ );
+
+ /// Similar to ExecuteAndWait, but returns immediately.
+ /// @returns The \see ProcessInfo of the newly launched process.
+ /// \note On Microsoft Windows systems, users will need to either call
+ /// \see Wait until the process finished execution or win32 CloseHandle() API
+ /// on ProcessInfo.ProcessHandle to avoid memory leaks.
+ ProcessInfo ExecuteNoWait(StringRef Program, ArrayRef<StringRef> Args,
+ std::optional<ArrayRef<StringRef>> Env,
+ ArrayRef<std::optional<StringRef>> Redirects = {},
+ unsigned MemoryLimit = 0,
+ std::string *ErrMsg = nullptr,
+ bool *ExecutionFailed = nullptr,
+ BitVector *AffinityMask = nullptr);
+
+ /// Return true if the given arguments fit within system-specific
+ /// argument length limits.
+ bool commandLineFitsWithinSystemLimits(StringRef Program,
+ ArrayRef<StringRef> Args);
+
+ /// Return true if the given arguments fit within system-specific
+ /// argument length limits.
+ bool commandLineFitsWithinSystemLimits(StringRef Program,
+ ArrayRef<const char *> Args);
+
+ /// File encoding options when writing contents that a non-UTF8 tool will
+ /// read (on Windows systems). For UNIX, we always use UTF-8.
+ enum WindowsEncodingMethod {
+ /// UTF-8 is the LLVM native encoding, being the same as "do not perform
+ /// encoding conversion".
+ WEM_UTF8,
+ WEM_CurrentCodePage,
+ WEM_UTF16
+ };
+
+ /// Saves the UTF8-encoded \p contents string into the file \p FileName
+ /// using a specific encoding.
+ ///
+ /// This write file function adds the possibility to choose which encoding
+ /// to use when writing a text file. On Windows, this is important when
+ /// writing files with internationalization support with an encoding that is
+ /// different from the one used in LLVM (UTF-8). We use this when writing
+ /// response files, since GCC tools on MinGW only understand legacy code
+ /// pages, and VisualStudio tools only understand UTF-16.
+ /// For UNIX, using different encodings is silently ignored, since all tools
+ /// work well with UTF-8.
+ /// This function assumes that you only use UTF-8 *text* data and will convert
+ /// it to your desired encoding before writing to the file.
+ ///
+ /// FIXME: We use EM_CurrentCodePage to write response files for GNU tools in
+ /// a MinGW/MinGW-w64 environment, which has serious flaws but currently is
+ /// our best shot to make gcc/ld understand international characters. This
+ /// should be changed as soon as binutils fix this to support UTF16 on mingw.
+ ///
+ /// \returns non-zero error_code if failed
+ std::error_code
+ writeFileWithEncoding(StringRef FileName, StringRef Contents,
+ WindowsEncodingMethod Encoding = WEM_UTF8);
+
+ /// This function waits for the process specified by \p PI to finish.
+ /// \returns A \see ProcessInfo struct with Pid set to:
+ /// \li The process id of the child process if the child process has changed
+ /// state.
+ /// \li 0 if the child process has not changed state.
+ /// \note Users of this function should always check the ReturnCode member of
+ /// the \see ProcessInfo returned from this function.
+ ProcessInfo
+ Wait(const ProcessInfo &PI, ///< The child process that should be waited on.
+ std::optional<unsigned> SecondsToWait, ///< If std::nullopt, waits until
+ ///< child has terminated.
+ ///< If a value, this specifies the amount of time to wait for the child
+ ///< process. If the time expires, and \p Polling is false, the child is
+ ///< killed and this < function returns. If the time expires and \p
+ ///< Polling is true, the child is resumed.
+ ///<
+ ///< If zero, this function will perform a non-blocking
+ ///< wait on the child process.
+ std::string *ErrMsg = nullptr, ///< If non-zero, provides a pointer to a
+ ///< string instance in which error messages will be returned. If the
+ ///< string is non-empty upon return an error occurred while invoking the
+ ///< program.
+ std::optional<ProcessStatistics> *ProcStat =
+ nullptr, ///< If non-zero, provides
+ /// a pointer to a structure in which process execution statistics will
+ /// be stored.
+
+ bool Polling = false ///< If true, do not kill the process on timeout.
+ );
+
+ /// Print a command argument, and optionally quote it.
+ void printArg(llvm::raw_ostream &OS, StringRef Arg, bool Quote);
+
+#if defined(_WIN32)
+ /// Given a list of command line arguments, quote and escape them as necessary
+ /// to build a single flat command line appropriate for calling CreateProcess
+ /// on
+ /// Windows.
+ ErrorOr<std::wstring> flattenWindowsCommandLine(ArrayRef<StringRef> Args);
+#endif
+ }
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/RISCVAttributeParser.h b/contrib/libs/llvm16/include/llvm/Support/RISCVAttributeParser.h
new file mode 100644
index 00000000000..c7b935f3dec
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/RISCVAttributeParser.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- RISCVAttributeParser.h - RISCV Attribute Parser ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H
+#define LLVM_SUPPORT_RISCVATTRIBUTEPARSER_H
+
+#include "llvm/Support/ELFAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
+
+namespace llvm {
+class RISCVAttributeParser : public ELFAttributeParser {
+ struct DisplayHandler {
+ RISCVAttrs::AttrType attribute;
+ Error (RISCVAttributeParser::*routine)(unsigned);
+ };
+ static const DisplayHandler displayRoutines[];
+
+ Error handler(uint64_t tag, bool &handled) override;
+
+ Error unalignedAccess(unsigned tag);
+ Error stackAlign(unsigned tag);
+
+public:
+ RISCVAttributeParser(ScopedPrinter *sw)
+ : ELFAttributeParser(sw, RISCVAttrs::getRISCVAttributeTags(), "riscv") {}
+ RISCVAttributeParser()
+ : ELFAttributeParser(RISCVAttrs::getRISCVAttributeTags(), "riscv") {}
+};
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/RISCVAttributes.h b/contrib/libs/llvm16/include/llvm/Support/RISCVAttributes.h
new file mode 100644
index 00000000000..0fc2a0047d5
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/RISCVAttributes.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- RISCVAttributes.h - RISCV Attributes --------------------*- 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 enumerations for RISCV attributes as defined in RISC-V
+// ELF psABI specification.
+//
+// RISC-V ELF psABI specification
+//
+// https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_RISCVATTRIBUTES_H
+#define LLVM_SUPPORT_RISCVATTRIBUTES_H
+
+#include "llvm/Support/ELFAttributes.h"
+
+namespace llvm {
+namespace RISCVAttrs {
+
+const TagNameMap &getRISCVAttributeTags();
+
+enum AttrType : unsigned {
+ // Attribute types in ELF/.riscv.attributes.
+ STACK_ALIGN = 4,
+ ARCH = 5,
+ UNALIGNED_ACCESS = 6,
+ PRIV_SPEC = 8,
+ PRIV_SPEC_MINOR = 10,
+ PRIV_SPEC_REVISION = 12,
+};
+
+enum StackAlign { ALIGN_4 = 4, ALIGN_16 = 16 };
+
+enum { NOT_ALLOWED = 0, ALLOWED = 1 };
+
+} // namespace RISCVAttrs
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/RISCVISAInfo.h b/contrib/libs/llvm16/include/llvm/Support/RISCVISAInfo.h
new file mode 100644
index 00000000000..9a23501816d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/RISCVISAInfo.h
@@ -0,0 +1,126 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- RISCVISAInfo.h - RISCV ISA Information ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RISCVISAINFO_H
+#define LLVM_SUPPORT_RISCVISAINFO_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace llvm {
+struct RISCVExtensionInfo {
+ std::string ExtName;
+ unsigned MajorVersion;
+ unsigned MinorVersion;
+};
+
+class RISCVISAInfo {
+public:
+ RISCVISAInfo(const RISCVISAInfo &) = delete;
+ RISCVISAInfo &operator=(const RISCVISAInfo &) = delete;
+
+ static bool compareExtension(const std::string &LHS, const std::string &RHS);
+
+ /// Helper class for OrderedExtensionMap.
+ struct ExtensionComparator {
+ bool operator()(const std::string &LHS, const std::string &RHS) const {
+ return compareExtension(LHS, RHS);
+ }
+ };
+
+ /// OrderedExtensionMap is std::map, it's specialized to keep entries
+ /// in canonical order of extension.
+ typedef std::map<std::string, RISCVExtensionInfo, ExtensionComparator>
+ OrderedExtensionMap;
+
+ RISCVISAInfo(unsigned XLen, OrderedExtensionMap &Exts)
+ : XLen(XLen), FLen(0), MinVLen(0), MaxELen(0), MaxELenFp(0), Exts(Exts) {}
+
+ /// Parse RISCV ISA info from arch string.
+ static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
+ parseArchString(StringRef Arch, bool EnableExperimentalExtension,
+ bool ExperimentalExtensionVersionCheck = true,
+ bool IgnoreUnknown = false);
+
+ /// Parse RISCV ISA info from an arch string that is already in normalized
+ /// form (as defined in the psABI). Unlike parseArchString, this function
+ /// will not error for unrecognized extension names or extension versions.
+ static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
+ parseNormalizedArchString(StringRef Arch);
+
+ /// Parse RISCV ISA info from feature vector.
+ static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
+ parseFeatures(unsigned XLen, const std::vector<std::string> &Features);
+
+ /// Convert RISCV ISA info to a feature vector.
+ void toFeatures(std::vector<StringRef> &Features,
+ llvm::function_ref<StringRef(const Twine &)> StrAlloc,
+ bool AddAllExtensions) const;
+
+ const OrderedExtensionMap &getExtensions() const { return Exts; };
+
+ unsigned getXLen() const { return XLen; };
+ unsigned getFLen() const { return FLen; };
+ unsigned getMinVLen() const { return MinVLen; }
+ unsigned getMaxVLen() const { return 65536; }
+ unsigned getMaxELen() const { return MaxELen; }
+ unsigned getMaxELenFp() const { return MaxELenFp; }
+
+ bool hasExtension(StringRef Ext) const;
+ std::string toString() const;
+ std::vector<std::string> toFeatureVector() const;
+ StringRef computeDefaultABI() const;
+
+ static bool isSupportedExtensionFeature(StringRef Ext);
+ static bool isSupportedExtension(StringRef Ext);
+ static bool isSupportedExtension(StringRef Ext, unsigned MajorVersion,
+ unsigned MinorVersion);
+ static llvm::Expected<std::unique_ptr<RISCVISAInfo>>
+ postProcessAndChecking(std::unique_ptr<RISCVISAInfo> &&ISAInfo);
+
+private:
+ RISCVISAInfo(unsigned XLen)
+ : XLen(XLen), FLen(0), MinVLen(0), MaxELen(0), MaxELenFp(0) {}
+
+ unsigned XLen;
+ unsigned FLen;
+ unsigned MinVLen;
+ unsigned MaxELen, MaxELenFp;
+
+ OrderedExtensionMap Exts;
+
+ void addExtension(StringRef ExtName, unsigned MajorVersion,
+ unsigned MinorVersion);
+
+ Error checkDependency();
+
+ void updateImplication();
+ void updateCombination();
+ void updateFLen();
+ void updateMinVLen();
+ void updateMaxELen();
+};
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/RWMutex.h b/contrib/libs/llvm16/include/llvm/Support/RWMutex.h
new file mode 100644
index 00000000000..8468e76b54b
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/RWMutex.h
@@ -0,0 +1,206 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::RWMutex class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RWMUTEX_H
+#define LLVM_SUPPORT_RWMUTEX_H
+
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Threading.h"
+#include <cassert>
+#include <mutex>
+#include <shared_mutex>
+
+// std::shared_timed_mutex is only availble on macOS 10.12 and later.
+#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200
+#define LLVM_USE_RW_MUTEX_IMPL
+#endif
+#endif
+
+namespace llvm {
+namespace sys {
+
+#if defined(LLVM_USE_RW_MUTEX_IMPL)
+/// Platform agnostic RWMutex class.
+class RWMutexImpl {
+ /// @name Constructors
+ /// @{
+public:
+ /// Initializes the lock but doesn't acquire it.
+ /// Default Constructor.
+ explicit RWMutexImpl();
+
+ /// @}
+ /// @name Do Not Implement
+ /// @{
+ RWMutexImpl(const RWMutexImpl &original) = delete;
+ RWMutexImpl &operator=(const RWMutexImpl &) = delete;
+ /// @}
+
+ /// Releases and removes the lock
+ /// Destructor
+ ~RWMutexImpl();
+
+ /// @}
+ /// @name Methods
+ /// @{
+public:
+ /// Attempts to unconditionally acquire the lock in reader mode. If the
+ /// lock is held by a writer, this method will wait until it can acquire
+ /// the lock.
+ /// @returns false if any kind of error occurs, true otherwise.
+ /// Unconditionally acquire the lock in reader mode.
+ bool lock_shared();
+
+ /// Attempts to release the lock in reader mode.
+ /// @returns false if any kind of error occurs, true otherwise.
+ /// Unconditionally release the lock in reader mode.
+ bool unlock_shared();
+
+ /// Attempts to unconditionally acquire the lock in reader mode. If the
+ /// lock is held by any readers, this method will wait until it can
+ /// acquire the lock.
+ /// @returns false if any kind of error occurs, true otherwise.
+ /// Unconditionally acquire the lock in writer mode.
+ bool lock();
+
+ /// Attempts to release the lock in writer mode.
+ /// @returns false if any kind of error occurs, true otherwise.
+ /// Unconditionally release the lock in write mode.
+ bool unlock();
+
+ //@}
+ /// @name Platform Dependent Data
+ /// @{
+private:
+#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
+ void *data_ = nullptr; ///< We don't know what the data will be
+#endif
+};
+#endif
+
+/// SmartMutex - An R/W mutex with a compile time constant parameter that
+/// indicates whether this mutex should become a no-op when we're not
+/// running in multithreaded mode.
+template <bool mt_only> class SmartRWMutex {
+#if !defined(LLVM_USE_RW_MUTEX_IMPL)
+ std::shared_mutex impl;
+#else
+ RWMutexImpl impl;
+#endif
+ unsigned readers = 0;
+ unsigned writers = 0;
+
+public:
+ bool lock_shared() {
+ if (!mt_only || llvm_is_multithreaded()) {
+ impl.lock_shared();
+ return true;
+ }
+
+ // Single-threaded debugging code. This would be racy in multithreaded
+ // mode, but provides not basic checks in single threaded mode.
+ ++readers;
+ return true;
+ }
+
+ bool unlock_shared() {
+ if (!mt_only || llvm_is_multithreaded()) {
+ impl.unlock_shared();
+ return true;
+ }
+
+ // Single-threaded debugging code. This would be racy in multithreaded
+ // mode, but provides not basic checks in single threaded mode.
+ assert(readers > 0 && "Reader lock not acquired before release!");
+ --readers;
+ return true;
+ }
+
+ bool lock() {
+ if (!mt_only || llvm_is_multithreaded()) {
+ impl.lock();
+ return true;
+ }
+
+ // Single-threaded debugging code. This would be racy in multithreaded
+ // mode, but provides not basic checks in single threaded mode.
+ assert(writers == 0 && "Writer lock already acquired!");
+ ++writers;
+ return true;
+ }
+
+ bool unlock() {
+ if (!mt_only || llvm_is_multithreaded()) {
+ impl.unlock();
+ return true;
+ }
+
+ // Single-threaded debugging code. This would be racy in multithreaded
+ // mode, but provides not basic checks in single threaded mode.
+ assert(writers == 1 && "Writer lock not acquired before release!");
+ --writers;
+ return true;
+ }
+};
+
+typedef SmartRWMutex<false> RWMutex;
+
+/// ScopedReader - RAII acquisition of a reader lock
+#if !defined(LLVM_USE_RW_MUTEX_IMPL)
+template <bool mt_only>
+using SmartScopedReader = const std::shared_lock<SmartRWMutex<mt_only>>;
+#else
+template <bool mt_only> struct SmartScopedReader {
+ SmartRWMutex<mt_only> &mutex;
+
+ explicit SmartScopedReader(SmartRWMutex<mt_only> &m) : mutex(m) {
+ mutex.lock_shared();
+ }
+
+ ~SmartScopedReader() { mutex.unlock_shared(); }
+};
+#endif
+typedef SmartScopedReader<false> ScopedReader;
+
+/// ScopedWriter - RAII acquisition of a writer lock
+#if !defined(LLVM_USE_RW_MUTEX_IMPL)
+template <bool mt_only>
+using SmartScopedWriter = std::lock_guard<SmartRWMutex<mt_only>>;
+#else
+template <bool mt_only> struct SmartScopedWriter {
+ SmartRWMutex<mt_only> &mutex;
+
+ explicit SmartScopedWriter(SmartRWMutex<mt_only> &m) : mutex(m) {
+ mutex.lock();
+ }
+
+ ~SmartScopedWriter() { mutex.unlock(); }
+};
+#endif
+typedef SmartScopedWriter<false> ScopedWriter;
+
+} // end namespace sys
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_RWMUTEX_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/RandomNumberGenerator.h b/contrib/libs/llvm16/include/llvm/Support/RandomNumberGenerator.h
new file mode 100644
index 00000000000..28bab7133c4
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/RandomNumberGenerator.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//==- llvm/Support/RandomNumberGenerator.h - RNG for diversity ---*- 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 defines an abstraction for deterministic random number
+// generation (RNG). Note that the current implementation is not
+// cryptographically secure as it uses the C++11 <random> facilities.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RANDOMNUMBERGENERATOR_H_
+#define LLVM_SUPPORT_RANDOMNUMBERGENERATOR_H_
+
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataTypes.h" // Needed for uint64_t on Windows.
+#include <random>
+#include <system_error>
+
+namespace llvm {
+class StringRef;
+
+/// A random number generator.
+///
+/// Instances of this class should not be shared across threads. The
+/// seed should be set by passing the -rng-seed=<uint64> option. Use
+/// Module::createRNG to create a new RNG instance for use with that
+/// module.
+class RandomNumberGenerator {
+
+ // 64-bit Mersenne Twister by Matsumoto and Nishimura, 2000
+ // http://en.cppreference.com/w/cpp/numeric/random/mersenne_twister_engine
+ // This RNG is deterministically portable across C++11
+ // implementations.
+ using generator_type = std::mt19937_64;
+
+public:
+ using result_type = generator_type::result_type;
+
+ /// Returns a random number in the range [0, Max).
+ result_type operator()();
+
+ static constexpr result_type min() { return generator_type::min(); }
+ static constexpr result_type max() { return generator_type::max(); }
+
+private:
+ /// Seeds and salts the underlying RNG engine.
+ ///
+ /// This constructor should not be used directly. Instead use
+ /// Module::createRNG to create a new RNG salted with the Module ID.
+ RandomNumberGenerator(StringRef Salt);
+
+ generator_type Generator;
+
+ // Noncopyable.
+ RandomNumberGenerator(const RandomNumberGenerator &other) = delete;
+ RandomNumberGenerator &operator=(const RandomNumberGenerator &other) = delete;
+
+ friend class Module;
+};
+
+// Get random vector of specified size
+std::error_code getRandomBytes(void *Buffer, size_t Size);
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Recycler.h b/contrib/libs/llvm16/include/llvm/Support/Recycler.h
new file mode 100644
index 00000000000..7a9bcb29a8f
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Recycler.h
@@ -0,0 +1,126 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//==- llvm/Support/Recycler.h - Recycling Allocator --------------*- 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 defines the Recycler class template. See the doxygen comment for
+// Recycler for more details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RECYCLER_H
+#define LLVM_SUPPORT_RECYCLER_H
+
+#include "llvm/ADT/ilist.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cassert>
+
+namespace llvm {
+
+/// PrintRecyclingAllocatorStats - Helper for RecyclingAllocator for
+/// printing statistics.
+///
+void PrintRecyclerStats(size_t Size, size_t Align, size_t FreeListSize);
+
+/// Recycler - This class manages a linked-list of deallocated nodes
+/// and facilitates reusing deallocated memory in place of allocating
+/// new memory.
+///
+template <class T, size_t Size = sizeof(T), size_t Align = alignof(T)>
+class Recycler {
+ struct FreeNode {
+ FreeNode *Next;
+ };
+
+ /// List of nodes that have deleted contents and are not in active use.
+ FreeNode *FreeList = nullptr;
+
+ FreeNode *pop_val() {
+ auto *Val = FreeList;
+ __asan_unpoison_memory_region(Val, Size);
+ FreeList = FreeList->Next;
+ __msan_allocated_memory(Val, Size);
+ return Val;
+ }
+
+ void push(FreeNode *N) {
+ N->Next = FreeList;
+ FreeList = N;
+ __asan_poison_memory_region(N, Size);
+ }
+
+public:
+ ~Recycler() {
+ // If this fails, either the callee has lost track of some allocation,
+ // or the callee isn't tracking allocations and should just call
+ // clear() before deleting the Recycler.
+ assert(!FreeList && "Non-empty recycler deleted!");
+ }
+
+ /// clear - Release all the tracked allocations to the allocator. The
+ /// recycler must be free of any tracked allocations before being
+ /// deleted; calling clear is one way to ensure this.
+ template<class AllocatorType>
+ void clear(AllocatorType &Allocator) {
+ while (FreeList) {
+ T *t = reinterpret_cast<T *>(pop_val());
+ Allocator.Deallocate(t);
+ }
+ }
+
+ /// Special case for BumpPtrAllocator which has an empty Deallocate()
+ /// function.
+ ///
+ /// There is no need to traverse the free list, pulling all the objects into
+ /// cache.
+ void clear(BumpPtrAllocator &) { FreeList = nullptr; }
+
+ template<class SubClass, class AllocatorType>
+ SubClass *Allocate(AllocatorType &Allocator) {
+ static_assert(alignof(SubClass) <= Align,
+ "Recycler allocation alignment is less than object align!");
+ static_assert(sizeof(SubClass) <= Size,
+ "Recycler allocation size is less than object size!");
+ return FreeList ? reinterpret_cast<SubClass *>(pop_val())
+ : static_cast<SubClass *>(Allocator.Allocate(Size, Align));
+ }
+
+ template<class AllocatorType>
+ T *Allocate(AllocatorType &Allocator) {
+ return Allocate<T>(Allocator);
+ }
+
+ template<class SubClass, class AllocatorType>
+ void Deallocate(AllocatorType & /*Allocator*/, SubClass* Element) {
+ push(reinterpret_cast<FreeNode *>(Element));
+ }
+
+ void PrintStats();
+};
+
+template <class T, size_t Size, size_t Align>
+void Recycler<T, Size, Align>::PrintStats() {
+ size_t S = 0;
+ for (auto *I = FreeList; I; I = I->Next)
+ ++S;
+ PrintRecyclerStats(Size, Align, S);
+}
+
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/RecyclingAllocator.h b/contrib/libs/llvm16/include/llvm/Support/RecyclingAllocator.h
new file mode 100644
index 00000000000..c683de3ffab
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/RecyclingAllocator.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//==- llvm/Support/RecyclingAllocator.h - Recycling Allocator ----*- 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 defines the RecyclingAllocator class. See the doxygen comment for
+// RecyclingAllocator for more details on the implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RECYCLINGALLOCATOR_H
+#define LLVM_SUPPORT_RECYCLINGALLOCATOR_H
+
+#include "llvm/Support/Recycler.h"
+
+namespace llvm {
+
+/// RecyclingAllocator - This class wraps an Allocator, adding the
+/// functionality of recycling deleted objects.
+///
+template <class AllocatorType, class T, size_t Size = sizeof(T),
+ size_t Align = alignof(T)>
+class RecyclingAllocator {
+private:
+ /// Base - Implementation details.
+ ///
+ Recycler<T, Size, Align> Base;
+
+ /// Allocator - The wrapped allocator.
+ ///
+ AllocatorType Allocator;
+
+public:
+ ~RecyclingAllocator() { Base.clear(Allocator); }
+
+ /// Allocate - Return a pointer to storage for an object of type
+ /// SubClass. The storage may be either newly allocated or recycled.
+ ///
+ template<class SubClass>
+ SubClass *Allocate() { return Base.template Allocate<SubClass>(Allocator); }
+
+ T *Allocate() { return Base.Allocate(Allocator); }
+
+ /// Deallocate - Release storage for the pointed-to object. The
+ /// storage will be kept track of and may be recycled.
+ ///
+ template<class SubClass>
+ void Deallocate(SubClass* E) { return Base.Deallocate(Allocator, E); }
+
+ void PrintStats() {
+ Allocator.PrintStats();
+ Base.PrintStats();
+ }
+};
+
+}
+
+template<class AllocatorType, class T, size_t Size, size_t Align>
+inline void *operator new(size_t size,
+ llvm::RecyclingAllocator<AllocatorType,
+ T, Size, Align> &Allocator) {
+ assert(size <= Size && "allocation size exceeded");
+ return Allocator.Allocate();
+}
+
+template<class AllocatorType, class T, size_t Size, size_t Align>
+inline void operator delete(void *E,
+ llvm::RecyclingAllocator<AllocatorType,
+ T, Size, Align> &A) {
+ A.Deallocate(E);
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Regex.h b/contrib/libs/llvm16/include/llvm/Support/Regex.h
new file mode 100644
index 00000000000..70387ec7f5e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Regex.h
@@ -0,0 +1,124 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- Regex.h - Regular Expression matcher implementation -*- C++ -*-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a POSIX regular expression matcher. Both Basic and
+// Extended POSIX regular expressions (ERE) are supported. EREs were extended
+// to support backreferences in matches.
+// This implementation also supports matching strings with embedded NUL chars.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_REGEX_H
+#define LLVM_SUPPORT_REGEX_H
+
+#include "llvm/ADT/BitmaskEnum.h"
+#include <string>
+
+struct llvm_regex;
+
+namespace llvm {
+ class StringRef;
+ template<typename T> class SmallVectorImpl;
+
+ class Regex {
+ public:
+ enum RegexFlags : unsigned {
+ NoFlags = 0,
+ /// Compile for matching that ignores upper/lower case distinctions.
+ IgnoreCase = 1,
+ /// Compile for newline-sensitive matching. With this flag '[^' bracket
+ /// expressions and '.' never match newline. A ^ anchor matches the
+ /// null string after any newline in the string in addition to its normal
+ /// function, and the $ anchor matches the null string before any
+ /// newline in the string in addition to its normal function.
+ Newline = 2,
+ /// By default, the POSIX extended regular expression (ERE) syntax is
+ /// assumed. Pass this flag to turn on basic regular expressions (BRE)
+ /// instead.
+ BasicRegex = 4,
+
+ LLVM_MARK_AS_BITMASK_ENUM(BasicRegex)
+ };
+
+ Regex();
+ /// Compiles the given regular expression \p Regex.
+ ///
+ /// \param Regex - referenced string is no longer needed after this
+ /// constructor does finish. Only its compiled form is kept stored.
+ Regex(StringRef Regex, RegexFlags Flags = NoFlags);
+ Regex(StringRef Regex, unsigned Flags);
+ Regex(const Regex &) = delete;
+ Regex &operator=(Regex regex) {
+ std::swap(preg, regex.preg);
+ std::swap(error, regex.error);
+ return *this;
+ }
+ Regex(Regex &&regex);
+ ~Regex();
+
+ /// isValid - returns the error encountered during regex compilation, if
+ /// any.
+ bool isValid(std::string &Error) const;
+ bool isValid() const { return !error; }
+
+ /// getNumMatches - In a valid regex, return the number of parenthesized
+ /// matches it contains. The number filled in by match will include this
+ /// many entries plus one for the whole regex (as element 0).
+ unsigned getNumMatches() const;
+
+ /// matches - Match the regex against a given \p String.
+ ///
+ /// \param Matches - If given, on a successful match this will be filled in
+ /// with references to the matched group expressions (inside \p String),
+ /// the first group is always the entire pattern.
+ ///
+ /// \param Error - If non-null, any errors in the matching will be recorded
+ /// as a non-empty string. If there is no error, it will be an empty string.
+ ///
+ /// This returns true on a successful match.
+ bool match(StringRef String, SmallVectorImpl<StringRef> *Matches = nullptr,
+ std::string *Error = nullptr) const;
+
+ /// sub - Return the result of replacing the first match of the regex in
+ /// \p String with the \p Repl string. Backreferences like "\0" in the
+ /// replacement string are replaced with the appropriate match substring.
+ ///
+ /// Note that the replacement string has backslash escaping performed on
+ /// it. Invalid backreferences are ignored (replaced by empty strings).
+ ///
+ /// \param Error If non-null, any errors in the substitution (invalid
+ /// backreferences, trailing backslashes) will be recorded as a non-empty
+ /// string. If there is no error, it will be an empty string.
+ std::string sub(StringRef Repl, StringRef String,
+ std::string *Error = nullptr) const;
+
+ /// If this function returns true, ^Str$ is an extended regular
+ /// expression that matches Str and only Str.
+ static bool isLiteralERE(StringRef Str);
+
+ /// Turn String into a regex by escaping its special characters.
+ static std::string escape(StringRef String);
+
+ private:
+ struct llvm_regex *preg;
+ int error;
+ };
+}
+
+#endif // LLVM_SUPPORT_REGEX_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Registry.h b/contrib/libs/llvm16/include/llvm/Support/Registry.h
new file mode 100644
index 00000000000..720f3528566
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Registry.h
@@ -0,0 +1,170 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//=== Registry.h - Linker-supported plugin registries -----------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines a registry template for discovering pluggable modules.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_REGISTRY_H
+#define LLVM_SUPPORT_REGISTRY_H
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include <memory>
+
+namespace llvm {
+ /// A simple registry entry which provides only a name, description, and
+ /// no-argument constructor.
+ template <typename T>
+ class SimpleRegistryEntry {
+ StringRef Name, Desc;
+ std::unique_ptr<T> (*Ctor)();
+
+ public:
+ SimpleRegistryEntry(StringRef N, StringRef D, std::unique_ptr<T> (*C)())
+ : Name(N), Desc(D), Ctor(C) {}
+
+ StringRef getName() const { return Name; }
+ StringRef getDesc() const { return Desc; }
+ std::unique_ptr<T> instantiate() const { return Ctor(); }
+ };
+
+ /// A global registry used in conjunction with static constructors to make
+ /// pluggable components (like targets or garbage collectors) "just work" when
+ /// linked with an executable.
+ template <typename T>
+ class Registry {
+ public:
+ typedef T type;
+ typedef SimpleRegistryEntry<T> entry;
+
+ class node;
+ class iterator;
+
+ private:
+ Registry() = delete;
+
+ friend class node;
+ static node *Head, *Tail;
+
+ public:
+ /// Node in linked list of entries.
+ ///
+ class node {
+ friend class iterator;
+ friend Registry<T>;
+
+ node *Next;
+ const entry& Val;
+
+ public:
+ node(const entry &V) : Next(nullptr), Val(V) {}
+ };
+
+ /// Add a node to the Registry: this is the interface between the plugin and
+ /// the executable.
+ ///
+ /// This function is exported by the executable and called by the plugin to
+ /// add a node to the executable's registry. Therefore it's not defined here
+ /// to avoid it being instantiated in the plugin and is instead defined in
+ /// the executable (see LLVM_INSTANTIATE_REGISTRY below).
+ static void add_node(node *N);
+
+ /// Iterators for registry entries.
+ ///
+ class iterator
+ : public llvm::iterator_facade_base<iterator, std::forward_iterator_tag,
+ const entry> {
+ const node *Cur;
+
+ public:
+ explicit iterator(const node *N) : Cur(N) {}
+
+ bool operator==(const iterator &That) const { return Cur == That.Cur; }
+ iterator &operator++() { Cur = Cur->Next; return *this; }
+ const entry &operator*() const { return Cur->Val; }
+ };
+
+ // begin is not defined here in order to avoid usage of an undefined static
+ // data member, instead it's instantiated by LLVM_INSTANTIATE_REGISTRY.
+ static iterator begin();
+ static iterator end() { return iterator(nullptr); }
+
+ static iterator_range<iterator> entries() {
+ return make_range(begin(), end());
+ }
+
+ /// A static registration template. Use like such:
+ ///
+ /// Registry<Collector>::Add<FancyGC>
+ /// X("fancy-gc", "Newfangled garbage collector.");
+ ///
+ /// Use of this template requires that:
+ ///
+ /// 1. The registered subclass has a default constructor.
+ template <typename V>
+ class Add {
+ entry Entry;
+ node Node;
+
+ static std::unique_ptr<T> CtorFn() { return std::make_unique<V>(); }
+
+ public:
+ Add(StringRef Name, StringRef Desc)
+ : Entry(Name, Desc, CtorFn), Node(Entry) {
+ add_node(&Node);
+ }
+ };
+ };
+} // end namespace llvm
+
+/// Instantiate a registry class.
+///
+/// This provides template definitions of add_node, begin, and the Head and Tail
+/// pointers, then explicitly instantiates them. We could explicitly specialize
+/// them, instead of the two-step process of define then instantiate, but
+/// strictly speaking that's not allowed by the C++ standard (we would need to
+/// have explicit specialization declarations in all translation units where the
+/// specialization is used) so we don't.
+#define LLVM_INSTANTIATE_REGISTRY(REGISTRY_CLASS) \
+ namespace llvm { \
+ template<typename T> typename Registry<T>::node *Registry<T>::Head = nullptr;\
+ template<typename T> typename Registry<T>::node *Registry<T>::Tail = nullptr;\
+ template<typename T> \
+ void Registry<T>::add_node(typename Registry<T>::node *N) { \
+ if (Tail) \
+ Tail->Next = N; \
+ else \
+ Head = N; \
+ Tail = N; \
+ } \
+ template<typename T> typename Registry<T>::iterator Registry<T>::begin() { \
+ return iterator(Head); \
+ } \
+ template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Head; \
+ template REGISTRY_CLASS::node *Registry<REGISTRY_CLASS::type>::Tail; \
+ template \
+ void Registry<REGISTRY_CLASS::type>::add_node(REGISTRY_CLASS::node*); \
+ template REGISTRY_CLASS::iterator Registry<REGISTRY_CLASS::type>::begin(); \
+ }
+
+#endif // LLVM_SUPPORT_REGISTRY_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ReverseIteration.h b/contrib/libs/llvm16/include/llvm/Support/ReverseIteration.h
new file mode 100644
index 00000000000..cac20c480c6
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ReverseIteration.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+#ifndef LLVM_SUPPORT_REVERSEITERATION_H
+#define LLVM_SUPPORT_REVERSEITERATION_H
+
+#include "llvm/Config/abi-breaking.h"
+#include "llvm/Support/PointerLikeTypeTraits.h"
+
+namespace llvm {
+
+template<class T = void *>
+bool shouldReverseIterate() {
+#if LLVM_ENABLE_REVERSE_ITERATION
+ return detail::IsPointerLike<T>::value;
+#else
+ return false;
+#endif
+}
+
+}
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SHA1.h b/contrib/libs/llvm16/include/llvm/Support/SHA1.h
new file mode 100644
index 00000000000..5c90359e80e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SHA1.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//==- SHA1.h - SHA1 implementation for LLVM --*- 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 code is taken from public domain
+// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c)
+// and modified by wrapping it in a C++ interface for LLVM,
+// and removing unnecessary code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SHA1_H
+#define LLVM_SUPPORT_SHA1_H
+
+#include <array>
+#include <cstdint>
+
+namespace llvm {
+template <typename T> class ArrayRef;
+class StringRef;
+
+/// A class that wrap the SHA1 algorithm.
+class SHA1 {
+public:
+ SHA1() { init(); }
+
+ /// Reinitialize the internal state
+ void init();
+
+ /// Digest more data.
+ void update(ArrayRef<uint8_t> Data);
+
+ /// Digest more data.
+ void update(StringRef Str);
+
+ /// Return the current raw 160-bits SHA1 for the digested data
+ /// since the last call to init(). This call will add data to the internal
+ /// state and as such is not suited for getting an intermediate result
+ /// (see result()).
+ std::array<uint8_t, 20> final();
+
+ /// Return the current raw 160-bits SHA1 for the digested data
+ /// since the last call to init(). This is suitable for getting the SHA1 at
+ /// any time without invalidating the internal state so that more calls can be
+ /// made into update.
+ std::array<uint8_t, 20> result();
+
+ /// Returns a raw 160-bit SHA1 hash for the given data.
+ static std::array<uint8_t, 20> hash(ArrayRef<uint8_t> Data);
+
+private:
+ /// Define some constants.
+ /// "static constexpr" would be cleaner but MSVC does not support it yet.
+ enum { BLOCK_LENGTH = 64 };
+ enum { HASH_LENGTH = 20 };
+
+ // Internal State
+ struct {
+ union {
+ uint8_t C[BLOCK_LENGTH];
+ uint32_t L[BLOCK_LENGTH / 4];
+ } Buffer;
+ uint32_t State[HASH_LENGTH / 4];
+ uint32_t ByteCount;
+ uint8_t BufferOffset;
+ } InternalState;
+
+ // Helper
+ void writebyte(uint8_t data);
+ void hashBlock();
+ void addUncounted(uint8_t data);
+ void pad();
+
+ void final(std::array<uint32_t, HASH_LENGTH / 4> &HashResult);
+};
+
+} // end llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SHA256.h b/contrib/libs/llvm16/include/llvm/Support/SHA256.h
new file mode 100644
index 00000000000..25ff8212376
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SHA256.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//====- SHA256.cpp - SHA256 implementation ---*- C++ -* ======//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/*
+ * The SHA-256 Secure Hash Standard was published by NIST in 2002.
+ *
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ *
+ * The implementation is based on nacl's sha256 implementation [0] and LLVM's
+ * pre-exsiting SHA1 code [1].
+ *
+ * [0] https://hyperelliptic.org/nacl/nacl-20110221.tar.bz2 (public domain
+ * code)
+ * [1] llvm/lib/Support/SHA1.{h,cpp}
+ */
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SHA256_H
+#define LLVM_SUPPORT_SHA256_H
+
+#include <array>
+#include <cstdint>
+
+namespace llvm {
+
+template <typename T> class ArrayRef;
+class StringRef;
+
+class SHA256 {
+public:
+ explicit SHA256() { init(); }
+
+ /// Reinitialize the internal state
+ void init();
+
+ /// Digest more data.
+ void update(ArrayRef<uint8_t> Data);
+
+ /// Digest more data.
+ void update(StringRef Str);
+
+ /// Return the current raw 256-bits SHA256 for the digested
+ /// data since the last call to init(). This call will add data to the
+ /// internal state and as such is not suited for getting an intermediate
+ /// result (see result()).
+ std::array<uint8_t, 32> final();
+
+ /// Return the current raw 256-bits SHA256 for the digested
+ /// data since the last call to init(). This is suitable for getting the
+ /// SHA256 at any time without invalidating the internal state so that more
+ /// calls can be made into update.
+ std::array<uint8_t, 32> result();
+
+ /// Returns a raw 256-bit SHA256 hash for the given data.
+ static std::array<uint8_t, 32> hash(ArrayRef<uint8_t> Data);
+
+private:
+ /// Define some constants.
+ /// "static constexpr" would be cleaner but MSVC does not support it yet.
+ enum { BLOCK_LENGTH = 64 };
+ enum { HASH_LENGTH = 32 };
+
+ // Internal State
+ struct {
+ union {
+ uint8_t C[BLOCK_LENGTH];
+ uint32_t L[BLOCK_LENGTH / 4];
+ } Buffer;
+ uint32_t State[HASH_LENGTH / 4];
+ uint32_t ByteCount;
+ uint8_t BufferOffset;
+ } InternalState;
+
+ // Helper
+ void writebyte(uint8_t data);
+ void hashBlock();
+ void addUncounted(uint8_t data);
+ void pad();
+
+ void final(std::array<uint32_t, HASH_LENGTH / 4> &HashResult);
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_SHA256_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SMLoc.h b/contrib/libs/llvm16/include/llvm/Support/SMLoc.h
new file mode 100644
index 00000000000..d91f25afee5
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SMLoc.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- SMLoc.h - Source location for use with diagnostics -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SMLoc class. This class encapsulates a location in
+// source code for use in diagnostics.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SMLOC_H
+#define LLVM_SUPPORT_SMLOC_H
+
+#include <cassert>
+#include <optional>
+
+namespace llvm {
+
+/// Represents a location in source code.
+class SMLoc {
+ const char *Ptr = nullptr;
+
+public:
+ SMLoc() = default;
+
+ bool isValid() const { return Ptr != nullptr; }
+
+ bool operator==(const SMLoc &RHS) const { return RHS.Ptr == Ptr; }
+ bool operator!=(const SMLoc &RHS) const { return RHS.Ptr != Ptr; }
+
+ const char *getPointer() const { return Ptr; }
+
+ static SMLoc getFromPointer(const char *Ptr) {
+ SMLoc L;
+ L.Ptr = Ptr;
+ return L;
+ }
+};
+
+/// Represents a range in source code.
+///
+/// SMRange is implemented using a half-open range, as is the convention in C++.
+/// In the string "abc", the range [1,3) represents the substring "bc", and the
+/// range [2,2) represents an empty range between the characters "b" and "c".
+class SMRange {
+public:
+ SMLoc Start, End;
+
+ SMRange() = default;
+ SMRange(std::nullopt_t) {}
+ SMRange(SMLoc St, SMLoc En) : Start(St), End(En) {
+ assert(Start.isValid() == End.isValid() &&
+ "Start and End should either both be valid or both be invalid!");
+ }
+
+ bool isValid() const { return Start.isValid(); }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_SMLOC_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SMTAPI.h b/contrib/libs/llvm16/include/llvm/Support/SMTAPI.h
new file mode 100644
index 00000000000..55699d26442
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SMTAPI.h
@@ -0,0 +1,458 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- SMTAPI.h -------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a SMT generic Solver API, which will be the base class
+// for every SMT solver specific class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SMTAPI_H
+#define LLVM_SUPPORT_SMTAPI_H
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+
+namespace llvm {
+
+/// Generic base class for SMT sorts
+class SMTSort {
+public:
+ SMTSort() = default;
+ virtual ~SMTSort() = default;
+
+ /// Returns true if the sort is a bitvector, calls isBitvectorSortImpl().
+ virtual bool isBitvectorSort() const { return isBitvectorSortImpl(); }
+
+ /// Returns true if the sort is a floating-point, calls isFloatSortImpl().
+ virtual bool isFloatSort() const { return isFloatSortImpl(); }
+
+ /// Returns true if the sort is a boolean, calls isBooleanSortImpl().
+ virtual bool isBooleanSort() const { return isBooleanSortImpl(); }
+
+ /// Returns the bitvector size, fails if the sort is not a bitvector
+ /// Calls getBitvectorSortSizeImpl().
+ virtual unsigned getBitvectorSortSize() const {
+ assert(isBitvectorSort() && "Not a bitvector sort!");
+ unsigned Size = getBitvectorSortSizeImpl();
+ assert(Size && "Size is zero!");
+ return Size;
+ };
+
+ /// Returns the floating-point size, fails if the sort is not a floating-point
+ /// Calls getFloatSortSizeImpl().
+ virtual unsigned getFloatSortSize() const {
+ assert(isFloatSort() && "Not a floating-point sort!");
+ unsigned Size = getFloatSortSizeImpl();
+ assert(Size && "Size is zero!");
+ return Size;
+ };
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
+
+ bool operator<(const SMTSort &Other) const {
+ llvm::FoldingSetNodeID ID1, ID2;
+ Profile(ID1);
+ Other.Profile(ID2);
+ return ID1 < ID2;
+ }
+
+ friend bool operator==(SMTSort const &LHS, SMTSort const &RHS) {
+ return LHS.equal_to(RHS);
+ }
+
+ virtual void print(raw_ostream &OS) const = 0;
+
+ LLVM_DUMP_METHOD void dump() const;
+
+protected:
+ /// Query the SMT solver and returns true if two sorts are equal (same kind
+ /// and bit width). This does not check if the two sorts are the same objects.
+ virtual bool equal_to(SMTSort const &other) const = 0;
+
+ /// Query the SMT solver and checks if a sort is bitvector.
+ virtual bool isBitvectorSortImpl() const = 0;
+
+ /// Query the SMT solver and checks if a sort is floating-point.
+ virtual bool isFloatSortImpl() const = 0;
+
+ /// Query the SMT solver and checks if a sort is boolean.
+ virtual bool isBooleanSortImpl() const = 0;
+
+ /// Query the SMT solver and returns the sort bit width.
+ virtual unsigned getBitvectorSortSizeImpl() const = 0;
+
+ /// Query the SMT solver and returns the sort bit width.
+ virtual unsigned getFloatSortSizeImpl() const = 0;
+};
+
+/// Shared pointer for SMTSorts, used by SMTSolver API.
+using SMTSortRef = const SMTSort *;
+
+/// Generic base class for SMT exprs
+class SMTExpr {
+public:
+ SMTExpr() = default;
+ virtual ~SMTExpr() = default;
+
+ bool operator<(const SMTExpr &Other) const {
+ llvm::FoldingSetNodeID ID1, ID2;
+ Profile(ID1);
+ Other.Profile(ID2);
+ return ID1 < ID2;
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
+
+ friend bool operator==(SMTExpr const &LHS, SMTExpr const &RHS) {
+ return LHS.equal_to(RHS);
+ }
+
+ virtual void print(raw_ostream &OS) const = 0;
+
+ LLVM_DUMP_METHOD void dump() const;
+
+protected:
+ /// Query the SMT solver and returns true if two sorts are equal (same kind
+ /// and bit width). This does not check if the two sorts are the same objects.
+ virtual bool equal_to(SMTExpr const &other) const = 0;
+};
+
+/// Shared pointer for SMTExprs, used by SMTSolver API.
+using SMTExprRef = const SMTExpr *;
+
+/// Generic base class for SMT Solvers
+///
+/// This class is responsible for wrapping all sorts and expression generation,
+/// through the mk* methods. It also provides methods to create SMT expressions
+/// straight from clang's AST, through the from* methods.
+class SMTSolver {
+public:
+ SMTSolver() = default;
+ virtual ~SMTSolver() = default;
+
+ LLVM_DUMP_METHOD void dump() const;
+
+ // Returns an appropriate floating-point sort for the given bitwidth.
+ SMTSortRef getFloatSort(unsigned BitWidth) {
+ switch (BitWidth) {
+ case 16:
+ return getFloat16Sort();
+ case 32:
+ return getFloat32Sort();
+ case 64:
+ return getFloat64Sort();
+ case 128:
+ return getFloat128Sort();
+ default:;
+ }
+ llvm_unreachable("Unsupported floating-point bitwidth!");
+ }
+
+ // Returns a boolean sort.
+ virtual SMTSortRef getBoolSort() = 0;
+
+ // Returns an appropriate bitvector sort for the given bitwidth.
+ virtual SMTSortRef getBitvectorSort(const unsigned BitWidth) = 0;
+
+ // Returns a floating-point sort of width 16
+ virtual SMTSortRef getFloat16Sort() = 0;
+
+ // Returns a floating-point sort of width 32
+ virtual SMTSortRef getFloat32Sort() = 0;
+
+ // Returns a floating-point sort of width 64
+ virtual SMTSortRef getFloat64Sort() = 0;
+
+ // Returns a floating-point sort of width 128
+ virtual SMTSortRef getFloat128Sort() = 0;
+
+ // Returns an appropriate sort for the given AST.
+ virtual SMTSortRef getSort(const SMTExprRef &AST) = 0;
+
+ /// Given a constraint, adds it to the solver
+ virtual void addConstraint(const SMTExprRef &Exp) const = 0;
+
+ /// Creates a bitvector addition operation
+ virtual SMTExprRef mkBVAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector subtraction operation
+ virtual SMTExprRef mkBVSub(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector multiplication operation
+ virtual SMTExprRef mkBVMul(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed modulus operation
+ virtual SMTExprRef mkBVSRem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned modulus operation
+ virtual SMTExprRef mkBVURem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed division operation
+ virtual SMTExprRef mkBVSDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned division operation
+ virtual SMTExprRef mkBVUDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector logical shift left operation
+ virtual SMTExprRef mkBVShl(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector arithmetic shift right operation
+ virtual SMTExprRef mkBVAshr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector logical shift right operation
+ virtual SMTExprRef mkBVLshr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector negation operation
+ virtual SMTExprRef mkBVNeg(const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector not operation
+ virtual SMTExprRef mkBVNot(const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector xor operation
+ virtual SMTExprRef mkBVXor(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector or operation
+ virtual SMTExprRef mkBVOr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector and operation
+ virtual SMTExprRef mkBVAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned less-than operation
+ virtual SMTExprRef mkBVUlt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed less-than operation
+ virtual SMTExprRef mkBVSlt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned greater-than operation
+ virtual SMTExprRef mkBVUgt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed greater-than operation
+ virtual SMTExprRef mkBVSgt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned less-equal-than operation
+ virtual SMTExprRef mkBVUle(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed less-equal-than operation
+ virtual SMTExprRef mkBVSle(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector unsigned greater-equal-than operation
+ virtual SMTExprRef mkBVUge(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a bitvector signed greater-equal-than operation
+ virtual SMTExprRef mkBVSge(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean not operation
+ virtual SMTExprRef mkNot(const SMTExprRef &Exp) = 0;
+
+ /// Creates a boolean equality operation
+ virtual SMTExprRef mkEqual(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean and operation
+ virtual SMTExprRef mkAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean or operation
+ virtual SMTExprRef mkOr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a boolean ite operation
+ virtual SMTExprRef mkIte(const SMTExprRef &Cond, const SMTExprRef &T,
+ const SMTExprRef &F) = 0;
+
+ /// Creates a bitvector sign extension operation
+ virtual SMTExprRef mkBVSignExt(unsigned i, const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector zero extension operation
+ virtual SMTExprRef mkBVZeroExt(unsigned i, const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector extract operation
+ virtual SMTExprRef mkBVExtract(unsigned High, unsigned Low,
+ const SMTExprRef &Exp) = 0;
+
+ /// Creates a bitvector concat operation
+ virtual SMTExprRef mkBVConcat(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a predicate that checks for overflow in a bitvector addition
+ /// operation
+ virtual SMTExprRef mkBVAddNoOverflow(const SMTExprRef &LHS,
+ const SMTExprRef &RHS,
+ bool isSigned) = 0;
+
+ /// Creates a predicate that checks for underflow in a signed bitvector
+ /// addition operation
+ virtual SMTExprRef mkBVAddNoUnderflow(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a predicate that checks for overflow in a signed bitvector
+ /// subtraction operation
+ virtual SMTExprRef mkBVSubNoOverflow(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a predicate that checks for underflow in a bitvector subtraction
+ /// operation
+ virtual SMTExprRef mkBVSubNoUnderflow(const SMTExprRef &LHS,
+ const SMTExprRef &RHS,
+ bool isSigned) = 0;
+
+ /// Creates a predicate that checks for overflow in a signed bitvector
+ /// division/modulus operation
+ virtual SMTExprRef mkBVSDivNoOverflow(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a predicate that checks for overflow in a bitvector negation
+ /// operation
+ virtual SMTExprRef mkBVNegNoOverflow(const SMTExprRef &Exp) = 0;
+
+ /// Creates a predicate that checks for overflow in a bitvector multiplication
+ /// operation
+ virtual SMTExprRef mkBVMulNoOverflow(const SMTExprRef &LHS,
+ const SMTExprRef &RHS,
+ bool isSigned) = 0;
+
+ /// Creates a predicate that checks for underflow in a signed bitvector
+ /// multiplication operation
+ virtual SMTExprRef mkBVMulNoUnderflow(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point negation operation
+ virtual SMTExprRef mkFPNeg(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isInfinite operation
+ virtual SMTExprRef mkFPIsInfinite(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isNaN operation
+ virtual SMTExprRef mkFPIsNaN(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isNormal operation
+ virtual SMTExprRef mkFPIsNormal(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point isZero operation
+ virtual SMTExprRef mkFPIsZero(const SMTExprRef &Exp) = 0;
+
+ /// Creates a floating-point multiplication operation
+ virtual SMTExprRef mkFPMul(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point division operation
+ virtual SMTExprRef mkFPDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point remainder operation
+ virtual SMTExprRef mkFPRem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point addition operation
+ virtual SMTExprRef mkFPAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point subtraction operation
+ virtual SMTExprRef mkFPSub(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point less-than operation
+ virtual SMTExprRef mkFPLt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point greater-than operation
+ virtual SMTExprRef mkFPGt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point less-than-or-equal operation
+ virtual SMTExprRef mkFPLe(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point greater-than-or-equal operation
+ virtual SMTExprRef mkFPGe(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point equality operation
+ virtual SMTExprRef mkFPEqual(const SMTExprRef &LHS,
+ const SMTExprRef &RHS) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to floating-point
+ /// operation
+ virtual SMTExprRef mkFPtoFP(const SMTExprRef &From, const SMTSortRef &To) = 0;
+
+ /// Creates a floating-point conversion from signed bitvector to
+ /// floatint-point operation
+ virtual SMTExprRef mkSBVtoFP(const SMTExprRef &From,
+ const SMTSortRef &To) = 0;
+
+ /// Creates a floating-point conversion from unsigned bitvector to
+ /// floatint-point operation
+ virtual SMTExprRef mkUBVtoFP(const SMTExprRef &From,
+ const SMTSortRef &To) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to signed
+ /// bitvector operation
+ virtual SMTExprRef mkFPtoSBV(const SMTExprRef &From, unsigned ToWidth) = 0;
+
+ /// Creates a floating-point conversion from floatint-point to unsigned
+ /// bitvector operation
+ virtual SMTExprRef mkFPtoUBV(const SMTExprRef &From, unsigned ToWidth) = 0;
+
+ /// Creates a new symbol, given a name and a sort
+ virtual SMTExprRef mkSymbol(const char *Name, SMTSortRef Sort) = 0;
+
+ // Returns an appropriate floating-point rounding mode.
+ virtual SMTExprRef getFloatRoundingMode() = 0;
+
+ // If the a model is available, returns the value of a given bitvector symbol
+ virtual llvm::APSInt getBitvector(const SMTExprRef &Exp, unsigned BitWidth,
+ bool isUnsigned) = 0;
+
+ // If the a model is available, returns the value of a given boolean symbol
+ virtual bool getBoolean(const SMTExprRef &Exp) = 0;
+
+ /// Constructs an SMTExprRef from a boolean.
+ virtual SMTExprRef mkBoolean(const bool b) = 0;
+
+ /// Constructs an SMTExprRef from a finite APFloat.
+ virtual SMTExprRef mkFloat(const llvm::APFloat Float) = 0;
+
+ /// Constructs an SMTExprRef from an APSInt and its bit width
+ virtual SMTExprRef mkBitvector(const llvm::APSInt Int, unsigned BitWidth) = 0;
+
+ /// Given an expression, extract the value of this operand in the model.
+ virtual bool getInterpretation(const SMTExprRef &Exp, llvm::APSInt &Int) = 0;
+
+ /// Given an expression extract the value of this operand in the model.
+ virtual bool getInterpretation(const SMTExprRef &Exp,
+ llvm::APFloat &Float) = 0;
+
+ /// Check if the constraints are satisfiable
+ virtual std::optional<bool> check() const = 0;
+
+ /// Push the current solver state
+ virtual void push() = 0;
+
+ /// Pop the previous solver state
+ virtual void pop(unsigned NumStates = 1) = 0;
+
+ /// Reset the solver and remove all constraints.
+ virtual void reset() = 0;
+
+ /// Checks if the solver supports floating-points.
+ virtual bool isFPSupported() = 0;
+
+ virtual void print(raw_ostream &OS) const = 0;
+};
+
+/// Shared pointer for SMTSolvers.
+using SMTSolverRef = std::shared_ptr<SMTSolver>;
+
+/// Convenience method to create and Z3Solver object
+SMTSolverRef CreateZ3Solver();
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SaveAndRestore.h b/contrib/libs/llvm16/include/llvm/Support/SaveAndRestore.h
new file mode 100644
index 00000000000..8cc5e4e19b0
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SaveAndRestore.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- SaveAndRestore.h - Utility -------------------------------*- C++ -*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides utility classes that use RAII to save and restore
+/// values.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SAVEANDRESTORE_H
+#define LLVM_SUPPORT_SAVEANDRESTORE_H
+
+#include <utility>
+
+namespace llvm {
+
+/// A utility class that uses RAII to save and restore the value of a variable.
+template <typename T> struct SaveAndRestore {
+ SaveAndRestore(T &X) : X(X), OldValue(X) {}
+ SaveAndRestore(T &X, const T &NewValue) : X(X), OldValue(X) { X = NewValue; }
+ SaveAndRestore(T &X, T &&NewValue) : X(X), OldValue(std::move(X)) {
+ X = std::move(NewValue);
+ }
+ ~SaveAndRestore() { X = std::move(OldValue); }
+ const T &get() { return OldValue; }
+
+private:
+ T &X;
+ T OldValue;
+};
+
+// User-defined CTAD guides.
+template <typename T> SaveAndRestore(T &) -> SaveAndRestore<T>;
+template <typename T> SaveAndRestore(T &, const T &) -> SaveAndRestore<T>;
+template <typename T> SaveAndRestore(T &, T &&) -> SaveAndRestore<T>;
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ScaledNumber.h b/contrib/libs/llvm16/include/llvm/Support/ScaledNumber.h
new file mode 100644
index 00000000000..8880a26c692
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ScaledNumber.h
@@ -0,0 +1,903 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/ScaledNumber.h - Support for scaled numbers -*- 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 functions (and a class) useful for working with scaled
+// numbers -- in particular, pairs of integers where one represents digits and
+// another represents a scale. The functions are helpers and live in the
+// namespace ScaledNumbers. The class ScaledNumber is useful for modelling
+// certain cost metrics that need simple, integer-like semantics that are easy
+// to reason about.
+//
+// These might remind you of soft-floats. If you want one of those, you're in
+// the wrong place. Look at include/llvm/ADT/APFloat.h instead.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SCALEDNUMBER_H
+#define LLVM_SUPPORT_SCALEDNUMBER_H
+
+#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+#include <cstdint>
+#include <limits>
+#include <string>
+#include <tuple>
+#include <utility>
+
+namespace llvm {
+namespace ScaledNumbers {
+
+/// Maximum scale; same as APFloat for easy debug printing.
+const int32_t MaxScale = 16383;
+
+/// Maximum scale; same as APFloat for easy debug printing.
+const int32_t MinScale = -16382;
+
+/// Get the width of a number.
+template <class DigitsT> inline int getWidth() { return sizeof(DigitsT) * 8; }
+
+/// Conditionally round up a scaled number.
+///
+/// Given \c Digits and \c Scale, round up iff \c ShouldRound is \c true.
+/// Always returns \c Scale unless there's an overflow, in which case it
+/// returns \c 1+Scale.
+///
+/// \pre adding 1 to \c Scale will not overflow INT16_MAX.
+template <class DigitsT>
+inline std::pair<DigitsT, int16_t> getRounded(DigitsT Digits, int16_t Scale,
+ bool ShouldRound) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+
+ if (ShouldRound)
+ if (!++Digits)
+ // Overflow.
+ return std::make_pair(DigitsT(1) << (getWidth<DigitsT>() - 1), Scale + 1);
+ return std::make_pair(Digits, Scale);
+}
+
+/// Convenience helper for 32-bit rounding.
+inline std::pair<uint32_t, int16_t> getRounded32(uint32_t Digits, int16_t Scale,
+ bool ShouldRound) {
+ return getRounded(Digits, Scale, ShouldRound);
+}
+
+/// Convenience helper for 64-bit rounding.
+inline std::pair<uint64_t, int16_t> getRounded64(uint64_t Digits, int16_t Scale,
+ bool ShouldRound) {
+ return getRounded(Digits, Scale, ShouldRound);
+}
+
+/// Adjust a 64-bit scaled number down to the appropriate width.
+///
+/// \pre Adding 64 to \c Scale will not overflow INT16_MAX.
+template <class DigitsT>
+inline std::pair<DigitsT, int16_t> getAdjusted(uint64_t Digits,
+ int16_t Scale = 0) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+
+ const int Width = getWidth<DigitsT>();
+ if (Width == 64 || Digits <= std::numeric_limits<DigitsT>::max())
+ return std::make_pair(Digits, Scale);
+
+ // Shift right and round.
+ int Shift = 64 - Width - countLeadingZeros(Digits);
+ return getRounded<DigitsT>(Digits >> Shift, Scale + Shift,
+ Digits & (UINT64_C(1) << (Shift - 1)));
+}
+
+/// Convenience helper for adjusting to 32 bits.
+inline std::pair<uint32_t, int16_t> getAdjusted32(uint64_t Digits,
+ int16_t Scale = 0) {
+ return getAdjusted<uint32_t>(Digits, Scale);
+}
+
+/// Convenience helper for adjusting to 64 bits.
+inline std::pair<uint64_t, int16_t> getAdjusted64(uint64_t Digits,
+ int16_t Scale = 0) {
+ return getAdjusted<uint64_t>(Digits, Scale);
+}
+
+/// Multiply two 64-bit integers to create a 64-bit scaled number.
+///
+/// Implemented with four 64-bit integer multiplies.
+std::pair<uint64_t, int16_t> multiply64(uint64_t LHS, uint64_t RHS);
+
+/// Multiply two 32-bit integers to create a 32-bit scaled number.
+///
+/// Implemented with one 64-bit integer multiply.
+template <class DigitsT>
+inline std::pair<DigitsT, int16_t> getProduct(DigitsT LHS, DigitsT RHS) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+
+ if (getWidth<DigitsT>() <= 32 || (LHS <= UINT32_MAX && RHS <= UINT32_MAX))
+ return getAdjusted<DigitsT>(uint64_t(LHS) * RHS);
+
+ return multiply64(LHS, RHS);
+}
+
+/// Convenience helper for 32-bit product.
+inline std::pair<uint32_t, int16_t> getProduct32(uint32_t LHS, uint32_t RHS) {
+ return getProduct(LHS, RHS);
+}
+
+/// Convenience helper for 64-bit product.
+inline std::pair<uint64_t, int16_t> getProduct64(uint64_t LHS, uint64_t RHS) {
+ return getProduct(LHS, RHS);
+}
+
+/// Divide two 64-bit integers to create a 64-bit scaled number.
+///
+/// Implemented with long division.
+///
+/// \pre \c Dividend and \c Divisor are non-zero.
+std::pair<uint64_t, int16_t> divide64(uint64_t Dividend, uint64_t Divisor);
+
+/// Divide two 32-bit integers to create a 32-bit scaled number.
+///
+/// Implemented with one 64-bit integer divide/remainder pair.
+///
+/// \pre \c Dividend and \c Divisor are non-zero.
+std::pair<uint32_t, int16_t> divide32(uint32_t Dividend, uint32_t Divisor);
+
+/// Divide two 32-bit numbers to create a 32-bit scaled number.
+///
+/// Implemented with one 64-bit integer divide/remainder pair.
+///
+/// Returns \c (DigitsT_MAX, MaxScale) for divide-by-zero (0 for 0/0).
+template <class DigitsT>
+std::pair<DigitsT, int16_t> getQuotient(DigitsT Dividend, DigitsT Divisor) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+ static_assert(sizeof(DigitsT) == 4 || sizeof(DigitsT) == 8,
+ "expected 32-bit or 64-bit digits");
+
+ // Check for zero.
+ if (!Dividend)
+ return std::make_pair(0, 0);
+ if (!Divisor)
+ return std::make_pair(std::numeric_limits<DigitsT>::max(), MaxScale);
+
+ if (getWidth<DigitsT>() == 64)
+ return divide64(Dividend, Divisor);
+ return divide32(Dividend, Divisor);
+}
+
+/// Convenience helper for 32-bit quotient.
+inline std::pair<uint32_t, int16_t> getQuotient32(uint32_t Dividend,
+ uint32_t Divisor) {
+ return getQuotient(Dividend, Divisor);
+}
+
+/// Convenience helper for 64-bit quotient.
+inline std::pair<uint64_t, int16_t> getQuotient64(uint64_t Dividend,
+ uint64_t Divisor) {
+ return getQuotient(Dividend, Divisor);
+}
+
+/// Implementation of getLg() and friends.
+///
+/// Returns the rounded lg of \c Digits*2^Scale and an int specifying whether
+/// this was rounded up (1), down (-1), or exact (0).
+///
+/// Returns \c INT32_MIN when \c Digits is zero.
+template <class DigitsT>
+inline std::pair<int32_t, int> getLgImpl(DigitsT Digits, int16_t Scale) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+
+ if (!Digits)
+ return std::make_pair(INT32_MIN, 0);
+
+ // Get the floor of the lg of Digits.
+ int32_t LocalFloor = sizeof(Digits) * 8 - countLeadingZeros(Digits) - 1;
+
+ // Get the actual floor.
+ int32_t Floor = Scale + LocalFloor;
+ if (Digits == UINT64_C(1) << LocalFloor)
+ return std::make_pair(Floor, 0);
+
+ // Round based on the next digit.
+ assert(LocalFloor >= 1);
+ bool Round = Digits & UINT64_C(1) << (LocalFloor - 1);
+ return std::make_pair(Floor + Round, Round ? 1 : -1);
+}
+
+/// Get the lg (rounded) of a scaled number.
+///
+/// Get the lg of \c Digits*2^Scale.
+///
+/// Returns \c INT32_MIN when \c Digits is zero.
+template <class DigitsT> int32_t getLg(DigitsT Digits, int16_t Scale) {
+ return getLgImpl(Digits, Scale).first;
+}
+
+/// Get the lg floor of a scaled number.
+///
+/// Get the floor of the lg of \c Digits*2^Scale.
+///
+/// Returns \c INT32_MIN when \c Digits is zero.
+template <class DigitsT> int32_t getLgFloor(DigitsT Digits, int16_t Scale) {
+ auto Lg = getLgImpl(Digits, Scale);
+ return Lg.first - (Lg.second > 0);
+}
+
+/// Get the lg ceiling of a scaled number.
+///
+/// Get the ceiling of the lg of \c Digits*2^Scale.
+///
+/// Returns \c INT32_MIN when \c Digits is zero.
+template <class DigitsT> int32_t getLgCeiling(DigitsT Digits, int16_t Scale) {
+ auto Lg = getLgImpl(Digits, Scale);
+ return Lg.first + (Lg.second < 0);
+}
+
+/// Implementation for comparing scaled numbers.
+///
+/// Compare two 64-bit numbers with different scales. Given that the scale of
+/// \c L is higher than that of \c R by \c ScaleDiff, compare them. Return -1,
+/// 1, and 0 for less than, greater than, and equal, respectively.
+///
+/// \pre 0 <= ScaleDiff < 64.
+int compareImpl(uint64_t L, uint64_t R, int ScaleDiff);
+
+/// Compare two scaled numbers.
+///
+/// Compare two scaled numbers. Returns 0 for equal, -1 for less than, and 1
+/// for greater than.
+template <class DigitsT>
+int compare(DigitsT LDigits, int16_t LScale, DigitsT RDigits, int16_t RScale) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+
+ // Check for zero.
+ if (!LDigits)
+ return RDigits ? -1 : 0;
+ if (!RDigits)
+ return 1;
+
+ // Check for the scale. Use getLgFloor to be sure that the scale difference
+ // is always lower than 64.
+ int32_t lgL = getLgFloor(LDigits, LScale), lgR = getLgFloor(RDigits, RScale);
+ if (lgL != lgR)
+ return lgL < lgR ? -1 : 1;
+
+ // Compare digits.
+ if (LScale < RScale)
+ return compareImpl(LDigits, RDigits, RScale - LScale);
+
+ return -compareImpl(RDigits, LDigits, LScale - RScale);
+}
+
+/// Match scales of two numbers.
+///
+/// Given two scaled numbers, match up their scales. Change the digits and
+/// scales in place. Shift the digits as necessary to form equivalent numbers,
+/// losing precision only when necessary.
+///
+/// If the output value of \c LDigits (\c RDigits) is \c 0, the output value of
+/// \c LScale (\c RScale) is unspecified.
+///
+/// As a convenience, returns the matching scale. If the output value of one
+/// number is zero, returns the scale of the other. If both are zero, which
+/// scale is returned is unspecified.
+template <class DigitsT>
+int16_t matchScales(DigitsT &LDigits, int16_t &LScale, DigitsT &RDigits,
+ int16_t &RScale) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+
+ if (LScale < RScale)
+ // Swap arguments.
+ return matchScales(RDigits, RScale, LDigits, LScale);
+ if (!LDigits)
+ return RScale;
+ if (!RDigits || LScale == RScale)
+ return LScale;
+
+ // Now LScale > RScale. Get the difference.
+ int32_t ScaleDiff = int32_t(LScale) - RScale;
+ if (ScaleDiff >= 2 * getWidth<DigitsT>()) {
+ // Don't bother shifting. RDigits will get zero-ed out anyway.
+ RDigits = 0;
+ return LScale;
+ }
+
+ // Shift LDigits left as much as possible, then shift RDigits right.
+ int32_t ShiftL = std::min<int32_t>(countLeadingZeros(LDigits), ScaleDiff);
+ assert(ShiftL < getWidth<DigitsT>() && "can't shift more than width");
+
+ int32_t ShiftR = ScaleDiff - ShiftL;
+ if (ShiftR >= getWidth<DigitsT>()) {
+ // Don't bother shifting. RDigits will get zero-ed out anyway.
+ RDigits = 0;
+ return LScale;
+ }
+
+ LDigits <<= ShiftL;
+ RDigits >>= ShiftR;
+
+ LScale -= ShiftL;
+ RScale += ShiftR;
+ assert(LScale == RScale && "scales should match");
+ return LScale;
+}
+
+/// Get the sum of two scaled numbers.
+///
+/// Get the sum of two scaled numbers with as much precision as possible.
+///
+/// \pre Adding 1 to \c LScale (or \c RScale) will not overflow INT16_MAX.
+template <class DigitsT>
+std::pair<DigitsT, int16_t> getSum(DigitsT LDigits, int16_t LScale,
+ DigitsT RDigits, int16_t RScale) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+
+ // Check inputs up front. This is only relevant if addition overflows, but
+ // testing here should catch more bugs.
+ assert(LScale < INT16_MAX && "scale too large");
+ assert(RScale < INT16_MAX && "scale too large");
+
+ // Normalize digits to match scales.
+ int16_t Scale = matchScales(LDigits, LScale, RDigits, RScale);
+
+ // Compute sum.
+ DigitsT Sum = LDigits + RDigits;
+ if (Sum >= RDigits)
+ return std::make_pair(Sum, Scale);
+
+ // Adjust sum after arithmetic overflow.
+ DigitsT HighBit = DigitsT(1) << (getWidth<DigitsT>() - 1);
+ return std::make_pair(HighBit | Sum >> 1, Scale + 1);
+}
+
+/// Convenience helper for 32-bit sum.
+inline std::pair<uint32_t, int16_t> getSum32(uint32_t LDigits, int16_t LScale,
+ uint32_t RDigits, int16_t RScale) {
+ return getSum(LDigits, LScale, RDigits, RScale);
+}
+
+/// Convenience helper for 64-bit sum.
+inline std::pair<uint64_t, int16_t> getSum64(uint64_t LDigits, int16_t LScale,
+ uint64_t RDigits, int16_t RScale) {
+ return getSum(LDigits, LScale, RDigits, RScale);
+}
+
+/// Get the difference of two scaled numbers.
+///
+/// Get LHS minus RHS with as much precision as possible.
+///
+/// Returns \c (0, 0) if the RHS is larger than the LHS.
+template <class DigitsT>
+std::pair<DigitsT, int16_t> getDifference(DigitsT LDigits, int16_t LScale,
+ DigitsT RDigits, int16_t RScale) {
+ static_assert(!std::numeric_limits<DigitsT>::is_signed, "expected unsigned");
+
+ // Normalize digits to match scales.
+ const DigitsT SavedRDigits = RDigits;
+ const int16_t SavedRScale = RScale;
+ matchScales(LDigits, LScale, RDigits, RScale);
+
+ // Compute difference.
+ if (LDigits <= RDigits)
+ return std::make_pair(0, 0);
+ if (RDigits || !SavedRDigits)
+ return std::make_pair(LDigits - RDigits, LScale);
+
+ // Check if RDigits just barely lost its last bit. E.g., for 32-bit:
+ //
+ // 1*2^32 - 1*2^0 == 0xffffffff != 1*2^32
+ const auto RLgFloor = getLgFloor(SavedRDigits, SavedRScale);
+ if (!compare(LDigits, LScale, DigitsT(1), RLgFloor + getWidth<DigitsT>()))
+ return std::make_pair(std::numeric_limits<DigitsT>::max(), RLgFloor);
+
+ return std::make_pair(LDigits, LScale);
+}
+
+/// Convenience helper for 32-bit difference.
+inline std::pair<uint32_t, int16_t> getDifference32(uint32_t LDigits,
+ int16_t LScale,
+ uint32_t RDigits,
+ int16_t RScale) {
+ return getDifference(LDigits, LScale, RDigits, RScale);
+}
+
+/// Convenience helper for 64-bit difference.
+inline std::pair<uint64_t, int16_t> getDifference64(uint64_t LDigits,
+ int16_t LScale,
+ uint64_t RDigits,
+ int16_t RScale) {
+ return getDifference(LDigits, LScale, RDigits, RScale);
+}
+
+} // end namespace ScaledNumbers
+} // end namespace llvm
+
+namespace llvm {
+
+class raw_ostream;
+class ScaledNumberBase {
+public:
+ static constexpr int DefaultPrecision = 10;
+
+ static void dump(uint64_t D, int16_t E, int Width);
+ static raw_ostream &print(raw_ostream &OS, uint64_t D, int16_t E, int Width,
+ unsigned Precision);
+ static std::string toString(uint64_t D, int16_t E, int Width,
+ unsigned Precision);
+ static int countLeadingZeros32(uint32_t N) { return countLeadingZeros(N); }
+ static int countLeadingZeros64(uint64_t N) { return countLeadingZeros(N); }
+ static uint64_t getHalf(uint64_t N) { return (N >> 1) + (N & 1); }
+
+ static std::pair<uint64_t, bool> splitSigned(int64_t N) {
+ if (N >= 0)
+ return std::make_pair(N, false);
+ uint64_t Unsigned = N == INT64_MIN ? UINT64_C(1) << 63 : uint64_t(-N);
+ return std::make_pair(Unsigned, true);
+ }
+ static int64_t joinSigned(uint64_t U, bool IsNeg) {
+ if (U > uint64_t(INT64_MAX))
+ return IsNeg ? INT64_MIN : INT64_MAX;
+ return IsNeg ? -int64_t(U) : int64_t(U);
+ }
+};
+
+/// Simple representation of a scaled number.
+///
+/// ScaledNumber is a number represented by digits and a scale. It uses simple
+/// saturation arithmetic and every operation is well-defined for every value.
+/// It's somewhat similar in behaviour to a soft-float, but is *not* a
+/// replacement for one. If you're doing numerics, look at \a APFloat instead.
+/// Nevertheless, we've found these semantics useful for modelling certain cost
+/// metrics.
+///
+/// The number is split into a signed scale and unsigned digits. The number
+/// represented is \c getDigits()*2^getScale(). In this way, the digits are
+/// much like the mantissa in the x87 long double, but there is no canonical
+/// form so the same number can be represented by many bit representations.
+///
+/// ScaledNumber is templated on the underlying integer type for digits, which
+/// is expected to be unsigned.
+///
+/// Unlike APFloat, ScaledNumber does not model architecture floating point
+/// behaviour -- while this might make it a little faster and easier to reason
+/// about, it certainly makes it more dangerous for general numerics.
+///
+/// ScaledNumber is totally ordered. However, there is no canonical form, so
+/// there are multiple representations of most scalars. E.g.:
+///
+/// ScaledNumber(8u, 0) == ScaledNumber(4u, 1)
+/// ScaledNumber(4u, 1) == ScaledNumber(2u, 2)
+/// ScaledNumber(2u, 2) == ScaledNumber(1u, 3)
+///
+/// ScaledNumber implements most arithmetic operations. Precision is kept
+/// where possible. Uses simple saturation arithmetic, so that operations
+/// saturate to 0.0 or getLargest() rather than under or overflowing. It has
+/// some extra arithmetic for unit inversion. 0.0/0.0 is defined to be 0.0.
+/// Any other division by 0.0 is defined to be getLargest().
+///
+/// As a convenience for modifying the exponent, left and right shifting are
+/// both implemented, and both interpret negative shifts as positive shifts in
+/// the opposite direction.
+///
+/// Scales are limited to the range accepted by x87 long double. This makes
+/// it trivial to add functionality to convert to APFloat (this is already
+/// relied on for the implementation of printing).
+///
+/// Possible (and conflicting) future directions:
+///
+/// 1. Turn this into a wrapper around \a APFloat.
+/// 2. Share the algorithm implementations with \a APFloat.
+/// 3. Allow \a ScaledNumber to represent a signed number.
+template <class DigitsT> class ScaledNumber : ScaledNumberBase {
+public:
+ static_assert(!std::numeric_limits<DigitsT>::is_signed,
+ "only unsigned floats supported");
+
+ typedef DigitsT DigitsType;
+
+private:
+ typedef std::numeric_limits<DigitsType> DigitsLimits;
+
+ static constexpr int Width = sizeof(DigitsType) * 8;
+ static_assert(Width <= 64, "invalid integer width for digits");
+
+private:
+ DigitsType Digits = 0;
+ int16_t Scale = 0;
+
+public:
+ ScaledNumber() = default;
+
+ constexpr ScaledNumber(DigitsType Digits, int16_t Scale)
+ : Digits(Digits), Scale(Scale) {}
+
+private:
+ ScaledNumber(const std::pair<DigitsT, int16_t> &X)
+ : Digits(X.first), Scale(X.second) {}
+
+public:
+ static ScaledNumber getZero() { return ScaledNumber(0, 0); }
+ static ScaledNumber getOne() { return ScaledNumber(1, 0); }
+ static ScaledNumber getLargest() {
+ return ScaledNumber(DigitsLimits::max(), ScaledNumbers::MaxScale);
+ }
+ static ScaledNumber get(uint64_t N) { return adjustToWidth(N, 0); }
+ static ScaledNumber getInverse(uint64_t N) {
+ return get(N).invert();
+ }
+ static ScaledNumber getFraction(DigitsType N, DigitsType D) {
+ return getQuotient(N, D);
+ }
+
+ int16_t getScale() const { return Scale; }
+ DigitsType getDigits() const { return Digits; }
+
+ /// Convert to the given integer type.
+ ///
+ /// Convert to \c IntT using simple saturating arithmetic, truncating if
+ /// necessary.
+ template <class IntT> IntT toInt() const;
+
+ bool isZero() const { return !Digits; }
+ bool isLargest() const { return *this == getLargest(); }
+ bool isOne() const {
+ if (Scale > 0 || Scale <= -Width)
+ return false;
+ return Digits == DigitsType(1) << -Scale;
+ }
+
+ /// The log base 2, rounded.
+ ///
+ /// Get the lg of the scalar. lg 0 is defined to be INT32_MIN.
+ int32_t lg() const { return ScaledNumbers::getLg(Digits, Scale); }
+
+ /// The log base 2, rounded towards INT32_MIN.
+ ///
+ /// Get the lg floor. lg 0 is defined to be INT32_MIN.
+ int32_t lgFloor() const { return ScaledNumbers::getLgFloor(Digits, Scale); }
+
+ /// The log base 2, rounded towards INT32_MAX.
+ ///
+ /// Get the lg ceiling. lg 0 is defined to be INT32_MIN.
+ int32_t lgCeiling() const {
+ return ScaledNumbers::getLgCeiling(Digits, Scale);
+ }
+
+ bool operator==(const ScaledNumber &X) const { return compare(X) == 0; }
+ bool operator<(const ScaledNumber &X) const { return compare(X) < 0; }
+ bool operator!=(const ScaledNumber &X) const { return compare(X) != 0; }
+ bool operator>(const ScaledNumber &X) const { return compare(X) > 0; }
+ bool operator<=(const ScaledNumber &X) const { return compare(X) <= 0; }
+ bool operator>=(const ScaledNumber &X) const { return compare(X) >= 0; }
+
+ bool operator!() const { return isZero(); }
+
+ /// Convert to a decimal representation in a string.
+ ///
+ /// Convert to a string. Uses scientific notation for very large/small
+ /// numbers. Scientific notation is used roughly for numbers outside of the
+ /// range 2^-64 through 2^64.
+ ///
+ /// \c Precision indicates the number of decimal digits of precision to use;
+ /// 0 requests the maximum available.
+ ///
+ /// As a special case to make debugging easier, if the number is small enough
+ /// to convert without scientific notation and has more than \c Precision
+ /// digits before the decimal place, it's printed accurately to the first
+ /// digit past zero. E.g., assuming 10 digits of precision:
+ ///
+ /// 98765432198.7654... => 98765432198.8
+ /// 8765432198.7654... => 8765432198.8
+ /// 765432198.7654... => 765432198.8
+ /// 65432198.7654... => 65432198.77
+ /// 5432198.7654... => 5432198.765
+ std::string toString(unsigned Precision = DefaultPrecision) {
+ return ScaledNumberBase::toString(Digits, Scale, Width, Precision);
+ }
+
+ /// Print a decimal representation.
+ ///
+ /// Print a string. See toString for documentation.
+ raw_ostream &print(raw_ostream &OS,
+ unsigned Precision = DefaultPrecision) const {
+ return ScaledNumberBase::print(OS, Digits, Scale, Width, Precision);
+ }
+ void dump() const { return ScaledNumberBase::dump(Digits, Scale, Width); }
+
+ ScaledNumber &operator+=(const ScaledNumber &X) {
+ std::tie(Digits, Scale) =
+ ScaledNumbers::getSum(Digits, Scale, X.Digits, X.Scale);
+ // Check for exponent past MaxScale.
+ if (Scale > ScaledNumbers::MaxScale)
+ *this = getLargest();
+ return *this;
+ }
+ ScaledNumber &operator-=(const ScaledNumber &X) {
+ std::tie(Digits, Scale) =
+ ScaledNumbers::getDifference(Digits, Scale, X.Digits, X.Scale);
+ return *this;
+ }
+ ScaledNumber &operator*=(const ScaledNumber &X);
+ ScaledNumber &operator/=(const ScaledNumber &X);
+ ScaledNumber &operator<<=(int16_t Shift) {
+ shiftLeft(Shift);
+ return *this;
+ }
+ ScaledNumber &operator>>=(int16_t Shift) {
+ shiftRight(Shift);
+ return *this;
+ }
+
+private:
+ void shiftLeft(int32_t Shift);
+ void shiftRight(int32_t Shift);
+
+ /// Adjust two floats to have matching exponents.
+ ///
+ /// Adjust \c this and \c X to have matching exponents. Returns the new \c X
+ /// by value. Does nothing if \a isZero() for either.
+ ///
+ /// The value that compares smaller will lose precision, and possibly become
+ /// \a isZero().
+ ScaledNumber matchScales(ScaledNumber X) {
+ ScaledNumbers::matchScales(Digits, Scale, X.Digits, X.Scale);
+ return X;
+ }
+
+public:
+ /// Scale a large number accurately.
+ ///
+ /// Scale N (multiply it by this). Uses full precision multiplication, even
+ /// if Width is smaller than 64, so information is not lost.
+ uint64_t scale(uint64_t N) const;
+ uint64_t scaleByInverse(uint64_t N) const {
+ // TODO: implement directly, rather than relying on inverse. Inverse is
+ // expensive.
+ return inverse().scale(N);
+ }
+ int64_t scale(int64_t N) const {
+ std::pair<uint64_t, bool> Unsigned = splitSigned(N);
+ return joinSigned(scale(Unsigned.first), Unsigned.second);
+ }
+ int64_t scaleByInverse(int64_t N) const {
+ std::pair<uint64_t, bool> Unsigned = splitSigned(N);
+ return joinSigned(scaleByInverse(Unsigned.first), Unsigned.second);
+ }
+
+ int compare(const ScaledNumber &X) const {
+ return ScaledNumbers::compare(Digits, Scale, X.Digits, X.Scale);
+ }
+ int compareTo(uint64_t N) const {
+ return ScaledNumbers::compare<uint64_t>(Digits, Scale, N, 0);
+ }
+ int compareTo(int64_t N) const { return N < 0 ? 1 : compareTo(uint64_t(N)); }
+
+ ScaledNumber &invert() { return *this = ScaledNumber::get(1) / *this; }
+ ScaledNumber inverse() const { return ScaledNumber(*this).invert(); }
+
+private:
+ static ScaledNumber getProduct(DigitsType LHS, DigitsType RHS) {
+ return ScaledNumbers::getProduct(LHS, RHS);
+ }
+ static ScaledNumber getQuotient(DigitsType Dividend, DigitsType Divisor) {
+ return ScaledNumbers::getQuotient(Dividend, Divisor);
+ }
+
+ static int countLeadingZerosWidth(DigitsType Digits) {
+ if (Width == 64)
+ return countLeadingZeros64(Digits);
+ if (Width == 32)
+ return countLeadingZeros32(Digits);
+ return countLeadingZeros32(Digits) + Width - 32;
+ }
+
+ /// Adjust a number to width, rounding up if necessary.
+ ///
+ /// Should only be called for \c Shift close to zero.
+ ///
+ /// \pre Shift >= MinScale && Shift + 64 <= MaxScale.
+ static ScaledNumber adjustToWidth(uint64_t N, int32_t Shift) {
+ assert(Shift >= ScaledNumbers::MinScale && "Shift should be close to 0");
+ assert(Shift <= ScaledNumbers::MaxScale - 64 &&
+ "Shift should be close to 0");
+ auto Adjusted = ScaledNumbers::getAdjusted<DigitsT>(N, Shift);
+ return Adjusted;
+ }
+
+ static ScaledNumber getRounded(ScaledNumber P, bool Round) {
+ // Saturate.
+ if (P.isLargest())
+ return P;
+
+ return ScaledNumbers::getRounded(P.Digits, P.Scale, Round);
+ }
+};
+
+#define SCALED_NUMBER_BOP(op, base) \
+ template <class DigitsT> \
+ ScaledNumber<DigitsT> operator op(const ScaledNumber<DigitsT> &L, \
+ const ScaledNumber<DigitsT> &R) { \
+ return ScaledNumber<DigitsT>(L) base R; \
+ }
+SCALED_NUMBER_BOP(+, += )
+SCALED_NUMBER_BOP(-, -= )
+SCALED_NUMBER_BOP(*, *= )
+SCALED_NUMBER_BOP(/, /= )
+#undef SCALED_NUMBER_BOP
+
+template <class DigitsT>
+ScaledNumber<DigitsT> operator<<(const ScaledNumber<DigitsT> &L,
+ int16_t Shift) {
+ return ScaledNumber<DigitsT>(L) <<= Shift;
+}
+
+template <class DigitsT>
+ScaledNumber<DigitsT> operator>>(const ScaledNumber<DigitsT> &L,
+ int16_t Shift) {
+ return ScaledNumber<DigitsT>(L) >>= Shift;
+}
+
+template <class DigitsT>
+raw_ostream &operator<<(raw_ostream &OS, const ScaledNumber<DigitsT> &X) {
+ return X.print(OS, 10);
+}
+
+#define SCALED_NUMBER_COMPARE_TO_TYPE(op, T1, T2) \
+ template <class DigitsT> \
+ bool operator op(const ScaledNumber<DigitsT> &L, T1 R) { \
+ return L.compareTo(T2(R)) op 0; \
+ } \
+ template <class DigitsT> \
+ bool operator op(T1 L, const ScaledNumber<DigitsT> &R) { \
+ return 0 op R.compareTo(T2(L)); \
+ }
+#define SCALED_NUMBER_COMPARE_TO(op) \
+ SCALED_NUMBER_COMPARE_TO_TYPE(op, uint64_t, uint64_t) \
+ SCALED_NUMBER_COMPARE_TO_TYPE(op, uint32_t, uint64_t) \
+ SCALED_NUMBER_COMPARE_TO_TYPE(op, int64_t, int64_t) \
+ SCALED_NUMBER_COMPARE_TO_TYPE(op, int32_t, int64_t)
+SCALED_NUMBER_COMPARE_TO(< )
+SCALED_NUMBER_COMPARE_TO(> )
+SCALED_NUMBER_COMPARE_TO(== )
+SCALED_NUMBER_COMPARE_TO(!= )
+SCALED_NUMBER_COMPARE_TO(<= )
+SCALED_NUMBER_COMPARE_TO(>= )
+#undef SCALED_NUMBER_COMPARE_TO
+#undef SCALED_NUMBER_COMPARE_TO_TYPE
+
+template <class DigitsT>
+uint64_t ScaledNumber<DigitsT>::scale(uint64_t N) const {
+ if (Width == 64 || N <= DigitsLimits::max())
+ return (get(N) * *this).template toInt<uint64_t>();
+
+ // Defer to the 64-bit version.
+ return ScaledNumber<uint64_t>(Digits, Scale).scale(N);
+}
+
+template <class DigitsT>
+template <class IntT>
+IntT ScaledNumber<DigitsT>::toInt() const {
+ typedef std::numeric_limits<IntT> Limits;
+ if (*this < 1)
+ return 0;
+ if (*this >= Limits::max())
+ return Limits::max();
+
+ IntT N = Digits;
+ if (Scale > 0) {
+ assert(size_t(Scale) < sizeof(IntT) * 8);
+ return N << Scale;
+ }
+ if (Scale < 0) {
+ assert(size_t(-Scale) < sizeof(IntT) * 8);
+ return N >> -Scale;
+ }
+ return N;
+}
+
+template <class DigitsT>
+ScaledNumber<DigitsT> &ScaledNumber<DigitsT>::
+operator*=(const ScaledNumber &X) {
+ if (isZero())
+ return *this;
+ if (X.isZero())
+ return *this = X;
+
+ // Save the exponents.
+ int32_t Scales = int32_t(Scale) + int32_t(X.Scale);
+
+ // Get the raw product.
+ *this = getProduct(Digits, X.Digits);
+
+ // Combine with exponents.
+ return *this <<= Scales;
+}
+template <class DigitsT>
+ScaledNumber<DigitsT> &ScaledNumber<DigitsT>::
+operator/=(const ScaledNumber &X) {
+ if (isZero())
+ return *this;
+ if (X.isZero())
+ return *this = getLargest();
+
+ // Save the exponents.
+ int32_t Scales = int32_t(Scale) - int32_t(X.Scale);
+
+ // Get the raw quotient.
+ *this = getQuotient(Digits, X.Digits);
+
+ // Combine with exponents.
+ return *this <<= Scales;
+}
+template <class DigitsT> void ScaledNumber<DigitsT>::shiftLeft(int32_t Shift) {
+ if (!Shift || isZero())
+ return;
+ assert(Shift != INT32_MIN);
+ if (Shift < 0) {
+ shiftRight(-Shift);
+ return;
+ }
+
+ // Shift as much as we can in the exponent.
+ int32_t ScaleShift = std::min(Shift, ScaledNumbers::MaxScale - Scale);
+ Scale += ScaleShift;
+ if (ScaleShift == Shift)
+ return;
+
+ // Check this late, since it's rare.
+ if (isLargest())
+ return;
+
+ // Shift the digits themselves.
+ Shift -= ScaleShift;
+ if (Shift > countLeadingZerosWidth(Digits)) {
+ // Saturate.
+ *this = getLargest();
+ return;
+ }
+
+ Digits <<= Shift;
+}
+
+template <class DigitsT> void ScaledNumber<DigitsT>::shiftRight(int32_t Shift) {
+ if (!Shift || isZero())
+ return;
+ assert(Shift != INT32_MIN);
+ if (Shift < 0) {
+ shiftLeft(-Shift);
+ return;
+ }
+
+ // Shift as much as we can in the exponent.
+ int32_t ScaleShift = std::min(Shift, Scale - ScaledNumbers::MinScale);
+ Scale -= ScaleShift;
+ if (ScaleShift == Shift)
+ return;
+
+ // Shift the digits themselves.
+ Shift -= ScaleShift;
+ if (Shift >= Width) {
+ // Saturate.
+ *this = getZero();
+ return;
+ }
+
+ Digits >>= Shift;
+}
+
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_SCALEDNUMBER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ScopedPrinter.h b/contrib/libs/llvm16/include/llvm/Support/ScopedPrinter.h
new file mode 100644
index 00000000000..1e8b8db2cce
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ScopedPrinter.h
@@ -0,0 +1,860 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- ScopedPrinter.h ----------------------------------------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SCOPEDPRINTER_H
+#define LLVM_SUPPORT_SCOPEDPRINTER_H
+
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+template <typename T> struct EnumEntry {
+ StringRef Name;
+ // While Name suffices in most of the cases, in certain cases
+ // GNU style and LLVM style of ELFDumper do not
+ // display same string for same enum. The AltName if initialized appropriately
+ // will hold the string that GNU style emits.
+ // Example:
+ // "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to
+ // "Advanced Micro Devices X86-64" on GNU style
+ StringRef AltName;
+ T Value;
+ constexpr EnumEntry(StringRef N, StringRef A, T V)
+ : Name(N), AltName(A), Value(V) {}
+ constexpr EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {}
+};
+
+struct HexNumber {
+ // To avoid sign-extension we have to explicitly cast to the appropriate
+ // unsigned type. The overloads are here so that every type that is implicitly
+ // convertible to an integer (including enums and endian helpers) can be used
+ // without requiring type traits or call-site changes.
+ HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {}
+ HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {}
+ HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {}
+ HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {}
+ HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {}
+ HexNumber(signed long long Value)
+ : Value(static_cast<unsigned long long>(Value)) {}
+ HexNumber(unsigned char Value) : Value(Value) {}
+ HexNumber(unsigned short Value) : Value(Value) {}
+ HexNumber(unsigned int Value) : Value(Value) {}
+ HexNumber(unsigned long Value) : Value(Value) {}
+ HexNumber(unsigned long long Value) : Value(Value) {}
+ uint64_t Value;
+};
+
+struct FlagEntry {
+ FlagEntry(StringRef Name, char Value)
+ : Name(Name), Value(static_cast<unsigned char>(Value)) {}
+ FlagEntry(StringRef Name, signed char Value)
+ : Name(Name), Value(static_cast<unsigned char>(Value)) {}
+ FlagEntry(StringRef Name, signed short Value)
+ : Name(Name), Value(static_cast<unsigned short>(Value)) {}
+ FlagEntry(StringRef Name, signed int Value)
+ : Name(Name), Value(static_cast<unsigned int>(Value)) {}
+ FlagEntry(StringRef Name, signed long Value)
+ : Name(Name), Value(static_cast<unsigned long>(Value)) {}
+ FlagEntry(StringRef Name, signed long long Value)
+ : Name(Name), Value(static_cast<unsigned long long>(Value)) {}
+ FlagEntry(StringRef Name, unsigned char Value) : Name(Name), Value(Value) {}
+ FlagEntry(StringRef Name, unsigned short Value) : Name(Name), Value(Value) {}
+ FlagEntry(StringRef Name, unsigned int Value) : Name(Name), Value(Value) {}
+ FlagEntry(StringRef Name, unsigned long Value) : Name(Name), Value(Value) {}
+ FlagEntry(StringRef Name, unsigned long long Value)
+ : Name(Name), Value(Value) {}
+ StringRef Name;
+ uint64_t Value;
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value);
+
+template <class T> std::string to_string(const T &Value) {
+ std::string number;
+ raw_string_ostream stream(number);
+ stream << Value;
+ return stream.str();
+}
+
+template <typename T, typename TEnum>
+std::string enumToString(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues) {
+ for (const EnumEntry<TEnum> &EnumItem : EnumValues)
+ if (EnumItem.Value == Value)
+ return std::string(EnumItem.AltName);
+ return utohexstr(Value, true);
+}
+
+class ScopedPrinter {
+public:
+ enum class ScopedPrinterKind {
+ Base,
+ JSON,
+ };
+
+ ScopedPrinter(raw_ostream &OS,
+ ScopedPrinterKind Kind = ScopedPrinterKind::Base)
+ : OS(OS), Kind(Kind) {}
+
+ ScopedPrinterKind getKind() const { return Kind; }
+
+ static bool classof(const ScopedPrinter *SP) {
+ return SP->getKind() == ScopedPrinterKind::Base;
+ }
+
+ virtual ~ScopedPrinter() = default;
+
+ void flush() { OS.flush(); }
+
+ void indent(int Levels = 1) { IndentLevel += Levels; }
+
+ void unindent(int Levels = 1) {
+ IndentLevel = IndentLevel > Levels ? IndentLevel - Levels : 0;
+ }
+
+ void resetIndent() { IndentLevel = 0; }
+
+ int getIndentLevel() { return IndentLevel; }
+
+ void setPrefix(StringRef P) { Prefix = P; }
+
+ void printIndent() {
+ OS << Prefix;
+ for (int i = 0; i < IndentLevel; ++i)
+ OS << " ";
+ }
+
+ template <typename T> HexNumber hex(T Value) { return HexNumber(Value); }
+
+ template <typename T, typename TEnum>
+ void printEnum(StringRef Label, T Value,
+ ArrayRef<EnumEntry<TEnum>> EnumValues) {
+ StringRef Name;
+ bool Found = false;
+ for (const auto &EnumItem : EnumValues) {
+ if (EnumItem.Value == Value) {
+ Name = EnumItem.Name;
+ Found = true;
+ break;
+ }
+ }
+
+ if (Found)
+ printHex(Label, Name, Value);
+ else
+ printHex(Label, Value);
+ }
+
+ template <typename T, typename TFlag>
+ void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
+ TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
+ TFlag EnumMask3 = {}) {
+ SmallVector<FlagEntry, 10> SetFlags;
+
+ for (const auto &Flag : Flags) {
+ if (Flag.Value == 0)
+ continue;
+
+ TFlag EnumMask{};
+ if (Flag.Value & EnumMask1)
+ EnumMask = EnumMask1;
+ else if (Flag.Value & EnumMask2)
+ EnumMask = EnumMask2;
+ else if (Flag.Value & EnumMask3)
+ EnumMask = EnumMask3;
+ bool IsEnum = (Flag.Value & EnumMask) != 0;
+ if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
+ (IsEnum && (Value & EnumMask) == Flag.Value)) {
+ SetFlags.emplace_back(Flag.Name, Flag.Value);
+ }
+ }
+
+ llvm::sort(SetFlags, &flagName);
+ printFlagsImpl(Label, hex(Value), SetFlags);
+ }
+
+ template <typename T> void printFlags(StringRef Label, T Value) {
+ SmallVector<HexNumber, 10> SetFlags;
+ uint64_t Flag = 1;
+ uint64_t Curr = Value;
+ while (Curr > 0) {
+ if (Curr & 1)
+ SetFlags.emplace_back(Flag);
+ Curr >>= 1;
+ Flag <<= 1;
+ }
+ printFlagsImpl(Label, hex(Value), SetFlags);
+ }
+
+ virtual void printNumber(StringRef Label, uint64_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ virtual void printNumber(StringRef Label, uint32_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ virtual void printNumber(StringRef Label, uint16_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ virtual void printNumber(StringRef Label, uint8_t Value) {
+ startLine() << Label << ": " << unsigned(Value) << "\n";
+ }
+
+ virtual void printNumber(StringRef Label, int64_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ virtual void printNumber(StringRef Label, int32_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ virtual void printNumber(StringRef Label, int16_t Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ virtual void printNumber(StringRef Label, int8_t Value) {
+ startLine() << Label << ": " << int(Value) << "\n";
+ }
+
+ virtual void printNumber(StringRef Label, const APSInt &Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ template <typename T>
+ void printNumber(StringRef Label, StringRef Str, T Value) {
+ printNumberImpl(Label, Str, to_string(Value));
+ }
+
+ virtual void printBoolean(StringRef Label, bool Value) {
+ startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
+ }
+
+ template <typename... T> void printVersion(StringRef Label, T... Version) {
+ startLine() << Label << ": ";
+ printVersionInternal(Version...);
+ getOStream() << "\n";
+ }
+
+ template <typename T>
+ void printList(StringRef Label, const ArrayRef<T> List) {
+ SmallVector<std::string, 10> StringList;
+ for (const auto &Item : List)
+ StringList.emplace_back(to_string(Item));
+ printList(Label, StringList);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<bool> List) {
+ printListImpl(Label, List);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<std::string> List) {
+ printListImpl(Label, List);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<uint64_t> List) {
+ printListImpl(Label, List);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<uint32_t> List) {
+ printListImpl(Label, List);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<uint16_t> List) {
+ printListImpl(Label, List);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<uint8_t> List) {
+ SmallVector<unsigned> NumberList;
+ for (const uint8_t &Item : List)
+ NumberList.emplace_back(Item);
+ printListImpl(Label, NumberList);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<int64_t> List) {
+ printListImpl(Label, List);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<int32_t> List) {
+ printListImpl(Label, List);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<int16_t> List) {
+ printListImpl(Label, List);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<int8_t> List) {
+ SmallVector<int> NumberList;
+ for (const int8_t &Item : List)
+ NumberList.emplace_back(Item);
+ printListImpl(Label, NumberList);
+ }
+
+ virtual void printList(StringRef Label, const ArrayRef<APSInt> List) {
+ printListImpl(Label, List);
+ }
+
+ template <typename T, typename U>
+ void printList(StringRef Label, const T &List, const U &Printer) {
+ startLine() << Label << ": [";
+ ListSeparator LS;
+ for (const auto &Item : List) {
+ OS << LS;
+ Printer(OS, Item);
+ }
+ OS << "]\n";
+ }
+
+ template <typename T> void printHexList(StringRef Label, const T &List) {
+ SmallVector<HexNumber> HexList;
+ for (const auto &Item : List)
+ HexList.emplace_back(Item);
+ printHexListImpl(Label, HexList);
+ }
+
+ template <typename T> void printHex(StringRef Label, T Value) {
+ printHexImpl(Label, hex(Value));
+ }
+
+ template <typename T> void printHex(StringRef Label, StringRef Str, T Value) {
+ printHexImpl(Label, Str, hex(Value));
+ }
+
+ template <typename T>
+ void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) {
+ printSymbolOffsetImpl(Label, Symbol, hex(Value));
+ }
+
+ virtual void printString(StringRef Value) { startLine() << Value << "\n"; }
+
+ virtual void printString(StringRef Label, StringRef Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ void printStringEscaped(StringRef Label, StringRef Value) {
+ printStringEscapedImpl(Label, Value);
+ }
+
+ void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, Str, Value, false);
+ }
+
+ void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
+ auto V =
+ ArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), Value.size());
+ printBinaryImpl(Label, Str, V, false);
+ }
+
+ void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, StringRef(), Value, false);
+ }
+
+ void printBinary(StringRef Label, ArrayRef<char> Value) {
+ auto V =
+ ArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), Value.size());
+ printBinaryImpl(Label, StringRef(), V, false);
+ }
+
+ void printBinary(StringRef Label, StringRef Value) {
+ auto V =
+ ArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), Value.size());
+ printBinaryImpl(Label, StringRef(), V, false);
+ }
+
+ void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value,
+ uint32_t StartOffset) {
+ printBinaryImpl(Label, StringRef(), Value, true, StartOffset);
+ }
+
+ void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
+ printBinaryImpl(Label, StringRef(), Value, true);
+ }
+
+ void printBinaryBlock(StringRef Label, StringRef Value) {
+ auto V =
+ ArrayRef(reinterpret_cast<const uint8_t *>(Value.data()), Value.size());
+ printBinaryImpl(Label, StringRef(), V, true);
+ }
+
+ template <typename T> void printObject(StringRef Label, const T &Value) {
+ printString(Label, to_string(Value));
+ }
+
+ virtual void objectBegin() { scopedBegin('{'); }
+
+ virtual void objectBegin(StringRef Label) { scopedBegin(Label, '{'); }
+
+ virtual void objectEnd() { scopedEnd('}'); }
+
+ virtual void arrayBegin() { scopedBegin('['); }
+
+ virtual void arrayBegin(StringRef Label) { scopedBegin(Label, '['); }
+
+ virtual void arrayEnd() { scopedEnd(']'); }
+
+ virtual raw_ostream &startLine() {
+ printIndent();
+ return OS;
+ }
+
+ virtual raw_ostream &getOStream() { return OS; }
+
+private:
+ template <typename T> void printVersionInternal(T Value) {
+ getOStream() << Value;
+ }
+
+ template <typename S, typename T, typename... TArgs>
+ void printVersionInternal(S Value, T Value2, TArgs... Args) {
+ getOStream() << Value << ".";
+ printVersionInternal(Value2, Args...);
+ }
+
+ static bool flagName(const FlagEntry &LHS, const FlagEntry &RHS) {
+ return LHS.Name < RHS.Name;
+ }
+
+ virtual void printBinaryImpl(StringRef Label, StringRef Str,
+ ArrayRef<uint8_t> Value, bool Block,
+ uint32_t StartOffset = 0);
+
+ virtual void printFlagsImpl(StringRef Label, HexNumber Value,
+ ArrayRef<FlagEntry> Flags) {
+ startLine() << Label << " [ (" << Value << ")\n";
+ for (const auto &Flag : Flags)
+ startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n";
+ startLine() << "]\n";
+ }
+
+ virtual void printFlagsImpl(StringRef Label, HexNumber Value,
+ ArrayRef<HexNumber> Flags) {
+ startLine() << Label << " [ (" << Value << ")\n";
+ for (const auto &Flag : Flags)
+ startLine() << " " << Flag << '\n';
+ startLine() << "]\n";
+ }
+
+ template <typename T> void printListImpl(StringRef Label, const T List) {
+ startLine() << Label << ": [";
+ ListSeparator LS;
+ for (const auto &Item : List)
+ OS << LS << Item;
+ OS << "]\n";
+ }
+
+ virtual void printHexListImpl(StringRef Label,
+ const ArrayRef<HexNumber> List) {
+ startLine() << Label << ": [";
+ ListSeparator LS;
+ for (const auto &Item : List)
+ OS << LS << hex(Item);
+ OS << "]\n";
+ }
+
+ virtual void printHexImpl(StringRef Label, HexNumber Value) {
+ startLine() << Label << ": " << Value << "\n";
+ }
+
+ virtual void printHexImpl(StringRef Label, StringRef Str, HexNumber Value) {
+ startLine() << Label << ": " << Str << " (" << Value << ")\n";
+ }
+
+ virtual void printSymbolOffsetImpl(StringRef Label, StringRef Symbol,
+ HexNumber Value) {
+ startLine() << Label << ": " << Symbol << '+' << Value << '\n';
+ }
+
+ virtual void printNumberImpl(StringRef Label, StringRef Str,
+ StringRef Value) {
+ startLine() << Label << ": " << Str << " (" << Value << ")\n";
+ }
+
+ virtual void printStringEscapedImpl(StringRef Label, StringRef Value) {
+ startLine() << Label << ": ";
+ OS.write_escaped(Value);
+ OS << '\n';
+ }
+
+ void scopedBegin(char Symbol) {
+ startLine() << Symbol << '\n';
+ indent();
+ }
+
+ void scopedBegin(StringRef Label, char Symbol) {
+ startLine() << Label;
+ if (!Label.empty())
+ OS << ' ';
+ OS << Symbol << '\n';
+ indent();
+ }
+
+ void scopedEnd(char Symbol) {
+ unindent();
+ startLine() << Symbol << '\n';
+ }
+
+ raw_ostream &OS;
+ int IndentLevel = 0;
+ StringRef Prefix;
+ ScopedPrinterKind Kind;
+};
+
+template <>
+inline void
+ScopedPrinter::printHex<support::ulittle16_t>(StringRef Label,
+ support::ulittle16_t Value) {
+ startLine() << Label << ": " << hex(Value) << "\n";
+}
+
+struct DelimitedScope;
+
+class JSONScopedPrinter : public ScopedPrinter {
+private:
+ enum class Scope {
+ Array,
+ Object,
+ };
+
+ enum class ScopeKind {
+ NoAttribute,
+ Attribute,
+ NestedAttribute,
+ };
+
+ struct ScopeContext {
+ Scope Context;
+ ScopeKind Kind;
+ ScopeContext(Scope Context, ScopeKind Kind = ScopeKind::NoAttribute)
+ : Context(Context), Kind(Kind) {}
+ };
+
+ SmallVector<ScopeContext, 8> ScopeHistory;
+ json::OStream JOS;
+ std::unique_ptr<DelimitedScope> OuterScope;
+
+public:
+ JSONScopedPrinter(raw_ostream &OS, bool PrettyPrint = false,
+ std::unique_ptr<DelimitedScope> &&OuterScope =
+ std::unique_ptr<DelimitedScope>{});
+
+ static bool classof(const ScopedPrinter *SP) {
+ return SP->getKind() == ScopedPrinter::ScopedPrinterKind::JSON;
+ }
+
+ void printNumber(StringRef Label, uint64_t Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printNumber(StringRef Label, uint32_t Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printNumber(StringRef Label, uint16_t Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printNumber(StringRef Label, uint8_t Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printNumber(StringRef Label, int64_t Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printNumber(StringRef Label, int32_t Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printNumber(StringRef Label, int16_t Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printNumber(StringRef Label, int8_t Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printNumber(StringRef Label, const APSInt &Value) override {
+ JOS.attributeBegin(Label);
+ printAPSInt(Value);
+ JOS.attributeEnd();
+ }
+
+ void printBoolean(StringRef Label, bool Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void printList(StringRef Label, const ArrayRef<bool> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<std::string> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<uint64_t> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<uint32_t> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<uint16_t> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<uint8_t> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<int64_t> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<int32_t> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<int16_t> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<int8_t> List) override {
+ printListImpl(Label, List);
+ }
+
+ void printList(StringRef Label, const ArrayRef<APSInt> List) override {
+ JOS.attributeArray(Label, [&]() {
+ for (const APSInt &Item : List) {
+ printAPSInt(Item);
+ }
+ });
+ }
+
+ void printString(StringRef Value) override { JOS.value(Value); }
+
+ void printString(StringRef Label, StringRef Value) override {
+ JOS.attribute(Label, Value);
+ }
+
+ void objectBegin() override {
+ scopedBegin({Scope::Object, ScopeKind::NoAttribute});
+ }
+
+ void objectBegin(StringRef Label) override {
+ scopedBegin(Label, Scope::Object);
+ }
+
+ void objectEnd() override { scopedEnd(); }
+
+ void arrayBegin() override {
+ scopedBegin({Scope::Array, ScopeKind::NoAttribute});
+ }
+
+ void arrayBegin(StringRef Label) override {
+ scopedBegin(Label, Scope::Array);
+ }
+
+ void arrayEnd() override { scopedEnd(); }
+
+private:
+ // Output HexNumbers as decimals so that they're easier to parse.
+ uint64_t hexNumberToInt(HexNumber Hex) { return Hex.Value; }
+
+ void printAPSInt(const APSInt &Value) {
+ JOS.rawValueBegin() << Value;
+ JOS.rawValueEnd();
+ }
+
+ void printFlagsImpl(StringRef Label, HexNumber Value,
+ ArrayRef<FlagEntry> Flags) override {
+ JOS.attributeObject(Label, [&]() {
+ JOS.attribute("RawFlags", hexNumberToInt(Value));
+ JOS.attributeArray("Flags", [&]() {
+ for (const FlagEntry &Flag : Flags) {
+ JOS.objectBegin();
+ JOS.attribute("Name", Flag.Name);
+ JOS.attribute("Value", Flag.Value);
+ JOS.objectEnd();
+ }
+ });
+ });
+ }
+
+ void printFlagsImpl(StringRef Label, HexNumber Value,
+ ArrayRef<HexNumber> Flags) override {
+ JOS.attributeObject(Label, [&]() {
+ JOS.attribute("RawFlags", hexNumberToInt(Value));
+ JOS.attributeArray("Flags", [&]() {
+ for (const HexNumber &Flag : Flags) {
+ JOS.value(Flag.Value);
+ }
+ });
+ });
+ }
+
+ template <typename T> void printListImpl(StringRef Label, const T &List) {
+ JOS.attributeArray(Label, [&]() {
+ for (const auto &Item : List)
+ JOS.value(Item);
+ });
+ }
+
+ void printHexListImpl(StringRef Label,
+ const ArrayRef<HexNumber> List) override {
+ JOS.attributeArray(Label, [&]() {
+ for (const HexNumber &Item : List) {
+ JOS.value(hexNumberToInt(Item));
+ }
+ });
+ }
+
+ void printHexImpl(StringRef Label, HexNumber Value) override {
+ JOS.attribute(Label, hexNumberToInt(Value));
+ }
+
+ void printHexImpl(StringRef Label, StringRef Str, HexNumber Value) override {
+ JOS.attributeObject(Label, [&]() {
+ JOS.attribute("Value", Str);
+ JOS.attribute("RawValue", hexNumberToInt(Value));
+ });
+ }
+
+ void printSymbolOffsetImpl(StringRef Label, StringRef Symbol,
+ HexNumber Value) override {
+ JOS.attributeObject(Label, [&]() {
+ JOS.attribute("SymName", Symbol);
+ JOS.attribute("Offset", hexNumberToInt(Value));
+ });
+ }
+
+ void printNumberImpl(StringRef Label, StringRef Str,
+ StringRef Value) override {
+ JOS.attributeObject(Label, [&]() {
+ JOS.attribute("Value", Str);
+ JOS.attributeBegin("RawValue");
+ JOS.rawValueBegin() << Value;
+ JOS.rawValueEnd();
+ JOS.attributeEnd();
+ });
+ }
+
+ void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
+ bool Block, uint32_t StartOffset = 0) override {
+ JOS.attributeObject(Label, [&]() {
+ if (!Str.empty())
+ JOS.attribute("Value", Str);
+ JOS.attribute("Offset", StartOffset);
+ JOS.attributeArray("Bytes", [&]() {
+ for (uint8_t Val : Value)
+ JOS.value(Val);
+ });
+ });
+ }
+
+ void scopedBegin(ScopeContext ScopeCtx) {
+ if (ScopeCtx.Context == Scope::Object)
+ JOS.objectBegin();
+ else if (ScopeCtx.Context == Scope::Array)
+ JOS.arrayBegin();
+ ScopeHistory.push_back(ScopeCtx);
+ }
+
+ void scopedBegin(StringRef Label, Scope Ctx) {
+ ScopeKind Kind = ScopeKind::Attribute;
+ if (ScopeHistory.empty() || ScopeHistory.back().Context != Scope::Object) {
+ JOS.objectBegin();
+ Kind = ScopeKind::NestedAttribute;
+ }
+ JOS.attributeBegin(Label);
+ scopedBegin({Ctx, Kind});
+ }
+
+ void scopedEnd() {
+ ScopeContext ScopeCtx = ScopeHistory.back();
+ if (ScopeCtx.Context == Scope::Object)
+ JOS.objectEnd();
+ else if (ScopeCtx.Context == Scope::Array)
+ JOS.arrayEnd();
+ if (ScopeCtx.Kind == ScopeKind::Attribute ||
+ ScopeCtx.Kind == ScopeKind::NestedAttribute)
+ JOS.attributeEnd();
+ if (ScopeCtx.Kind == ScopeKind::NestedAttribute)
+ JOS.objectEnd();
+ ScopeHistory.pop_back();
+ }
+};
+
+struct DelimitedScope {
+ DelimitedScope(ScopedPrinter &W) : W(&W) {}
+ DelimitedScope() : W(nullptr) {}
+ virtual ~DelimitedScope() = default;
+ virtual void setPrinter(ScopedPrinter &W) = 0;
+ ScopedPrinter *W;
+};
+
+struct DictScope : DelimitedScope {
+ explicit DictScope() = default;
+ explicit DictScope(ScopedPrinter &W) : DelimitedScope(W) { W.objectBegin(); }
+
+ DictScope(ScopedPrinter &W, StringRef N) : DelimitedScope(W) {
+ W.objectBegin(N);
+ }
+
+ void setPrinter(ScopedPrinter &W) override {
+ this->W = &W;
+ W.objectBegin();
+ }
+
+ ~DictScope() {
+ if (W)
+ W->objectEnd();
+ }
+};
+
+struct ListScope : DelimitedScope {
+ explicit ListScope() = default;
+ explicit ListScope(ScopedPrinter &W) : DelimitedScope(W) { W.arrayBegin(); }
+
+ ListScope(ScopedPrinter &W, StringRef N) : DelimitedScope(W) {
+ W.arrayBegin(N);
+ }
+
+ void setPrinter(ScopedPrinter &W) override {
+ this->W = &W;
+ W.arrayBegin();
+ }
+
+ ~ListScope() {
+ if (W)
+ W->arrayEnd();
+ }
+};
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Signals.h b/contrib/libs/llvm16/include/llvm/Support/Signals.h
new file mode 100644
index 00000000000..66f3329c756
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Signals.h
@@ -0,0 +1,140 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Signals.h - Signal Handling support ----------*- 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 defines some helpful functions for dealing with the possibility of
+// unix signals occurring while your program is running.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SIGNALS_H
+#define LLVM_SUPPORT_SIGNALS_H
+
+#include <cstdint>
+#include <string>
+
+namespace llvm {
+class StringRef;
+class raw_ostream;
+
+namespace sys {
+
+ /// This function runs all the registered interrupt handlers, including the
+ /// removal of files registered by RemoveFileOnSignal.
+ void RunInterruptHandlers();
+
+ /// This function registers signal handlers to ensure that if a signal gets
+ /// delivered that the named file is removed.
+ /// Remove a file if a fatal signal occurs.
+ bool RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg = nullptr);
+
+ /// This function removes a file from the list of files to be removed on
+ /// signal delivery.
+ void DontRemoveFileOnSignal(StringRef Filename);
+
+ /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
+ /// process, print a stack trace and then exit.
+ /// Print a stack trace if a fatal signal occurs.
+ /// \param Argv0 the current binary name, used to find the symbolizer
+ /// relative to the current binary before searching $PATH; can be
+ /// StringRef(), in which case we will only search $PATH.
+ /// \param DisableCrashReporting if \c true, disable the normal crash
+ /// reporting mechanisms on the underlying operating system.
+ void PrintStackTraceOnErrorSignal(StringRef Argv0,
+ bool DisableCrashReporting = false);
+
+ /// Disable all system dialog boxes that appear when the process crashes.
+ void DisableSystemDialogsOnCrash();
+
+ /// Print the stack trace using the given \c raw_ostream object.
+ /// \param Depth refers to the number of stackframes to print. If not
+ /// specified, the entire frame is printed.
+ void PrintStackTrace(raw_ostream &OS, int Depth = 0);
+
+ // Run all registered signal handlers.
+ void RunSignalHandlers();
+
+ using SignalHandlerCallback = void (*)(void *);
+
+ /// Add a function to be called when an abort/kill signal is delivered to the
+ /// process. The handler can have a cookie passed to it to identify what
+ /// instance of the handler it is.
+ void AddSignalHandler(SignalHandlerCallback FnPtr, void *Cookie);
+
+ /// This function registers a function to be called when the user "interrupts"
+ /// the program (typically by pressing ctrl-c). When the user interrupts the
+ /// program, the specified interrupt function is called instead of the program
+ /// being killed, and the interrupt function automatically disabled.
+ ///
+ /// Note that interrupt functions are not allowed to call any non-reentrant
+ /// functions. An null interrupt function pointer disables the current
+ /// installed function. Note also that the handler may be executed on a
+ /// different thread on some platforms.
+ void SetInterruptFunction(void (*IF)());
+
+ /// Registers a function to be called when an "info" signal is delivered to
+ /// the process.
+ ///
+ /// On POSIX systems, this will be SIGUSR1; on systems that have it, SIGINFO
+ /// will also be used (typically ctrl-t).
+ ///
+ /// Note that signal handlers are not allowed to call any non-reentrant
+ /// functions. An null function pointer disables the current installed
+ /// function. Note also that the handler may be executed on a different
+ /// thread on some platforms.
+ void SetInfoSignalFunction(void (*Handler)());
+
+ /// Registers a function to be called in a "one-shot" manner when a pipe
+ /// signal is delivered to the process (i.e., on a failed write to a pipe).
+ /// After the pipe signal is handled once, the handler is unregistered.
+ ///
+ /// The LLVM signal handling code will not install any handler for the pipe
+ /// signal unless one is provided with this API (see \ref
+ /// DefaultOneShotPipeSignalHandler). This handler must be provided before
+ /// any other LLVM signal handlers are installed: the \ref InitLLVM
+ /// constructor has a flag that can simplify this setup.
+ ///
+ /// Note that the handler is not allowed to call any non-reentrant
+ /// functions. A null handler pointer disables the current installed
+ /// function. Note also that the handler may be executed on a
+ /// different thread on some platforms.
+ void SetOneShotPipeSignalFunction(void (*Handler)());
+
+ /// On Unix systems and Windows, this function exits with an "IO error" exit
+ /// code.
+ void DefaultOneShotPipeSignalHandler();
+
+#ifdef _WIN32
+ /// Windows does not support signals and this handler must be called manually.
+ void CallOneShotPipeSignalHandler();
+#endif
+
+ /// This function does the following:
+ /// - clean up any temporary files registered with RemoveFileOnSignal()
+ /// - dump the callstack from the exception context
+ /// - call any relevant interrupt/signal handlers
+ /// - create a core/mini dump of the exception context whenever possible
+ /// Context is a system-specific failure context: it is the signal type on
+ /// Unix; the ExceptionContext on Windows.
+ void CleanupOnSignal(uintptr_t Context);
+
+ void unregisterHandlers();
+} // End sys namespace
+} // End llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Signposts.h b/contrib/libs/llvm16/include/llvm/Support/Signposts.h
new file mode 100644
index 00000000000..ce4c271caa7
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Signposts.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/Signposts.h - Interval debug annotations ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Some OS's provide profilers that allow applications to provide custom
+/// annotations to the profiler. For example, on Xcode 10 and later 'signposts'
+/// can be emitted by the application and these will be rendered to the Points
+/// of Interest track on the instruments timeline.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SIGNPOSTS_H
+#define LLVM_SUPPORT_SIGNPOSTS_H
+
+#include <memory>
+
+namespace llvm {
+class SignpostEmitterImpl;
+class StringRef;
+
+/// Manages the emission of signposts into the recording method supported by
+/// the OS.
+class SignpostEmitter {
+ std::unique_ptr<SignpostEmitterImpl> Impl;
+
+public:
+ SignpostEmitter();
+ ~SignpostEmitter();
+
+ bool isEnabled() const;
+
+ /// Begin a signposted interval for a given object.
+ void startInterval(const void *O, StringRef Name);
+ /// End a signposted interval for a given object.
+ void endInterval(const void *O, StringRef Name);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_SIGNPOSTS_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SmallVectorMemoryBuffer.h b/contrib/libs/llvm16/include/llvm/Support/SmallVectorMemoryBuffer.h
new file mode 100644
index 00000000000..18d3033ee58
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SmallVectorMemoryBuffer.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- SmallVectorMemoryBuffer.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares a wrapper class to hold the memory into which an
+// object will be generated.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SMALLVECTORMEMORYBUFFER_H
+#define LLVM_SUPPORT_SMALLVECTORMEMORYBUFFER_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+/// SmallVector-backed MemoryBuffer instance.
+///
+/// This class enables efficient construction of MemoryBuffers from SmallVector
+/// instances. This is useful for MCJIT and Orc, where object files are streamed
+/// into SmallVectors, then inspected using ObjectFile (which takes a
+/// MemoryBuffer).
+class SmallVectorMemoryBuffer : public MemoryBuffer {
+public:
+ /// Construct a SmallVectorMemoryBuffer from the given SmallVector r-value.
+ SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV,
+ bool RequiresNullTerminator = true)
+ : SmallVectorMemoryBuffer(std::move(SV), "<in-memory object>",
+ RequiresNullTerminator) {}
+
+ /// Construct a named SmallVectorMemoryBuffer from the given SmallVector
+ /// r-value and StringRef.
+ SmallVectorMemoryBuffer(SmallVectorImpl<char> &&SV, StringRef Name,
+ bool RequiresNullTerminator = true)
+ : SV(std::move(SV)), BufferName(std::string(Name)) {
+ if (RequiresNullTerminator) {
+ this->SV.push_back('\0');
+ this->SV.pop_back();
+ }
+ init(this->SV.begin(), this->SV.end(), false);
+ }
+
+ // Key function.
+ ~SmallVectorMemoryBuffer() override;
+
+ StringRef getBufferIdentifier() const override { return BufferName; }
+
+ BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
+
+private:
+ SmallVector<char, 0> SV;
+ std::string BufferName;
+};
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SourceMgr.h b/contrib/libs/llvm16/include/llvm/Support/SourceMgr.h
new file mode 100644
index 00000000000..02371ce7225
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SourceMgr.h
@@ -0,0 +1,336 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- SourceMgr.h - Manager for Source Buffers & Diagnostics ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SMDiagnostic and SourceMgr classes. This
+// provides a simple substrate for diagnostics, #include handling, and other low
+// level things for simple parsers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SOURCEMGR_H
+#define LLVM_SUPPORT_SOURCEMGR_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SMLoc.h"
+#include <vector>
+
+namespace llvm {
+
+class raw_ostream;
+class SMDiagnostic;
+class SMFixIt;
+
+/// This owns the files read by a parser, handles include stacks,
+/// and handles diagnostic wrangling.
+class SourceMgr {
+public:
+ enum DiagKind {
+ DK_Error,
+ DK_Warning,
+ DK_Remark,
+ DK_Note,
+ };
+
+ /// Clients that want to handle their own diagnostics in a custom way can
+ /// register a function pointer+context as a diagnostic handler.
+ /// It gets called each time PrintMessage is invoked.
+ using DiagHandlerTy = void (*)(const SMDiagnostic &, void *Context);
+
+private:
+ struct SrcBuffer {
+ /// The memory buffer for the file.
+ std::unique_ptr<MemoryBuffer> Buffer;
+
+ /// Vector of offsets into Buffer at which there are line-endings
+ /// (lazily populated). Once populated, the '\n' that marks the end of
+ /// line number N from [1..] is at Buffer[OffsetCache[N-1]]. Since
+ /// these offsets are in sorted (ascending) order, they can be
+ /// binary-searched for the first one after any given offset (eg. an
+ /// offset corresponding to a particular SMLoc).
+ ///
+ /// Since we're storing offsets into relatively small files (often smaller
+ /// than 2^8 or 2^16 bytes), we select the offset vector element type
+ /// dynamically based on the size of Buffer.
+ mutable void *OffsetCache = nullptr;
+
+ /// Look up a given \p Ptr in in the buffer, determining which line it came
+ /// from.
+ unsigned getLineNumber(const char *Ptr) const;
+ template <typename T>
+ unsigned getLineNumberSpecialized(const char *Ptr) const;
+
+ /// Return a pointer to the first character of the specified line number or
+ /// null if the line number is invalid.
+ const char *getPointerForLineNumber(unsigned LineNo) const;
+ template <typename T>
+ const char *getPointerForLineNumberSpecialized(unsigned LineNo) const;
+
+ /// This is the location of the parent include, or null if at the top level.
+ SMLoc IncludeLoc;
+
+ SrcBuffer() = default;
+ SrcBuffer(SrcBuffer &&);
+ SrcBuffer(const SrcBuffer &) = delete;
+ SrcBuffer &operator=(const SrcBuffer &) = delete;
+ ~SrcBuffer();
+ };
+
+ /// This is all of the buffers that we are reading from.
+ std::vector<SrcBuffer> Buffers;
+
+ // This is the list of directories we should search for include files in.
+ std::vector<std::string> IncludeDirectories;
+
+ DiagHandlerTy DiagHandler = nullptr;
+ void *DiagContext = nullptr;
+
+ bool isValidBufferID(unsigned i) const { return i && i <= Buffers.size(); }
+
+public:
+ SourceMgr() = default;
+ SourceMgr(const SourceMgr &) = delete;
+ SourceMgr &operator=(const SourceMgr &) = delete;
+ SourceMgr(SourceMgr &&) = default;
+ SourceMgr &operator=(SourceMgr &&) = default;
+ ~SourceMgr() = default;
+
+ /// Return the include directories of this source manager.
+ ArrayRef<std::string> getIncludeDirs() const { return IncludeDirectories; }
+
+ void setIncludeDirs(const std::vector<std::string> &Dirs) {
+ IncludeDirectories = Dirs;
+ }
+
+ /// Specify a diagnostic handler to be invoked every time PrintMessage is
+ /// called. \p Ctx is passed into the handler when it is invoked.
+ void setDiagHandler(DiagHandlerTy DH, void *Ctx = nullptr) {
+ DiagHandler = DH;
+ DiagContext = Ctx;
+ }
+
+ DiagHandlerTy getDiagHandler() const { return DiagHandler; }
+ void *getDiagContext() const { return DiagContext; }
+
+ const SrcBuffer &getBufferInfo(unsigned i) const {
+ assert(isValidBufferID(i));
+ return Buffers[i - 1];
+ }
+
+ const MemoryBuffer *getMemoryBuffer(unsigned i) const {
+ assert(isValidBufferID(i));
+ return Buffers[i - 1].Buffer.get();
+ }
+
+ unsigned getNumBuffers() const { return Buffers.size(); }
+
+ unsigned getMainFileID() const {
+ assert(getNumBuffers());
+ return 1;
+ }
+
+ SMLoc getParentIncludeLoc(unsigned i) const {
+ assert(isValidBufferID(i));
+ return Buffers[i - 1].IncludeLoc;
+ }
+
+ /// Add a new source buffer to this source manager. This takes ownership of
+ /// the memory buffer.
+ unsigned AddNewSourceBuffer(std::unique_ptr<MemoryBuffer> F,
+ SMLoc IncludeLoc) {
+ SrcBuffer NB;
+ NB.Buffer = std::move(F);
+ NB.IncludeLoc = IncludeLoc;
+ Buffers.push_back(std::move(NB));
+ return Buffers.size();
+ }
+
+ /// Takes the source buffers from the given source manager and append them to
+ /// the current manager. `MainBufferIncludeLoc` is an optional include
+ /// location to attach to the main buffer of `SrcMgr` after it gets moved to
+ /// the current manager.
+ void takeSourceBuffersFrom(SourceMgr &SrcMgr,
+ SMLoc MainBufferIncludeLoc = SMLoc()) {
+ if (SrcMgr.Buffers.empty())
+ return;
+
+ size_t OldNumBuffers = getNumBuffers();
+ std::move(SrcMgr.Buffers.begin(), SrcMgr.Buffers.end(),
+ std::back_inserter(Buffers));
+ SrcMgr.Buffers.clear();
+ Buffers[OldNumBuffers].IncludeLoc = MainBufferIncludeLoc;
+ }
+
+ /// Search for a file with the specified name in the current directory or in
+ /// one of the IncludeDirs.
+ ///
+ /// If no file is found, this returns 0, otherwise it returns the buffer ID
+ /// of the stacked file. The full path to the included file can be found in
+ /// \p IncludedFile.
+ unsigned AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc,
+ std::string &IncludedFile);
+
+ /// Search for a file with the specified name in the current directory or in
+ /// one of the IncludeDirs, and try to open it **without** adding to the
+ /// SourceMgr. If the opened file is intended to be added to the source
+ /// manager, prefer `AddIncludeFile` instead.
+ ///
+ /// If no file is found, this returns an Error, otherwise it returns the
+ /// buffer of the stacked file. The full path to the included file can be
+ /// found in \p IncludedFile.
+ ErrorOr<std::unique_ptr<MemoryBuffer>>
+ OpenIncludeFile(const std::string &Filename, std::string &IncludedFile);
+
+ /// Return the ID of the buffer containing the specified location.
+ ///
+ /// 0 is returned if the buffer is not found.
+ unsigned FindBufferContainingLoc(SMLoc Loc) const;
+
+ /// Find the line number for the specified location in the specified file.
+ /// This is not a fast method.
+ unsigned FindLineNumber(SMLoc Loc, unsigned BufferID = 0) const {
+ return getLineAndColumn(Loc, BufferID).first;
+ }
+
+ /// Find the line and column number for the specified location in the
+ /// specified file. This is not a fast method.
+ std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc,
+ unsigned BufferID = 0) const;
+
+ /// Get a string with the \p SMLoc filename and line number
+ /// formatted in the standard style.
+ std::string getFormattedLocationNoOffset(SMLoc Loc,
+ bool IncludePath = false) const;
+
+ /// Given a line and column number in a mapped buffer, turn it into an SMLoc.
+ /// This will return a null SMLoc if the line/column location is invalid.
+ SMLoc FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,
+ unsigned ColNo);
+
+ /// Emit a message about the specified location with the specified string.
+ ///
+ /// \param ShowColors Display colored messages if output is a terminal and
+ /// the default error handler is used.
+ void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg,
+ ArrayRef<SMRange> Ranges = {},
+ ArrayRef<SMFixIt> FixIts = {},
+ bool ShowColors = true) const;
+
+ /// Emits a diagnostic to llvm::errs().
+ void PrintMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
+ ArrayRef<SMRange> Ranges = {},
+ ArrayRef<SMFixIt> FixIts = {},
+ bool ShowColors = true) const;
+
+ /// Emits a manually-constructed diagnostic to the given output stream.
+ ///
+ /// \param ShowColors Display colored messages if output is a terminal and
+ /// the default error handler is used.
+ void PrintMessage(raw_ostream &OS, const SMDiagnostic &Diagnostic,
+ bool ShowColors = true) const;
+
+ /// Return an SMDiagnostic at the specified location with the specified
+ /// string.
+ ///
+ /// \param Msg If non-null, the kind of message (e.g., "error") which is
+ /// prefixed to the message.
+ SMDiagnostic GetMessage(SMLoc Loc, DiagKind Kind, const Twine &Msg,
+ ArrayRef<SMRange> Ranges = {},
+ ArrayRef<SMFixIt> FixIts = {}) const;
+
+ /// Prints the names of included files and the line of the file they were
+ /// included from. A diagnostic handler can use this before printing its
+ /// custom formatted message.
+ ///
+ /// \param IncludeLoc The location of the include.
+ /// \param OS the raw_ostream to print on.
+ void PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const;
+};
+
+/// Represents a single fixit, a replacement of one range of text with another.
+class SMFixIt {
+ SMRange Range;
+
+ std::string Text;
+
+public:
+ SMFixIt(SMRange R, const Twine &Replacement);
+
+ SMFixIt(SMLoc Loc, const Twine &Replacement)
+ : SMFixIt(SMRange(Loc, Loc), Replacement) {}
+
+ StringRef getText() const { return Text; }
+ SMRange getRange() const { return Range; }
+
+ bool operator<(const SMFixIt &Other) const {
+ if (Range.Start.getPointer() != Other.Range.Start.getPointer())
+ return Range.Start.getPointer() < Other.Range.Start.getPointer();
+ if (Range.End.getPointer() != Other.Range.End.getPointer())
+ return Range.End.getPointer() < Other.Range.End.getPointer();
+ return Text < Other.Text;
+ }
+};
+
+/// Instances of this class encapsulate one diagnostic report, allowing
+/// printing to a raw_ostream as a caret diagnostic.
+class SMDiagnostic {
+ const SourceMgr *SM = nullptr;
+ SMLoc Loc;
+ std::string Filename;
+ int LineNo = 0;
+ int ColumnNo = 0;
+ SourceMgr::DiagKind Kind = SourceMgr::DK_Error;
+ std::string Message, LineContents;
+ std::vector<std::pair<unsigned, unsigned>> Ranges;
+ SmallVector<SMFixIt, 4> FixIts;
+
+public:
+ // Null diagnostic.
+ SMDiagnostic() = default;
+ // Diagnostic with no location (e.g. file not found, command line arg error).
+ SMDiagnostic(StringRef filename, SourceMgr::DiagKind Knd, StringRef Msg)
+ : Filename(filename), LineNo(-1), ColumnNo(-1), Kind(Knd), Message(Msg) {}
+
+ // Diagnostic with a location.
+ SMDiagnostic(const SourceMgr &sm, SMLoc L, StringRef FN, int Line, int Col,
+ SourceMgr::DiagKind Kind, StringRef Msg, StringRef LineStr,
+ ArrayRef<std::pair<unsigned, unsigned>> Ranges,
+ ArrayRef<SMFixIt> FixIts = {});
+
+ const SourceMgr *getSourceMgr() const { return SM; }
+ SMLoc getLoc() const { return Loc; }
+ StringRef getFilename() const { return Filename; }
+ int getLineNo() const { return LineNo; }
+ int getColumnNo() const { return ColumnNo; }
+ SourceMgr::DiagKind getKind() const { return Kind; }
+ StringRef getMessage() const { return Message; }
+ StringRef getLineContents() const { return LineContents; }
+ ArrayRef<std::pair<unsigned, unsigned>> getRanges() const { return Ranges; }
+
+ void addFixIt(const SMFixIt &Hint) { FixIts.push_back(Hint); }
+
+ ArrayRef<SMFixIt> getFixIts() const { return FixIts; }
+
+ void print(const char *ProgName, raw_ostream &S, bool ShowColors = true,
+ bool ShowKindLabel = true) const;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_SOURCEMGR_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SpecialCaseList.h b/contrib/libs/llvm16/include/llvm/Support/SpecialCaseList.h
new file mode 100644
index 00000000000..515f7ba0f2a
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SpecialCaseList.h
@@ -0,0 +1,170 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- SpecialCaseList.h - special case list for sanitizers ----*- 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 is a utility class used to parse user-provided text files with
+// "special case lists" for code sanitizers. Such files are used to
+// define an "ABI list" for DataFlowSanitizer and allow/exclusion lists for
+// sanitizers like AddressSanitizer or UndefinedBehaviorSanitizer.
+//
+// Empty lines and lines starting with "#" are ignored. Sections are defined
+// using a '[section_name]' header and can be used to specify sanitizers the
+// entries below it apply to. Section names are regular expressions, and
+// entries without a section header match all sections (e.g. an '[*]' header
+// is assumed.)
+// The remaining lines should have the form:
+// prefix:wildcard_expression[=category]
+// If category is not specified, it is assumed to be empty string.
+// Definitions of "prefix" and "category" are sanitizer-specific. For example,
+// sanitizer exclusion support prefixes "src", "mainfile", "fun" and "global".
+// Wildcard expressions define, respectively, source files, main files,
+// functions or globals which shouldn't be instrumented.
+// Examples of categories:
+// "functional": used in DFSan to list functions with pure functional
+// semantics.
+// "init": used in ASan exclusion list to disable initialization-order bugs
+// detection for certain globals or source files.
+// Full special case list file example:
+// ---
+// [address]
+// # Excluded items:
+// fun:*_ZN4base6subtle*
+// global:*global_with_bad_access_or_initialization*
+// global:*global_with_initialization_issues*=init
+// type:*Namespace::ClassName*=init
+// src:file_with_tricky_code.cc
+// src:ignore-global-initializers-issues.cc=init
+// mainfile:main_file.cc
+//
+// [dataflow]
+// # Functions with pure functional semantics:
+// fun:cos=functional
+// fun:sin=functional
+// ---
+// Note that the wild card is in fact an llvm::Regex, but * is automatically
+// replaced with .*
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SPECIALCASELIST_H
+#define LLVM_SUPPORT_SPECIALCASELIST_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/TrigramIndex.h"
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace llvm {
+class MemoryBuffer;
+class StringRef;
+
+namespace vfs {
+class FileSystem;
+}
+
+class SpecialCaseList {
+public:
+ /// Parses the special case list entries from files. On failure, returns
+ /// 0 and writes an error message to string.
+ static std::unique_ptr<SpecialCaseList>
+ create(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &FS,
+ std::string &Error);
+ /// Parses the special case list from a memory buffer. On failure, returns
+ /// 0 and writes an error message to string.
+ static std::unique_ptr<SpecialCaseList> create(const MemoryBuffer *MB,
+ std::string &Error);
+ /// Parses the special case list entries from files. On failure, reports a
+ /// fatal error.
+ static std::unique_ptr<SpecialCaseList>
+ createOrDie(const std::vector<std::string> &Paths, llvm::vfs::FileSystem &FS);
+
+ ~SpecialCaseList();
+
+ /// Returns true, if special case list contains a line
+ /// \code
+ /// @Prefix:<E>=@Category
+ /// \endcode
+ /// where @Query satisfies wildcard expression <E> in a given @Section.
+ bool inSection(StringRef Section, StringRef Prefix, StringRef Query,
+ StringRef Category = StringRef()) const;
+
+ /// Returns the line number corresponding to the special case list entry if
+ /// the special case list contains a line
+ /// \code
+ /// @Prefix:<E>=@Category
+ /// \endcode
+ /// where @Query satisfies wildcard expression <E> in a given @Section.
+ /// Returns zero if there is no exclusion entry corresponding to this
+ /// expression.
+ unsigned inSectionBlame(StringRef Section, StringRef Prefix, StringRef Query,
+ StringRef Category = StringRef()) const;
+
+protected:
+ // Implementations of the create*() functions that can also be used by derived
+ // classes.
+ bool createInternal(const std::vector<std::string> &Paths,
+ vfs::FileSystem &VFS, std::string &Error);
+ bool createInternal(const MemoryBuffer *MB, std::string &Error);
+
+ SpecialCaseList() = default;
+ SpecialCaseList(SpecialCaseList const &) = delete;
+ SpecialCaseList &operator=(SpecialCaseList const &) = delete;
+
+ /// Represents a set of regular expressions. Regular expressions which are
+ /// "literal" (i.e. no regex metacharacters) are stored in Strings. The
+ /// reason for doing so is efficiency; StringMap is much faster at matching
+ /// literal strings than Regex.
+ class Matcher {
+ public:
+ bool insert(std::string Regexp, unsigned LineNumber, std::string &REError);
+ // Returns the line number in the source file that this query matches to.
+ // Returns zero if no match is found.
+ unsigned match(StringRef Query) const;
+
+ private:
+ StringMap<unsigned> Strings;
+ TrigramIndex Trigrams;
+ std::vector<std::pair<std::unique_ptr<Regex>, unsigned>> RegExes;
+ };
+
+ using SectionEntries = StringMap<StringMap<Matcher>>;
+
+ struct Section {
+ Section(std::unique_ptr<Matcher> M) : SectionMatcher(std::move(M)){};
+
+ std::unique_ptr<Matcher> SectionMatcher;
+ SectionEntries Entries;
+ };
+
+ std::vector<Section> Sections;
+
+ /// Parses just-constructed SpecialCaseList entries from a memory buffer.
+ bool parse(const MemoryBuffer *MB, StringMap<size_t> &SectionsMap,
+ std::string &Error);
+
+ // Helper method for derived classes to search by Prefix, Query, and Category
+ // once they have already resolved a section entry.
+ unsigned inSectionBlame(const SectionEntries &Entries, StringRef Prefix,
+ StringRef Query, StringRef Category) const;
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_SPECIALCASELIST_H
+
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/StringSaver.h b/contrib/libs/llvm16/include/llvm/Support/StringSaver.h
new file mode 100644
index 00000000000..3f0b26aab41
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/StringSaver.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/StringSaver.h -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_STRINGSAVER_H
+#define LLVM_SUPPORT_STRINGSAVER_H
+
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Allocator.h"
+
+namespace llvm {
+
+/// Saves strings in the provided stable storage and returns a
+/// StringRef with a stable character pointer.
+class StringSaver final {
+ BumpPtrAllocator &Alloc;
+
+public:
+ StringSaver(BumpPtrAllocator &Alloc) : Alloc(Alloc) {}
+
+ BumpPtrAllocator &getAllocator() const { return Alloc; }
+
+ // All returned strings are null-terminated: *save(S).end() == 0.
+ StringRef save(const char *S) { return save(StringRef(S)); }
+ StringRef save(StringRef S);
+ StringRef save(const Twine &S) { return save(StringRef(S.str())); }
+ StringRef save(const std::string &S) { return save(StringRef(S)); }
+};
+
+/// Saves strings in the provided stable storage and returns a StringRef with a
+/// stable character pointer. Saving the same string yields the same StringRef.
+///
+/// Compared to StringSaver, it does more work but avoids saving the same string
+/// multiple times.
+///
+/// Compared to StringPool, it performs fewer allocations but doesn't support
+/// refcounting/deletion.
+class UniqueStringSaver final {
+ StringSaver Strings;
+ llvm::DenseSet<llvm::StringRef> Unique;
+
+public:
+ UniqueStringSaver(BumpPtrAllocator &Alloc) : Strings(Alloc) {}
+
+ // All returned strings are null-terminated: *save(S).end() == 0.
+ StringRef save(const char *S) { return save(StringRef(S)); }
+ StringRef save(StringRef S);
+ StringRef save(const Twine &S) { return save(StringRef(S.str())); }
+ StringRef save(const std::string &S) { return save(StringRef(S)); }
+};
+
+}
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SuffixTree.h b/contrib/libs/llvm16/include/llvm/Support/SuffixTree.h
new file mode 100644
index 00000000000..1b0da216bfc
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SuffixTree.h
@@ -0,0 +1,361 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/ADT/SuffixTree.h - Tree for substrings --------------*- 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 defines the Suffix Tree class and Suffix Tree Node struct.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_SUFFIXTREE_H
+#define LLVM_SUPPORT_SUFFIXTREE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/Allocator.h"
+#include <vector>
+
+namespace llvm {
+
+/// Represents an undefined index in the suffix tree.
+const unsigned EmptyIdx = -1;
+
+/// A node in a suffix tree which represents a substring or suffix.
+///
+/// Each node has either no children or at least two children, with the root
+/// being a exception in the empty tree.
+///
+/// Children are represented as a map between unsigned integers and nodes. If
+/// a node N has a child M on unsigned integer k, then the mapping represented
+/// by N is a proper prefix of the mapping represented by M. Note that this,
+/// although similar to a trie is somewhat different: each node stores a full
+/// substring of the full mapping rather than a single character state.
+///
+/// Each internal node contains a pointer to the internal node representing
+/// the same string, but with the first character chopped off. This is stored
+/// in \p Link. Each leaf node stores the start index of its respective
+/// suffix in \p SuffixIdx.
+struct SuffixTreeNode {
+
+ /// The children of this node.
+ ///
+ /// A child existing on an unsigned integer implies that from the mapping
+ /// represented by the current node, there is a way to reach another
+ /// mapping by tacking that character on the end of the current string.
+ llvm::DenseMap<unsigned, SuffixTreeNode *> Children;
+
+ /// The start index of this node's substring in the main string.
+ unsigned StartIdx = EmptyIdx;
+
+ /// The end index of this node's substring in the main string.
+ ///
+ /// Every leaf node must have its \p EndIdx incremented at the end of every
+ /// step in the construction algorithm. To avoid having to update O(N)
+ /// nodes individually at the end of every step, the end index is stored
+ /// as a pointer.
+ unsigned *EndIdx = nullptr;
+
+ /// For leaves, the start index of the suffix represented by this node.
+ ///
+ /// For all other nodes, this is ignored.
+ unsigned SuffixIdx = EmptyIdx;
+
+ /// For internal nodes, a pointer to the internal node representing
+ /// the same sequence with the first character chopped off.
+ ///
+ /// This acts as a shortcut in Ukkonen's algorithm. One of the things that
+ /// Ukkonen's algorithm does to achieve linear-time construction is
+ /// keep track of which node the next insert should be at. This makes each
+ /// insert O(1), and there are a total of O(N) inserts. The suffix link
+ /// helps with inserting children of internal nodes.
+ ///
+ /// Say we add a child to an internal node with associated mapping S. The
+ /// next insertion must be at the node representing S - its first character.
+ /// This is given by the way that we iteratively build the tree in Ukkonen's
+ /// algorithm. The main idea is to look at the suffixes of each prefix in the
+ /// string, starting with the longest suffix of the prefix, and ending with
+ /// the shortest. Therefore, if we keep pointers between such nodes, we can
+ /// move to the next insertion point in O(1) time. If we don't, then we'd
+ /// have to query from the root, which takes O(N) time. This would make the
+ /// construction algorithm O(N^2) rather than O(N).
+ SuffixTreeNode *Link = nullptr;
+
+ /// The length of the string formed by concatenating the edge labels from the
+ /// root to this node.
+ unsigned ConcatLen = 0;
+
+ /// Returns true if this node is a leaf.
+ bool isLeaf() const { return SuffixIdx != EmptyIdx; }
+
+ /// Returns true if this node is the root of its owning \p SuffixTree.
+ bool isRoot() const { return StartIdx == EmptyIdx; }
+
+ /// Return the number of elements in the substring associated with this node.
+ size_t size() const {
+
+ // Is it the root? If so, it's the empty string so return 0.
+ if (isRoot())
+ return 0;
+
+ assert(*EndIdx != EmptyIdx && "EndIdx is undefined!");
+
+ // Size = the number of elements in the string.
+ // For example, [0 1 2 3] has length 4, not 3. 3-0 = 3, so we have 3-0+1.
+ return *EndIdx - StartIdx + 1;
+ }
+
+ SuffixTreeNode(unsigned StartIdx, unsigned *EndIdx, SuffixTreeNode *Link)
+ : StartIdx(StartIdx), EndIdx(EndIdx), Link(Link) {}
+
+ SuffixTreeNode() = default;
+};
+
+/// A data structure for fast substring queries.
+///
+/// Suffix trees represent the suffixes of their input strings in their leaves.
+/// A suffix tree is a type of compressed trie structure where each node
+/// represents an entire substring rather than a single character. Each leaf
+/// of the tree is a suffix.
+///
+/// A suffix tree can be seen as a type of state machine where each state is a
+/// substring of the full string. The tree is structured so that, for a string
+/// of length N, there are exactly N leaves in the tree. This structure allows
+/// us to quickly find repeated substrings of the input string.
+///
+/// In this implementation, a "string" is a vector of unsigned integers.
+/// These integers may result from hashing some data type. A suffix tree can
+/// contain 1 or many strings, which can then be queried as one large string.
+///
+/// The suffix tree is implemented using Ukkonen's algorithm for linear-time
+/// suffix tree construction. Ukkonen's algorithm is explained in more detail
+/// in the paper by Esko Ukkonen "On-line construction of suffix trees. The
+/// paper is available at
+///
+/// https://www.cs.helsinki.fi/u/ukkonen/SuffixT1withFigs.pdf
+class SuffixTree {
+public:
+ /// Each element is an integer representing an instruction in the module.
+ llvm::ArrayRef<unsigned> Str;
+
+ /// A repeated substring in the tree.
+ struct RepeatedSubstring {
+ /// The length of the string.
+ unsigned Length;
+
+ /// The start indices of each occurrence.
+ std::vector<unsigned> StartIndices;
+ };
+
+private:
+ /// Maintains each node in the tree.
+ llvm::SpecificBumpPtrAllocator<SuffixTreeNode> NodeAllocator;
+
+ /// The root of the suffix tree.
+ ///
+ /// The root represents the empty string. It is maintained by the
+ /// \p NodeAllocator like every other node in the tree.
+ SuffixTreeNode *Root = nullptr;
+
+ /// Maintains the end indices of the internal nodes in the tree.
+ ///
+ /// Each internal node is guaranteed to never have its end index change
+ /// during the construction algorithm; however, leaves must be updated at
+ /// every step. Therefore, we need to store leaf end indices by reference
+ /// to avoid updating O(N) leaves at every step of construction. Thus,
+ /// every internal node must be allocated its own end index.
+ llvm::BumpPtrAllocator InternalEndIdxAllocator;
+
+ /// The end index of each leaf in the tree.
+ unsigned LeafEndIdx = -1;
+
+ /// Helper struct which keeps track of the next insertion point in
+ /// Ukkonen's algorithm.
+ struct ActiveState {
+ /// The next node to insert at.
+ SuffixTreeNode *Node = nullptr;
+
+ /// The index of the first character in the substring currently being added.
+ unsigned Idx = EmptyIdx;
+
+ /// The length of the substring we have to add at the current step.
+ unsigned Len = 0;
+ };
+
+ /// The point the next insertion will take place at in the
+ /// construction algorithm.
+ ActiveState Active;
+
+ /// Allocate a leaf node and add it to the tree.
+ ///
+ /// \param Parent The parent of this node.
+ /// \param StartIdx The start index of this node's associated string.
+ /// \param Edge The label on the edge leaving \p Parent to this node.
+ ///
+ /// \returns A pointer to the allocated leaf node.
+ SuffixTreeNode *insertLeaf(SuffixTreeNode &Parent, unsigned StartIdx,
+ unsigned Edge);
+
+ /// Allocate an internal node and add it to the tree.
+ ///
+ /// \param Parent The parent of this node. Only null when allocating the root.
+ /// \param StartIdx The start index of this node's associated string.
+ /// \param EndIdx The end index of this node's associated string.
+ /// \param Edge The label on the edge leaving \p Parent to this node.
+ ///
+ /// \returns A pointer to the allocated internal node.
+ SuffixTreeNode *insertInternalNode(SuffixTreeNode *Parent, unsigned StartIdx,
+ unsigned EndIdx, unsigned Edge);
+
+ /// Set the suffix indices of the leaves to the start indices of their
+ /// respective suffixes.
+ void setSuffixIndices();
+
+ /// Construct the suffix tree for the prefix of the input ending at
+ /// \p EndIdx.
+ ///
+ /// Used to construct the full suffix tree iteratively. At the end of each
+ /// step, the constructed suffix tree is either a valid suffix tree, or a
+ /// suffix tree with implicit suffixes. At the end of the final step, the
+ /// suffix tree is a valid tree.
+ ///
+ /// \param EndIdx The end index of the current prefix in the main string.
+ /// \param SuffixesToAdd The number of suffixes that must be added
+ /// to complete the suffix tree at the current phase.
+ ///
+ /// \returns The number of suffixes that have not been added at the end of
+ /// this step.
+ unsigned extend(unsigned EndIdx, unsigned SuffixesToAdd);
+
+public:
+ /// Construct a suffix tree from a sequence of unsigned integers.
+ ///
+ /// \param Str The string to construct the suffix tree for.
+ SuffixTree(const std::vector<unsigned> &Str);
+
+ /// Iterator for finding all repeated substrings in the suffix tree.
+ struct RepeatedSubstringIterator {
+ private:
+ /// The current node we're visiting.
+ SuffixTreeNode *N = nullptr;
+
+ /// The repeated substring associated with this node.
+ RepeatedSubstring RS;
+
+ /// The nodes left to visit.
+ std::vector<SuffixTreeNode *> ToVisit;
+
+ /// The minimum length of a repeated substring to find.
+ /// Since we're outlining, we want at least two instructions in the range.
+ /// FIXME: This may not be true for targets like X86 which support many
+ /// instruction lengths.
+ const unsigned MinLength = 2;
+
+ /// Move the iterator to the next repeated substring.
+ void advance() {
+ // Clear the current state. If we're at the end of the range, then this
+ // is the state we want to be in.
+ RS = RepeatedSubstring();
+ N = nullptr;
+
+ // Each leaf node represents a repeat of a string.
+ std::vector<SuffixTreeNode *> LeafChildren;
+
+ // Continue visiting nodes until we find one which repeats more than once.
+ while (!ToVisit.empty()) {
+ SuffixTreeNode *Curr = ToVisit.back();
+ ToVisit.pop_back();
+ LeafChildren.clear();
+
+ // Keep track of the length of the string associated with the node. If
+ // it's too short, we'll quit.
+ unsigned Length = Curr->ConcatLen;
+
+ // Iterate over each child, saving internal nodes for visiting, and
+ // leaf nodes in LeafChildren. Internal nodes represent individual
+ // strings, which may repeat.
+ for (auto &ChildPair : Curr->Children) {
+ // Save all of this node's children for processing.
+ if (!ChildPair.second->isLeaf())
+ ToVisit.push_back(ChildPair.second);
+
+ // It's not an internal node, so it must be a leaf. If we have a
+ // long enough string, then save the leaf children.
+ else if (Length >= MinLength)
+ LeafChildren.push_back(ChildPair.second);
+ }
+
+ // The root never represents a repeated substring. If we're looking at
+ // that, then skip it.
+ if (Curr->isRoot())
+ continue;
+
+ // Do we have any repeated substrings?
+ if (LeafChildren.size() >= 2) {
+ // Yes. Update the state to reflect this, and then bail out.
+ N = Curr;
+ RS.Length = Length;
+ for (SuffixTreeNode *Leaf : LeafChildren)
+ RS.StartIndices.push_back(Leaf->SuffixIdx);
+ break;
+ }
+ }
+
+ // At this point, either NewRS is an empty RepeatedSubstring, or it was
+ // set in the above loop. Similarly, N is either nullptr, or the node
+ // associated with NewRS.
+ }
+
+ public:
+ /// Return the current repeated substring.
+ RepeatedSubstring &operator*() { return RS; }
+
+ RepeatedSubstringIterator &operator++() {
+ advance();
+ return *this;
+ }
+
+ RepeatedSubstringIterator operator++(int I) {
+ RepeatedSubstringIterator It(*this);
+ advance();
+ return It;
+ }
+
+ bool operator==(const RepeatedSubstringIterator &Other) const {
+ return N == Other.N;
+ }
+ bool operator!=(const RepeatedSubstringIterator &Other) const {
+ return !(*this == Other);
+ }
+
+ RepeatedSubstringIterator(SuffixTreeNode *N) : N(N) {
+ // Do we have a non-null node?
+ if (N) {
+ // Yes. At the first step, we need to visit all of N's children.
+ // Note: This means that we visit N last.
+ ToVisit.push_back(N);
+ advance();
+ }
+ }
+ };
+
+ typedef RepeatedSubstringIterator iterator;
+ iterator begin() { return iterator(Root); }
+ iterator end() { return iterator(nullptr); }
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_SUFFIXTREE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SwapByteOrder.h b/contrib/libs/llvm16/include/llvm/Support/SwapByteOrder.h
new file mode 100644
index 00000000000..085df5b4168
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SwapByteOrder.h
@@ -0,0 +1,130 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares generic and optimized functions to swap the byte order of
+// an integral type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SWAPBYTEORDER_H
+#define LLVM_SUPPORT_SWAPBYTEORDER_H
+
+#include "llvm/ADT/bit.h"
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
+ defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+#include <endian.h>
+#elif defined(_AIX)
+#include <sys/machine.h>
+#elif defined(__sun)
+/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
+#include <sys/types.h>
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#if defined(_BIG_ENDIAN)
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#elif defined(__MVS__)
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#if !defined(BYTE_ORDER) && !defined(_WIN32)
+#include <machine/endian.h>
+#endif
+#endif
+
+namespace llvm {
+
+/// ByteSwap_16 - This function returns a byte-swapped representation of
+/// the 16-bit argument.
+inline uint16_t ByteSwap_16(uint16_t value) { return llvm::byteswap(value); }
+
+/// This function returns a byte-swapped representation of the 32-bit argument.
+inline uint32_t ByteSwap_32(uint32_t value) { return llvm::byteswap(value); }
+
+/// This function returns a byte-swapped representation of the 64-bit argument.
+inline uint64_t ByteSwap_64(uint64_t value) { return llvm::byteswap(value); }
+
+namespace sys {
+
+#if defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
+constexpr bool IsBigEndianHost = true;
+#else
+constexpr bool IsBigEndianHost = false;
+#endif
+
+static const bool IsLittleEndianHost = !IsBigEndianHost;
+
+inline unsigned char getSwappedBytes(unsigned char C) { return llvm::byteswap(C); }
+inline signed char getSwappedBytes( signed char C) { return llvm::byteswap(C); }
+inline char getSwappedBytes( char C) { return llvm::byteswap(C); }
+
+inline unsigned short getSwappedBytes(unsigned short C) { return llvm::byteswap(C); }
+inline signed short getSwappedBytes( signed short C) { return llvm::byteswap(C); }
+
+inline unsigned int getSwappedBytes(unsigned int C) { return llvm::byteswap(C); }
+inline signed int getSwappedBytes( signed int C) { return llvm::byteswap(C); }
+
+inline unsigned long getSwappedBytes(unsigned long C) { return llvm::byteswap(C); }
+inline signed long getSwappedBytes( signed long C) { return llvm::byteswap(C); }
+
+inline unsigned long long getSwappedBytes(unsigned long long C) { return llvm::byteswap(C); }
+inline signed long long getSwappedBytes( signed long long C) { return llvm::byteswap(C); }
+
+inline float getSwappedBytes(float C) {
+ union {
+ uint32_t i;
+ float f;
+ } in, out;
+ in.f = C;
+ out.i = llvm::byteswap(in.i);
+ return out.f;
+}
+
+inline double getSwappedBytes(double C) {
+ union {
+ uint64_t i;
+ double d;
+ } in, out;
+ in.d = C;
+ out.i = llvm::byteswap(in.i);
+ return out.d;
+}
+
+template <typename T>
+inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) {
+ return static_cast<T>(
+ llvm::byteswap(static_cast<std::underlying_type_t<T>>(C)));
+}
+
+template<typename T>
+inline void swapByteOrder(T &Value) {
+ Value = getSwappedBytes(Value);
+}
+
+} // end namespace sys
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SymbolRemappingReader.h b/contrib/libs/llvm16/include/llvm/Support/SymbolRemappingReader.h
new file mode 100644
index 00000000000..8d87e6e6abc
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SymbolRemappingReader.h
@@ -0,0 +1,144 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- SymbolRemappingReader.h - Read symbol remapping file -----*- 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 definitions needed for reading and applying symbol
+// remapping files.
+//
+// Support is provided only for the Itanium C++ name mangling scheme for now.
+//
+// NOTE: If you are making changes to this file format, please remember
+// to document them in the Clang documentation at
+// tools/clang/docs/UsersManual.rst.
+//
+// File format
+// -----------
+//
+// The symbol remappings are written as an ASCII text file. Blank lines and
+// lines starting with a # are ignored. All other lines specify a kind of
+// mangled name fragment, along with two fragments of that kind that should
+// be treated as equivalent, separated by spaces.
+//
+// See http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling for a
+// description of the Itanium name mangling scheme.
+//
+// The accepted fragment kinds are:
+//
+// * name A <name>, such as 6foobar or St3__1
+// * type A <type>, such as Ss or N4llvm9StringRefE
+// * encoding An <encoding> (a complete mangling without the leading _Z)
+//
+// For example:
+//
+// # Ignore int / long differences to treat symbols from 32-bit and 64-bit
+// # builds with differing size_t / ptrdiff_t / intptr_t as equivalent.
+// type i l
+// type j m
+//
+// # Ignore differences between libc++ and libstdc++, and between libstdc++'s
+// # C++98 and C++11 ABIs.
+// name 3std St3__1
+// name 3std St7__cxx11
+//
+// # Remap a function overload to a specialization of a template (including
+// # any local symbols declared within it).
+// encoding N2NS1fEi N2NS1fIiEEvT_
+//
+// # Substitutions must be remapped separately from namespace 'std' for now.
+// name Sa NSt3__19allocatorE
+// name Sb NSt3__112basic_stringE
+// type Ss NSt3__112basic_stringIcSt11char_traitsIcESaE
+// # ...
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SYMBOLREMAPPINGREADER_H
+#define LLVM_SUPPORT_SYMBOLREMAPPINGREADER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ItaniumManglingCanonicalizer.h"
+
+namespace llvm {
+
+class MemoryBuffer;
+
+class SymbolRemappingParseError : public ErrorInfo<SymbolRemappingParseError> {
+public:
+ SymbolRemappingParseError(StringRef File, int64_t Line, const Twine &Message)
+ : File(File), Line(Line), Message(Message.str()) {}
+
+ void log(llvm::raw_ostream &OS) const override {
+ OS << File << ':' << Line << ": " << Message;
+ }
+ std::error_code convertToErrorCode() const override {
+ return llvm::inconvertibleErrorCode();
+ }
+
+ StringRef getFileName() const { return File; }
+ int64_t getLineNum() const { return Line; }
+ StringRef getMessage() const { return Message; }
+
+ static char ID;
+
+private:
+ std::string File;
+ int64_t Line;
+ std::string Message;
+};
+
+/// Reader for symbol remapping files.
+///
+/// Remaps the symbol names in profile data to match those in the program
+/// according to a set of rules specified in a given file.
+class SymbolRemappingReader {
+public:
+ /// Read remappings from the given buffer, which must live as long as
+ /// the remapper.
+ Error read(MemoryBuffer &B);
+
+ /// A Key represents an equivalence class of symbol names.
+ using Key = uintptr_t;
+
+ /// Construct a key for the given symbol, or return an existing one if an
+ /// equivalent name has already been inserted. The symbol name must live
+ /// as long as the remapper.
+ ///
+ /// The result will be Key() if the name cannot be remapped (typically
+ /// because it is not a valid mangled name).
+ Key insert(StringRef FunctionName) {
+ return Canonicalizer.canonicalize(FunctionName);
+ }
+
+ /// Map the given symbol name into the key for the corresponding equivalence
+ /// class.
+ ///
+ /// The result will typically be Key() if no equivalent symbol has been
+ /// inserted, but this is not guaranteed: a Key different from all keys ever
+ /// returned by \c insert may be returned instead.
+ Key lookup(StringRef FunctionName) {
+ return Canonicalizer.lookup(FunctionName);
+ }
+
+private:
+ ItaniumManglingCanonicalizer Canonicalizer;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_SYMBOLREMAPPINGREADER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/SystemUtils.h b/contrib/libs/llvm16/include/llvm/Support/SystemUtils.h
new file mode 100644
index 00000000000..7b5e35b30f0
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/SystemUtils.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- SystemUtils.h - Utilities to do low-level system stuff ---*- 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 functions used to do a variety of low-level, often
+// system-specific, tasks.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_SYSTEMUTILS_H
+#define LLVM_SUPPORT_SYSTEMUTILS_H
+
+namespace llvm {
+class raw_ostream;
+
+/// Determine if the raw_ostream provided is connected to a terminal. If so,
+/// generate a warning message to errs() advising against display of bitcode
+/// and return true. Otherwise just return false.
+/// Check for output written to a console
+bool CheckBitcodeOutputToConsole(
+ raw_ostream &stream_to_check ///< The stream to be checked
+);
+
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/TarWriter.h b/contrib/libs/llvm16/include/llvm/Support/TarWriter.h
new file mode 100644
index 00000000000..ace31bef832
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/TarWriter.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/TarWriter.h - Tar archive file creator -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TARWRITER_H
+#define LLVM_SUPPORT_TARWRITER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+class TarWriter {
+public:
+ static Expected<std::unique_ptr<TarWriter>> create(StringRef OutputPath,
+ StringRef BaseDir);
+
+ void append(StringRef Path, StringRef Data);
+
+private:
+ TarWriter(int FD, StringRef BaseDir);
+ raw_fd_ostream OS;
+ std::string BaseDir;
+ StringSet<> Files;
+};
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/TargetOpcodes.def b/contrib/libs/llvm16/include/llvm/Support/TargetOpcodes.def
new file mode 100644
index 00000000000..d3fe1eec38d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/TargetOpcodes.def
@@ -0,0 +1,808 @@
+//===-- llvm/Support/TargetOpcodes.def - Target Indep Opcodes ---*- 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 defines the target independent instruction opcodes.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+/// HANDLE_TARGET_OPCODE defines an opcode and its associated enum value.
+///
+#ifndef HANDLE_TARGET_OPCODE
+#define HANDLE_TARGET_OPCODE(OPC, NUM)
+#endif
+
+/// HANDLE_TARGET_OPCODE_MARKER defines an alternative identifier for an opcode.
+///
+#ifndef HANDLE_TARGET_OPCODE_MARKER
+#define HANDLE_TARGET_OPCODE_MARKER(IDENT, OPC)
+#endif
+
+/// Every instruction defined here must also appear in Target.td.
+///
+HANDLE_TARGET_OPCODE(PHI)
+HANDLE_TARGET_OPCODE(INLINEASM)
+HANDLE_TARGET_OPCODE(INLINEASM_BR)
+HANDLE_TARGET_OPCODE(CFI_INSTRUCTION)
+HANDLE_TARGET_OPCODE(EH_LABEL)
+HANDLE_TARGET_OPCODE(GC_LABEL)
+HANDLE_TARGET_OPCODE(ANNOTATION_LABEL)
+
+/// KILL - This instruction is a noop that is used only to adjust the
+/// liveness of registers. This can be useful when dealing with
+/// sub-registers.
+HANDLE_TARGET_OPCODE(KILL)
+
+/// EXTRACT_SUBREG - This instruction takes two operands: a register
+/// that has subregisters, and a subregister index. It returns the
+/// extracted subregister value. This is commonly used to implement
+/// truncation operations on target architectures which support it.
+HANDLE_TARGET_OPCODE(EXTRACT_SUBREG)
+
+/// INSERT_SUBREG - This instruction takes three operands: a register that
+/// has subregisters, a register providing an insert value, and a
+/// subregister index. It returns the value of the first register with the
+/// value of the second register inserted. The first register is often
+/// defined by an IMPLICIT_DEF, because it is commonly used to implement
+/// anyext operations on target architectures which support it.
+HANDLE_TARGET_OPCODE(INSERT_SUBREG)
+
+/// IMPLICIT_DEF - This is the MachineInstr-level equivalent of undef.
+HANDLE_TARGET_OPCODE(IMPLICIT_DEF)
+
+/// SUBREG_TO_REG - Assert the value of bits in a super register.
+/// The result of this instruction is the value of the second operand inserted
+/// into the subregister specified by the third operand. All other bits are
+/// assumed to be equal to the bits in the immediate integer constant in the
+/// first operand. This instruction just communicates information; No code
+/// should be generated.
+/// This is typically used after an instruction where the write to a subregister
+/// implicitly cleared the bits in the super registers.
+HANDLE_TARGET_OPCODE(SUBREG_TO_REG)
+
+/// COPY_TO_REGCLASS - This instruction is a placeholder for a plain
+/// register-to-register copy into a specific register class. This is only
+/// used between instruction selection and MachineInstr creation, before
+/// virtual registers have been created for all the instructions, and it's
+/// only needed in cases where the register classes implied by the
+/// instructions are insufficient. It is emitted as a COPY MachineInstr.
+ HANDLE_TARGET_OPCODE(COPY_TO_REGCLASS)
+
+/// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic
+HANDLE_TARGET_OPCODE(DBG_VALUE)
+
+/// DBG_VALUE - a mapping of the llvm.dbg.value intrinsic with a variadic
+/// list of locations
+HANDLE_TARGET_OPCODE(DBG_VALUE_LIST)
+
+/// DBG_INSTR_REF - A mapping of llvm.dbg.value referring to the instruction
+/// that defines the value, rather than a virtual register.
+HANDLE_TARGET_OPCODE(DBG_INSTR_REF)
+
+/// DBG_PHI - remainder of a PHI, identifies a program point where values
+/// merge under control flow.
+HANDLE_TARGET_OPCODE(DBG_PHI)
+
+/// DBG_LABEL - a mapping of the llvm.dbg.label intrinsic
+HANDLE_TARGET_OPCODE(DBG_LABEL)
+
+/// REG_SEQUENCE - This variadic instruction is used to form a register that
+/// represents a consecutive sequence of sub-registers. It's used as a
+/// register coalescing / allocation aid and must be eliminated before code
+/// emission.
+// In SDNode form, the first operand encodes the register class created by
+// the REG_SEQUENCE, while each subsequent pair names a vreg + subreg index
+// pair. Once it has been lowered to a MachineInstr, the regclass operand
+// is no longer present.
+/// e.g. v1027 = REG_SEQUENCE v1024, 3, v1025, 4, v1026, 5
+/// After register coalescing references of v1024 should be replace with
+/// v1027:3, v1025 with v1027:4, etc.
+ HANDLE_TARGET_OPCODE(REG_SEQUENCE)
+
+/// COPY - Target-independent register copy. This instruction can also be
+/// used to copy between subregisters of virtual registers.
+ HANDLE_TARGET_OPCODE(COPY)
+
+/// BUNDLE - This instruction represents an instruction bundle. Instructions
+/// which immediately follow a BUNDLE instruction which are marked with
+/// 'InsideBundle' flag are inside the bundle.
+HANDLE_TARGET_OPCODE(BUNDLE)
+
+/// Lifetime markers.
+HANDLE_TARGET_OPCODE(LIFETIME_START)
+HANDLE_TARGET_OPCODE(LIFETIME_END)
+
+/// Pseudo probe
+HANDLE_TARGET_OPCODE(PSEUDO_PROBE)
+
+/// Arithmetic fence.
+HANDLE_TARGET_OPCODE(ARITH_FENCE)
+
+/// A Stackmap instruction captures the location of live variables at its
+/// position in the instruction stream. It is followed by a shadow of bytes
+/// that must lie within the function and not contain another stackmap.
+HANDLE_TARGET_OPCODE(STACKMAP)
+
+/// FEntry all - This is a marker instruction which gets translated into a raw fentry call.
+HANDLE_TARGET_OPCODE(FENTRY_CALL)
+
+/// Patchable call instruction - this instruction represents a call to a
+/// constant address, followed by a series of NOPs. It is intended to
+/// support optimizations for dynamic languages (such as javascript) that
+/// rewrite calls to runtimes with more efficient code sequences.
+/// This also implies a stack map.
+HANDLE_TARGET_OPCODE(PATCHPOINT)
+
+/// This pseudo-instruction loads the stack guard value. Targets which need
+/// to prevent the stack guard value or address from being spilled to the
+/// stack should override TargetLowering::emitLoadStackGuardNode and
+/// additionally expand this pseudo after register allocation.
+HANDLE_TARGET_OPCODE(LOAD_STACK_GUARD)
+
+/// These are used to support call sites that must have the stack adjusted
+/// before the call (e.g. to initialize an argument passed by value).
+/// See llvm.call.preallocated.{setup,arg} in the LangRef for more details.
+HANDLE_TARGET_OPCODE(PREALLOCATED_SETUP)
+HANDLE_TARGET_OPCODE(PREALLOCATED_ARG)
+
+/// Call instruction with associated vm state for deoptimization and list
+/// of live pointers for relocation by the garbage collector. It is
+/// intended to support garbage collection with fully precise relocating
+/// collectors and deoptimizations in either the callee or caller.
+HANDLE_TARGET_OPCODE(STATEPOINT)
+
+/// Instruction that records the offset of a local stack allocation passed to
+/// llvm.localescape. It has two arguments: the symbol for the label and the
+/// frame index of the local stack allocation.
+HANDLE_TARGET_OPCODE(LOCAL_ESCAPE)
+
+/// Wraps a machine instruction which can fault, bundled with associated
+/// information on how to handle such a fault.
+/// For example loading instruction that may page fault, bundled with associated
+/// information on how to handle such a page fault. It is intended to support
+/// "zero cost" null checks in managed languages by allowing LLVM to fold
+/// comparisons into existing memory operations.
+HANDLE_TARGET_OPCODE(FAULTING_OP)
+
+/// Wraps a machine instruction to add patchability constraints. An
+/// instruction wrapped in PATCHABLE_OP has to either have a minimum
+/// size or be preceded with a nop of that size. The first operand is
+/// an immediate denoting the minimum size of the instruction, the
+/// second operand is an immediate denoting the opcode of the original
+/// instruction. The rest of the operands are the operands of the
+/// original instruction.
+/// PATCHABLE_OP can be used as second operand to only insert a nop of
+/// required size.
+HANDLE_TARGET_OPCODE(PATCHABLE_OP)
+
+/// This is a marker instruction which gets translated into a nop sled, useful
+/// for inserting instrumentation instructions at runtime.
+HANDLE_TARGET_OPCODE(PATCHABLE_FUNCTION_ENTER)
+
+/// Wraps a return instruction and its operands to enable adding nop sleds
+/// either before or after the return. The nop sleds are useful for inserting
+/// instrumentation instructions at runtime.
+/// The patch here replaces the return instruction.
+HANDLE_TARGET_OPCODE(PATCHABLE_RET)
+
+/// This is a marker instruction which gets translated into a nop sled, useful
+/// for inserting instrumentation instructions at runtime.
+/// The patch here prepends the return instruction.
+/// The same thing as in x86_64 is not possible for ARM because it has multiple
+/// return instructions. Furthermore, CPU allows parametrized and even
+/// conditional return instructions. In the current ARM implementation we are
+/// making use of the fact that currently LLVM doesn't seem to generate
+/// conditional return instructions.
+/// On ARM, the same instruction can be used for popping multiple registers
+/// from the stack and returning (it just pops pc register too), and LLVM
+/// generates it sometimes. So we can't insert the sled between this stack
+/// adjustment and the return without splitting the original instruction into 2
+/// instructions. So on ARM, rather than jumping into the exit trampoline, we
+/// call it, it does the tracing, preserves the stack and returns.
+HANDLE_TARGET_OPCODE(PATCHABLE_FUNCTION_EXIT)
+
+/// Wraps a tail call instruction and its operands to enable adding nop sleds
+/// either before or after the tail exit. We use this as a disambiguation from
+/// PATCHABLE_RET which specifically only works for return instructions.
+HANDLE_TARGET_OPCODE(PATCHABLE_TAIL_CALL)
+
+/// Wraps a logging call and its arguments with nop sleds. At runtime, this can
+/// be patched to insert instrumentation instructions.
+HANDLE_TARGET_OPCODE(PATCHABLE_EVENT_CALL)
+
+/// Wraps a typed logging call and its argument with nop sleds. At runtime, this
+/// can be patched to insert instrumentation instructions.
+HANDLE_TARGET_OPCODE(PATCHABLE_TYPED_EVENT_CALL)
+
+HANDLE_TARGET_OPCODE(ICALL_BRANCH_FUNNEL)
+
+// This is a fence with the singlethread scope. It represents a compiler memory
+// barrier, but does not correspond to any generated instruction.
+HANDLE_TARGET_OPCODE(MEMBARRIER)
+
+/// The following generic opcodes are not supposed to appear after ISel.
+/// This is something we might want to relax, but for now, this is convenient
+/// to produce diagnostics.
+
+/// Instructions which should not exist past instruction selection, but do not
+/// generate code. These instructions only act as optimization hints.
+HANDLE_TARGET_OPCODE(G_ASSERT_SEXT)
+HANDLE_TARGET_OPCODE(G_ASSERT_ZEXT)
+HANDLE_TARGET_OPCODE(G_ASSERT_ALIGN)
+HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPTIMIZATION_HINT_START,
+ G_ASSERT_SEXT)
+HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPTIMIZATION_HINT_END,
+ G_ASSERT_ALIGN)
+
+/// Generic ADD instruction. This is an integer add.
+HANDLE_TARGET_OPCODE(G_ADD)
+HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_START, G_ADD)
+
+/// Generic SUB instruction. This is an integer sub.
+HANDLE_TARGET_OPCODE(G_SUB)
+
+// Generic multiply instruction.
+HANDLE_TARGET_OPCODE(G_MUL)
+
+// Generic signed division instruction.
+HANDLE_TARGET_OPCODE(G_SDIV)
+
+// Generic unsigned division instruction.
+HANDLE_TARGET_OPCODE(G_UDIV)
+
+// Generic signed remainder instruction.
+HANDLE_TARGET_OPCODE(G_SREM)
+
+// Generic unsigned remainder instruction.
+HANDLE_TARGET_OPCODE(G_UREM)
+
+// Generic signed divrem instruction.
+HANDLE_TARGET_OPCODE(G_SDIVREM)
+
+// Generic unsigned divrem instruction.
+HANDLE_TARGET_OPCODE(G_UDIVREM)
+
+/// Generic bitwise and instruction.
+HANDLE_TARGET_OPCODE(G_AND)
+
+/// Generic bitwise or instruction.
+HANDLE_TARGET_OPCODE(G_OR)
+
+/// Generic bitwise exclusive-or instruction.
+HANDLE_TARGET_OPCODE(G_XOR)
+
+
+HANDLE_TARGET_OPCODE(G_IMPLICIT_DEF)
+
+/// Generic PHI instruction with types.
+HANDLE_TARGET_OPCODE(G_PHI)
+
+/// Generic instruction to materialize the address of an alloca or other
+/// stack-based object.
+HANDLE_TARGET_OPCODE(G_FRAME_INDEX)
+
+/// Generic reference to global value.
+HANDLE_TARGET_OPCODE(G_GLOBAL_VALUE)
+
+/// Generic instruction to extract blocks of bits from the register given
+/// (typically a sub-register COPY after instruction selection).
+HANDLE_TARGET_OPCODE(G_EXTRACT)
+
+HANDLE_TARGET_OPCODE(G_UNMERGE_VALUES)
+
+/// Generic instruction to insert blocks of bits from the registers given into
+/// the source.
+HANDLE_TARGET_OPCODE(G_INSERT)
+
+/// Generic instruction to paste a variable number of components together into a
+/// larger register.
+HANDLE_TARGET_OPCODE(G_MERGE_VALUES)
+
+/// Generic instruction to create a vector value from a number of scalar
+/// components.
+HANDLE_TARGET_OPCODE(G_BUILD_VECTOR)
+
+/// Generic instruction to create a vector value from a number of scalar
+/// components, which have types larger than the result vector elt type.
+HANDLE_TARGET_OPCODE(G_BUILD_VECTOR_TRUNC)
+
+/// Generic instruction to create a vector by concatenating multiple vectors.
+HANDLE_TARGET_OPCODE(G_CONCAT_VECTORS)
+
+/// Generic pointer to int conversion.
+HANDLE_TARGET_OPCODE(G_PTRTOINT)
+
+/// Generic int to pointer conversion.
+HANDLE_TARGET_OPCODE(G_INTTOPTR)
+
+/// Generic bitcast. The source and destination types must be different, or a
+/// COPY is the relevant instruction.
+HANDLE_TARGET_OPCODE(G_BITCAST)
+
+/// Generic freeze.
+HANDLE_TARGET_OPCODE(G_FREEZE)
+
+// INTRINSIC fptrunc_round intrinsic.
+HANDLE_TARGET_OPCODE(G_INTRINSIC_FPTRUNC_ROUND)
+
+/// INTRINSIC trunc intrinsic.
+HANDLE_TARGET_OPCODE(G_INTRINSIC_TRUNC)
+
+/// INTRINSIC round intrinsic.
+HANDLE_TARGET_OPCODE(G_INTRINSIC_ROUND)
+
+/// INTRINSIC round to integer intrinsic.
+HANDLE_TARGET_OPCODE(G_INTRINSIC_LRINT)
+
+/// INTRINSIC roundeven intrinsic.
+HANDLE_TARGET_OPCODE(G_INTRINSIC_ROUNDEVEN)
+
+/// INTRINSIC readcyclecounter
+HANDLE_TARGET_OPCODE(G_READCYCLECOUNTER)
+
+/// Generic load (including anyext load)
+HANDLE_TARGET_OPCODE(G_LOAD)
+
+/// Generic signext load
+HANDLE_TARGET_OPCODE(G_SEXTLOAD)
+
+/// Generic zeroext load
+HANDLE_TARGET_OPCODE(G_ZEXTLOAD)
+
+/// Generic indexed load (including anyext load)
+HANDLE_TARGET_OPCODE(G_INDEXED_LOAD)
+
+/// Generic indexed signext load
+HANDLE_TARGET_OPCODE(G_INDEXED_SEXTLOAD)
+
+/// Generic indexed zeroext load
+HANDLE_TARGET_OPCODE(G_INDEXED_ZEXTLOAD)
+
+/// Generic store.
+HANDLE_TARGET_OPCODE(G_STORE)
+
+/// Generic indexed store.
+HANDLE_TARGET_OPCODE(G_INDEXED_STORE)
+
+/// Generic atomic cmpxchg with internal success check.
+HANDLE_TARGET_OPCODE(G_ATOMIC_CMPXCHG_WITH_SUCCESS)
+
+/// Generic atomic cmpxchg.
+HANDLE_TARGET_OPCODE(G_ATOMIC_CMPXCHG)
+
+/// Generic atomicrmw.
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_XCHG)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_ADD)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_SUB)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_AND)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_NAND)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_OR)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_XOR)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_MAX)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_MIN)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_UMAX)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_UMIN)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_FADD)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_FSUB)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_FMAX)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_FMIN)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_UINC_WRAP)
+HANDLE_TARGET_OPCODE(G_ATOMICRMW_UDEC_WRAP)
+
+// Marker for start of Generic AtomicRMW opcodes
+HANDLE_TARGET_OPCODE_MARKER(GENERIC_ATOMICRMW_OP_START, G_ATOMICRMW_XCHG)
+
+// Marker for end of Generic AtomicRMW opcodes
+HANDLE_TARGET_OPCODE_MARKER(GENERIC_ATOMICRMW_OP_END, G_ATOMICRMW_UDEC_WRAP)
+
+// Generic atomic fence
+HANDLE_TARGET_OPCODE(G_FENCE)
+
+/// Generic conditional branch instruction.
+HANDLE_TARGET_OPCODE(G_BRCOND)
+
+/// Generic indirect branch instruction.
+HANDLE_TARGET_OPCODE(G_BRINDIRECT)
+
+/// Begin an invoke region marker.
+HANDLE_TARGET_OPCODE(G_INVOKE_REGION_START)
+
+/// Generic intrinsic use (without side effects).
+HANDLE_TARGET_OPCODE(G_INTRINSIC)
+
+/// Generic intrinsic use (with side effects).
+HANDLE_TARGET_OPCODE(G_INTRINSIC_W_SIDE_EFFECTS)
+
+/// Generic extension allowing rubbish in high bits.
+HANDLE_TARGET_OPCODE(G_ANYEXT)
+
+/// Generic instruction to discard the high bits of a register. This differs
+/// from (G_EXTRACT val, 0) on its action on vectors: G_TRUNC will truncate
+/// each element individually, G_EXTRACT will typically discard the high
+/// elements of the vector.
+HANDLE_TARGET_OPCODE(G_TRUNC)
+
+/// Generic integer constant.
+HANDLE_TARGET_OPCODE(G_CONSTANT)
+
+/// Generic floating constant.
+HANDLE_TARGET_OPCODE(G_FCONSTANT)
+
+/// Generic va_start instruction. Stores to its one pointer operand.
+HANDLE_TARGET_OPCODE(G_VASTART)
+
+/// Generic va_start instruction. Stores to its one pointer operand.
+HANDLE_TARGET_OPCODE(G_VAARG)
+
+// Generic sign extend
+HANDLE_TARGET_OPCODE(G_SEXT)
+HANDLE_TARGET_OPCODE(G_SEXT_INREG)
+
+// Generic zero extend
+HANDLE_TARGET_OPCODE(G_ZEXT)
+
+// Generic left-shift
+HANDLE_TARGET_OPCODE(G_SHL)
+
+// Generic logical right-shift
+HANDLE_TARGET_OPCODE(G_LSHR)
+
+// Generic arithmetic right-shift
+HANDLE_TARGET_OPCODE(G_ASHR)
+
+// Generic funnel left shift
+HANDLE_TARGET_OPCODE(G_FSHL)
+
+// Generic funnel right shift
+HANDLE_TARGET_OPCODE(G_FSHR)
+
+// Generic right rotate
+HANDLE_TARGET_OPCODE(G_ROTR)
+
+// Generic left rotate
+HANDLE_TARGET_OPCODE(G_ROTL)
+
+/// Generic integer-base comparison, also applicable to vectors of integers.
+HANDLE_TARGET_OPCODE(G_ICMP)
+
+/// Generic floating-point comparison, also applicable to vectors.
+HANDLE_TARGET_OPCODE(G_FCMP)
+
+/// Generic select.
+HANDLE_TARGET_OPCODE(G_SELECT)
+
+/// Generic unsigned add instruction, consuming the normal operands and
+/// producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_UADDO)
+
+/// Generic unsigned add instruction, consuming the normal operands plus a carry
+/// flag, and similarly producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_UADDE)
+
+/// Generic unsigned sub instruction, consuming the normal operands and
+/// producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_USUBO)
+
+/// Generic unsigned subtract instruction, consuming the normal operands plus a
+/// carry flag, and similarly producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_USUBE)
+
+/// Generic signed add instruction, producing the result and a signed overflow
+/// flag.
+HANDLE_TARGET_OPCODE(G_SADDO)
+
+/// Generic signed add instruction, consuming the normal operands plus a carry
+/// flag, and similarly producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_SADDE)
+
+/// Generic signed subtract instruction, producing the result and a signed
+/// overflow flag.
+HANDLE_TARGET_OPCODE(G_SSUBO)
+
+/// Generic signed sub instruction, consuming the normal operands plus a carry
+/// flag, and similarly producing the result and a carry flag.
+HANDLE_TARGET_OPCODE(G_SSUBE)
+
+/// Generic unsigned multiply instruction, producing the result and a signed
+/// overflow flag.
+HANDLE_TARGET_OPCODE(G_UMULO)
+
+/// Generic signed multiply instruction, producing the result and a signed
+/// overflow flag.
+HANDLE_TARGET_OPCODE(G_SMULO)
+
+// Multiply two numbers at twice the incoming bit width (unsigned) and return
+// the high half of the result.
+HANDLE_TARGET_OPCODE(G_UMULH)
+
+// Multiply two numbers at twice the incoming bit width (signed) and return
+// the high half of the result.
+HANDLE_TARGET_OPCODE(G_SMULH)
+
+/// Generic saturating unsigned addition.
+HANDLE_TARGET_OPCODE(G_UADDSAT)
+
+/// Generic saturating signed addition.
+HANDLE_TARGET_OPCODE(G_SADDSAT)
+
+/// Generic saturating unsigned subtraction.
+HANDLE_TARGET_OPCODE(G_USUBSAT)
+
+/// Generic saturating signed subtraction.
+HANDLE_TARGET_OPCODE(G_SSUBSAT)
+
+/// Generic saturating unsigned left shift.
+HANDLE_TARGET_OPCODE(G_USHLSAT)
+
+/// Generic saturating signed left shift.
+HANDLE_TARGET_OPCODE(G_SSHLSAT)
+
+// Perform signed fixed point multiplication
+HANDLE_TARGET_OPCODE(G_SMULFIX)
+
+// Perform unsigned fixed point multiplication
+HANDLE_TARGET_OPCODE(G_UMULFIX)
+
+// Perform signed, saturating fixed point multiplication
+HANDLE_TARGET_OPCODE(G_SMULFIXSAT)
+
+// Perform unsigned, saturating fixed point multiplication
+HANDLE_TARGET_OPCODE(G_UMULFIXSAT)
+
+// Perform signed fixed point division
+HANDLE_TARGET_OPCODE(G_SDIVFIX)
+
+// Perform unsigned fixed point division
+HANDLE_TARGET_OPCODE(G_UDIVFIX)
+
+// Perform signed, saturating fixed point division
+HANDLE_TARGET_OPCODE(G_SDIVFIXSAT)
+
+// Perform unsigned, saturating fixed point division
+HANDLE_TARGET_OPCODE(G_UDIVFIXSAT)
+
+/// Generic FP addition.
+HANDLE_TARGET_OPCODE(G_FADD)
+
+/// Generic FP subtraction.
+HANDLE_TARGET_OPCODE(G_FSUB)
+
+/// Generic FP multiplication.
+HANDLE_TARGET_OPCODE(G_FMUL)
+
+/// Generic FMA multiplication. Behaves like llvm fma intrinsic
+HANDLE_TARGET_OPCODE(G_FMA)
+
+/// Generic FP multiply and add. Behaves as separate fmul and fadd.
+HANDLE_TARGET_OPCODE(G_FMAD)
+
+/// Generic FP division.
+HANDLE_TARGET_OPCODE(G_FDIV)
+
+/// Generic FP remainder.
+HANDLE_TARGET_OPCODE(G_FREM)
+
+/// Generic FP exponentiation.
+HANDLE_TARGET_OPCODE(G_FPOW)
+
+/// Generic FP exponentiation, with an integer exponent.
+HANDLE_TARGET_OPCODE(G_FPOWI)
+
+/// Generic base-e exponential of a value.
+HANDLE_TARGET_OPCODE(G_FEXP)
+
+/// Generic base-2 exponential of a value.
+HANDLE_TARGET_OPCODE(G_FEXP2)
+
+/// Floating point base-e logarithm of a value.
+HANDLE_TARGET_OPCODE(G_FLOG)
+
+/// Floating point base-2 logarithm of a value.
+HANDLE_TARGET_OPCODE(G_FLOG2)
+
+/// Floating point base-10 logarithm of a value.
+HANDLE_TARGET_OPCODE(G_FLOG10)
+
+/// Generic FP negation.
+HANDLE_TARGET_OPCODE(G_FNEG)
+
+/// Generic FP extension.
+HANDLE_TARGET_OPCODE(G_FPEXT)
+
+/// Generic float to signed-int conversion
+HANDLE_TARGET_OPCODE(G_FPTRUNC)
+
+/// Generic float to signed-int conversion
+HANDLE_TARGET_OPCODE(G_FPTOSI)
+
+/// Generic float to unsigned-int conversion
+HANDLE_TARGET_OPCODE(G_FPTOUI)
+
+/// Generic signed-int to float conversion
+HANDLE_TARGET_OPCODE(G_SITOFP)
+
+/// Generic unsigned-int to float conversion
+HANDLE_TARGET_OPCODE(G_UITOFP)
+
+/// Generic FP absolute value.
+HANDLE_TARGET_OPCODE(G_FABS)
+
+/// FCOPYSIGN(X, Y) - Return the value of X with the sign of Y. NOTE: This does
+/// not require that X and Y have the same type, just that they are both
+/// floating point. X and the result must have the same type. FCOPYSIGN(f32,
+/// f64) is allowed.
+HANDLE_TARGET_OPCODE(G_FCOPYSIGN)
+
+/// Generic test for floating-point class.
+HANDLE_TARGET_OPCODE(G_IS_FPCLASS)
+
+/// Generic FP canonicalize value.
+HANDLE_TARGET_OPCODE(G_FCANONICALIZE)
+
+/// FP min/max matching libm's fmin/fmax
+HANDLE_TARGET_OPCODE(G_FMINNUM)
+HANDLE_TARGET_OPCODE(G_FMAXNUM)
+
+/// FP min/max matching IEEE-754 2008's minnum/maxnum semantics.
+HANDLE_TARGET_OPCODE(G_FMINNUM_IEEE)
+HANDLE_TARGET_OPCODE(G_FMAXNUM_IEEE)
+
+/// FP min/max matching IEEE-754 2018 draft semantics.
+HANDLE_TARGET_OPCODE(G_FMINIMUM)
+HANDLE_TARGET_OPCODE(G_FMAXIMUM)
+
+/// Generic pointer offset
+HANDLE_TARGET_OPCODE(G_PTR_ADD)
+
+/// Clear the specified bits in a pointer.
+HANDLE_TARGET_OPCODE(G_PTRMASK)
+
+/// Generic signed integer minimum.
+HANDLE_TARGET_OPCODE(G_SMIN)
+
+/// Generic signed integer maximum.
+HANDLE_TARGET_OPCODE(G_SMAX)
+
+/// Generic unsigned integer maximum.
+HANDLE_TARGET_OPCODE(G_UMIN)
+
+/// Generic unsigned integer maximum.
+HANDLE_TARGET_OPCODE(G_UMAX)
+
+/// Generic integer absolute value.
+HANDLE_TARGET_OPCODE(G_ABS)
+
+HANDLE_TARGET_OPCODE(G_LROUND)
+HANDLE_TARGET_OPCODE(G_LLROUND)
+
+/// Generic BRANCH instruction. This is an unconditional branch.
+HANDLE_TARGET_OPCODE(G_BR)
+
+/// Generic branch to jump table entry.
+HANDLE_TARGET_OPCODE(G_BRJT)
+
+/// Generic insertelement.
+HANDLE_TARGET_OPCODE(G_INSERT_VECTOR_ELT)
+
+/// Generic extractelement.
+HANDLE_TARGET_OPCODE(G_EXTRACT_VECTOR_ELT)
+
+/// Generic shufflevector.
+HANDLE_TARGET_OPCODE(G_SHUFFLE_VECTOR)
+
+/// Generic count trailing zeroes.
+HANDLE_TARGET_OPCODE(G_CTTZ)
+
+/// Same as above, undefined for zero inputs.
+HANDLE_TARGET_OPCODE(G_CTTZ_ZERO_UNDEF)
+
+/// Generic count leading zeroes.
+HANDLE_TARGET_OPCODE(G_CTLZ)
+
+/// Same as above, undefined for zero inputs.
+HANDLE_TARGET_OPCODE(G_CTLZ_ZERO_UNDEF)
+
+/// Generic count bits.
+HANDLE_TARGET_OPCODE(G_CTPOP)
+
+/// Generic byte swap.
+HANDLE_TARGET_OPCODE(G_BSWAP)
+
+/// Generic bit reverse.
+HANDLE_TARGET_OPCODE(G_BITREVERSE)
+
+/// Floating point ceil.
+HANDLE_TARGET_OPCODE(G_FCEIL)
+
+/// Floating point cosine.
+HANDLE_TARGET_OPCODE(G_FCOS)
+
+/// Floating point sine.
+HANDLE_TARGET_OPCODE(G_FSIN)
+
+/// Floating point square root.
+HANDLE_TARGET_OPCODE(G_FSQRT)
+
+/// Floating point floor.
+HANDLE_TARGET_OPCODE(G_FFLOOR)
+
+/// Floating point round to next integer.
+HANDLE_TARGET_OPCODE(G_FRINT)
+
+/// Floating point round to nearest integer.
+HANDLE_TARGET_OPCODE(G_FNEARBYINT)
+
+/// Generic AddressSpaceCast.
+HANDLE_TARGET_OPCODE(G_ADDRSPACE_CAST)
+
+/// Generic block address
+HANDLE_TARGET_OPCODE(G_BLOCK_ADDR)
+
+/// Generic jump table address
+HANDLE_TARGET_OPCODE(G_JUMP_TABLE)
+
+/// Generic dynamic stack allocation.
+HANDLE_TARGET_OPCODE(G_DYN_STACKALLOC)
+
+/// Strict floating point instructions.
+HANDLE_TARGET_OPCODE(G_STRICT_FADD)
+HANDLE_TARGET_OPCODE(G_STRICT_FSUB)
+HANDLE_TARGET_OPCODE(G_STRICT_FMUL)
+HANDLE_TARGET_OPCODE(G_STRICT_FDIV)
+HANDLE_TARGET_OPCODE(G_STRICT_FREM)
+HANDLE_TARGET_OPCODE(G_STRICT_FMA)
+HANDLE_TARGET_OPCODE(G_STRICT_FSQRT)
+
+/// read_register intrinsic
+HANDLE_TARGET_OPCODE(G_READ_REGISTER)
+
+/// write_register intrinsic
+HANDLE_TARGET_OPCODE(G_WRITE_REGISTER)
+
+/// llvm.memcpy intrinsic
+HANDLE_TARGET_OPCODE(G_MEMCPY)
+
+/// llvm.memcpy.inline intrinsic
+HANDLE_TARGET_OPCODE(G_MEMCPY_INLINE)
+
+/// llvm.memmove intrinsic
+HANDLE_TARGET_OPCODE(G_MEMMOVE)
+
+/// llvm.memset intrinsic
+HANDLE_TARGET_OPCODE(G_MEMSET)
+HANDLE_TARGET_OPCODE(G_BZERO)
+
+/// Vector reductions
+HANDLE_TARGET_OPCODE(G_VECREDUCE_SEQ_FADD)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_SEQ_FMUL)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_FADD)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_FMUL)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_FMAX)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_FMIN)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_ADD)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_MUL)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_AND)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_OR)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_XOR)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_SMAX)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_SMIN)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_UMAX)
+HANDLE_TARGET_OPCODE(G_VECREDUCE_UMIN)
+
+HANDLE_TARGET_OPCODE(G_SBFX)
+HANDLE_TARGET_OPCODE(G_UBFX)
+
+/// Marker for the end of the generic opcode.
+/// This is used to check if an opcode is in the range of the
+/// generic opcodes.
+HANDLE_TARGET_OPCODE_MARKER(PRE_ISEL_GENERIC_OPCODE_END, G_UBFX)
+
+/// BUILTIN_OP_END - This must be the last enum value in this list.
+/// The target-specific post-isel opcode values start here.
+HANDLE_TARGET_OPCODE_MARKER(GENERIC_OP_END, PRE_ISEL_GENERIC_OPCODE_END)
diff --git a/contrib/libs/llvm16/include/llvm/Support/TargetParser.h b/contrib/libs/llvm16/include/llvm/Support/TargetParser.h
new file mode 100644
index 00000000000..f5d520b8fcd
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/TargetParser.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/TargetParser.h -----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This header is deprecated in favour of `llvm/TargetParser/TargetParser.h`.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/TargetParser.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ThreadPool.h b/contrib/libs/llvm16/include/llvm/Support/ThreadPool.h
new file mode 100644
index 00000000000..55a5bec523a
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ThreadPool.h
@@ -0,0 +1,260 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/ThreadPool.h - A ThreadPool implementation -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a crude C++11 based thread pool.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_THREADPOOL_H
+#define LLVM_SUPPORT_THREADPOOL_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/RWMutex.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/thread.h"
+
+#include <future>
+
+#include <condition_variable>
+#include <deque>
+#include <functional>
+#include <memory>
+#include <mutex>
+#include <utility>
+
+namespace llvm {
+
+class ThreadPoolTaskGroup;
+
+/// A ThreadPool for asynchronous parallel execution on a defined number of
+/// threads.
+///
+/// The pool keeps a vector of threads alive, waiting on a condition variable
+/// for some work to become available.
+///
+/// It is possible to reuse one thread pool for different groups of tasks
+/// by grouping tasks using ThreadPoolTaskGroup. All tasks are processed using
+/// the same queue, but it is possible to wait only for a specific group of
+/// tasks to finish.
+///
+/// It is also possible for worker threads to submit new tasks and wait for
+/// them. Note that this may result in a deadlock in cases such as when a task
+/// (directly or indirectly) tries to wait for its own completion, or when all
+/// available threads are used up by tasks waiting for a task that has no thread
+/// left to run on (this includes waiting on the returned future). It should be
+/// generally safe to wait() for a group as long as groups do not form a cycle.
+class ThreadPool {
+public:
+ /// Construct a pool using the hardware strategy \p S for mapping hardware
+ /// execution resources (threads, cores, CPUs)
+ /// Defaults to using the maximum execution resources in the system, but
+ /// accounting for the affinity mask.
+ ThreadPool(ThreadPoolStrategy S = hardware_concurrency());
+
+ /// Blocking destructor: the pool will wait for all the threads to complete.
+ ~ThreadPool();
+
+ /// Asynchronous submission of a task to the pool. The returned future can be
+ /// used to wait for the task to finish and is *non-blocking* on destruction.
+ template <typename Function, typename... Args>
+ auto async(Function &&F, Args &&...ArgList) {
+ auto Task =
+ std::bind(std::forward<Function>(F), std::forward<Args>(ArgList)...);
+ return async(std::move(Task));
+ }
+
+ /// Overload, task will be in the given task group.
+ template <typename Function, typename... Args>
+ auto async(ThreadPoolTaskGroup &Group, Function &&F, Args &&...ArgList) {
+ auto Task =
+ std::bind(std::forward<Function>(F), std::forward<Args>(ArgList)...);
+ return async(Group, std::move(Task));
+ }
+
+ /// Asynchronous submission of a task to the pool. The returned future can be
+ /// used to wait for the task to finish and is *non-blocking* on destruction.
+ template <typename Func>
+ auto async(Func &&F) -> std::shared_future<decltype(F())> {
+ return asyncImpl(std::function<decltype(F())()>(std::forward<Func>(F)),
+ nullptr);
+ }
+
+ template <typename Func>
+ auto async(ThreadPoolTaskGroup &Group, Func &&F)
+ -> std::shared_future<decltype(F())> {
+ return asyncImpl(std::function<decltype(F())()>(std::forward<Func>(F)),
+ &Group);
+ }
+
+ /// Blocking wait for all the threads to complete and the queue to be empty.
+ /// It is an error to try to add new tasks while blocking on this call.
+ /// Calling wait() from a task would deadlock waiting for itself.
+ void wait();
+
+ /// Blocking wait for only all the threads in the given group to complete.
+ /// It is possible to wait even inside a task, but waiting (directly or
+ /// indirectly) on itself will deadlock. If called from a task running on a
+ /// worker thread, the call may process pending tasks while waiting in order
+ /// not to waste the thread.
+ void wait(ThreadPoolTaskGroup &Group);
+
+ // TODO: misleading legacy name warning!
+ // Returns the maximum number of worker threads in the pool, not the current
+ // number of threads!
+ unsigned getThreadCount() const { return MaxThreadCount; }
+
+ /// Returns true if the current thread is a worker thread of this thread pool.
+ bool isWorkerThread() const;
+
+private:
+ /// Helpers to create a promise and a callable wrapper of \p Task that sets
+ /// the result of the promise. Returns the callable and a future to access the
+ /// result.
+ template <typename ResTy>
+ static std::pair<std::function<void()>, std::future<ResTy>>
+ createTaskAndFuture(std::function<ResTy()> Task) {
+ std::shared_ptr<std::promise<ResTy>> Promise =
+ std::make_shared<std::promise<ResTy>>();
+ auto F = Promise->get_future();
+ return {
+ [Promise = std::move(Promise), Task]() { Promise->set_value(Task()); },
+ std::move(F)};
+ }
+ static std::pair<std::function<void()>, std::future<void>>
+ createTaskAndFuture(std::function<void()> Task) {
+ std::shared_ptr<std::promise<void>> Promise =
+ std::make_shared<std::promise<void>>();
+ auto F = Promise->get_future();
+ return {[Promise = std::move(Promise), Task]() {
+ Task();
+ Promise->set_value();
+ },
+ std::move(F)};
+ }
+
+ /// Returns true if all tasks in the given group have finished (nullptr means
+ /// all tasks regardless of their group). QueueLock must be locked.
+ bool workCompletedUnlocked(ThreadPoolTaskGroup *Group) const;
+
+ /// Asynchronous submission of a task to the pool. The returned future can be
+ /// used to wait for the task to finish and is *non-blocking* on destruction.
+ template <typename ResTy>
+ std::shared_future<ResTy> asyncImpl(std::function<ResTy()> Task,
+ ThreadPoolTaskGroup *Group) {
+
+#if LLVM_ENABLE_THREADS
+ /// Wrap the Task in a std::function<void()> that sets the result of the
+ /// corresponding future.
+ auto R = createTaskAndFuture(Task);
+
+ int requestedThreads;
+ {
+ // Lock the queue and push the new task
+ std::unique_lock<std::mutex> LockGuard(QueueLock);
+
+ // Don't allow enqueueing after disabling the pool
+ assert(EnableFlag && "Queuing a thread during ThreadPool destruction");
+ Tasks.emplace_back(std::make_pair(std::move(R.first), Group));
+ requestedThreads = ActiveThreads + Tasks.size();
+ }
+ QueueCondition.notify_one();
+ grow(requestedThreads);
+ return R.second.share();
+
+#else // LLVM_ENABLE_THREADS Disabled
+
+ // Get a Future with launch::deferred execution using std::async
+ auto Future = std::async(std::launch::deferred, std::move(Task)).share();
+ // Wrap the future so that both ThreadPool::wait() can operate and the
+ // returned future can be sync'ed on.
+ Tasks.emplace_back(std::make_pair([Future]() { Future.get(); }, Group));
+ return Future;
+#endif
+ }
+
+#if LLVM_ENABLE_THREADS
+ // Grow to ensure that we have at least `requested` Threads, but do not go
+ // over MaxThreadCount.
+ void grow(int requested);
+
+ void processTasks(ThreadPoolTaskGroup *WaitingForGroup);
+#endif
+
+ /// Threads in flight
+ std::vector<llvm::thread> Threads;
+ /// Lock protecting access to the Threads vector.
+ mutable llvm::sys::RWMutex ThreadsLock;
+
+ /// Tasks waiting for execution in the pool.
+ std::deque<std::pair<std::function<void()>, ThreadPoolTaskGroup *>> Tasks;
+
+ /// Locking and signaling for accessing the Tasks queue.
+ std::mutex QueueLock;
+ std::condition_variable QueueCondition;
+
+ /// Signaling for job completion (all tasks or all tasks in a group).
+ std::condition_variable CompletionCondition;
+
+ /// Keep track of the number of thread actually busy
+ unsigned ActiveThreads = 0;
+ /// Number of threads active for tasks in the given group (only non-zero).
+ DenseMap<ThreadPoolTaskGroup *, unsigned> ActiveGroups;
+
+#if LLVM_ENABLE_THREADS // avoids warning for unused variable
+ /// Signal for the destruction of the pool, asking thread to exit.
+ bool EnableFlag = true;
+#endif
+
+ const ThreadPoolStrategy Strategy;
+
+ /// Maximum number of threads to potentially grow this pool to.
+ const unsigned MaxThreadCount;
+};
+
+/// A group of tasks to be run on a thread pool. Thread pool tasks in different
+/// groups can run on the same threadpool but can be waited for separately.
+/// It is even possible for tasks of one group to submit and wait for tasks
+/// of another group, as long as this does not form a loop.
+class ThreadPoolTaskGroup {
+public:
+ /// The ThreadPool argument is the thread pool to forward calls to.
+ ThreadPoolTaskGroup(ThreadPool &Pool) : Pool(Pool) {}
+
+ /// Blocking destructor: will wait for all the tasks in the group to complete
+ /// by calling ThreadPool::wait().
+ ~ThreadPoolTaskGroup() { wait(); }
+
+ /// Calls ThreadPool::async() for this group.
+ template <typename Function, typename... Args>
+ inline auto async(Function &&F, Args &&...ArgList) {
+ return Pool.async(*this, std::forward<Function>(F),
+ std::forward<Args>(ArgList)...);
+ }
+
+ /// Calls ThreadPool::wait() for this group.
+ void wait() { Pool.wait(*this); }
+
+private:
+ ThreadPool &Pool;
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_THREADPOOL_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Threading.h b/contrib/libs/llvm16/include/llvm/Support/Threading.h
new file mode 100644
index 00000000000..30f348e49cb
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Threading.h
@@ -0,0 +1,270 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/Threading.h - Control multithreading mode --*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares helper functions for running LLVM in a multi-threaded
+// environment.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_THREADING_H
+#define LLVM_SUPPORT_THREADING_H
+
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
+#include "llvm/Support/Compiler.h"
+#include <ciso646> // So we can check the C++ standard lib macros.
+#include <optional>
+
+#if defined(_MSC_VER)
+// MSVC's call_once implementation worked since VS 2015, which is the minimum
+// supported version as of this writing.
+#define LLVM_THREADING_USE_STD_CALL_ONCE 1
+#elif defined(LLVM_ON_UNIX) && \
+ (defined(_LIBCPP_VERSION) || \
+ !(defined(__NetBSD__) || defined(__OpenBSD__) || defined(__powerpc__)))
+// std::call_once from libc++ is used on all Unix platforms. Other
+// implementations like libstdc++ are known to have problems on NetBSD,
+// OpenBSD and PowerPC.
+#define LLVM_THREADING_USE_STD_CALL_ONCE 1
+#elif defined(LLVM_ON_UNIX) && \
+ (defined(__powerpc__) && defined(__LITTLE_ENDIAN__))
+#define LLVM_THREADING_USE_STD_CALL_ONCE 1
+#else
+#define LLVM_THREADING_USE_STD_CALL_ONCE 0
+#endif
+
+#if LLVM_THREADING_USE_STD_CALL_ONCE
+#include <mutex>
+#else
+#include "llvm/Support/Atomic.h"
+#endif
+
+namespace llvm {
+class Twine;
+
+/// Returns true if LLVM is compiled with support for multi-threading, and
+/// false otherwise.
+constexpr bool llvm_is_multithreaded() { return LLVM_ENABLE_THREADS; }
+
+#if LLVM_THREADING_USE_STD_CALL_ONCE
+
+ typedef std::once_flag once_flag;
+
+#else
+
+ enum InitStatus { Uninitialized = 0, Wait = 1, Done = 2 };
+
+ /// The llvm::once_flag structure
+ ///
+ /// This type is modeled after std::once_flag to use with llvm::call_once.
+ /// This structure must be used as an opaque object. It is a struct to force
+ /// autoinitialization and behave like std::once_flag.
+ struct once_flag {
+ volatile sys::cas_flag status = Uninitialized;
+ };
+
+#endif
+
+ /// Execute the function specified as a parameter once.
+ ///
+ /// Typical usage:
+ /// \code
+ /// void foo() {...};
+ /// ...
+ /// static once_flag flag;
+ /// call_once(flag, foo);
+ /// \endcode
+ ///
+ /// \param flag Flag used for tracking whether or not this has run.
+ /// \param F Function to call once.
+ template <typename Function, typename... Args>
+ void call_once(once_flag &flag, Function &&F, Args &&... ArgList) {
+#if LLVM_THREADING_USE_STD_CALL_ONCE
+ std::call_once(flag, std::forward<Function>(F),
+ std::forward<Args>(ArgList)...);
+#else
+ // For other platforms we use a generic (if brittle) version based on our
+ // atomics.
+ sys::cas_flag old_val = sys::CompareAndSwap(&flag.status, Wait, Uninitialized);
+ if (old_val == Uninitialized) {
+ std::forward<Function>(F)(std::forward<Args>(ArgList)...);
+ sys::MemoryFence();
+ TsanIgnoreWritesBegin();
+ TsanHappensBefore(&flag.status);
+ flag.status = Done;
+ TsanIgnoreWritesEnd();
+ } else {
+ // Wait until any thread doing the call has finished.
+ sys::cas_flag tmp = flag.status;
+ sys::MemoryFence();
+ while (tmp != Done) {
+ tmp = flag.status;
+ sys::MemoryFence();
+ }
+ }
+ TsanHappensAfter(&flag.status);
+#endif
+ }
+
+ /// This tells how a thread pool will be used
+ class ThreadPoolStrategy {
+ public:
+ // The default value (0) means all available threads should be used,
+ // taking the affinity mask into account. If set, this value only represents
+ // a suggested high bound, the runtime might choose a lower value (not
+ // higher).
+ unsigned ThreadsRequested = 0;
+
+ // If SMT is active, use hyper threads. If false, there will be only one
+ // std::thread per core.
+ bool UseHyperThreads = true;
+
+ // If set, will constrain 'ThreadsRequested' to the number of hardware
+ // threads, or hardware cores.
+ bool Limit = false;
+
+ /// Retrieves the max available threads for the current strategy. This
+ /// accounts for affinity masks and takes advantage of all CPU sockets.
+ unsigned compute_thread_count() const;
+
+ /// Assign the current thread to an ideal hardware CPU or NUMA node. In a
+ /// multi-socket system, this ensures threads are assigned to all CPU
+ /// sockets. \p ThreadPoolNum represents a number bounded by [0,
+ /// compute_thread_count()).
+ void apply_thread_strategy(unsigned ThreadPoolNum) const;
+
+ /// Finds the CPU socket where a thread should go. Returns 'std::nullopt' if
+ /// the thread shall remain on the actual CPU socket.
+ std::optional<unsigned> compute_cpu_socket(unsigned ThreadPoolNum) const;
+ };
+
+ /// Build a strategy from a number of threads as a string provided in \p Num.
+ /// When Num is above the max number of threads specified by the \p Default
+ /// strategy, we attempt to equally allocate the threads on all CPU sockets.
+ /// "0" or an empty string will return the \p Default strategy.
+ /// "all" for using all hardware threads.
+ std::optional<ThreadPoolStrategy>
+ get_threadpool_strategy(StringRef Num, ThreadPoolStrategy Default = {});
+
+ /// Returns a thread strategy for tasks requiring significant memory or other
+ /// resources. To be used for workloads where hardware_concurrency() proves to
+ /// be less efficient. Avoid this strategy if doing lots of I/O. Currently
+ /// based on physical cores, if available for the host system, otherwise falls
+ /// back to hardware_concurrency(). Returns 1 when LLVM is configured with
+ /// LLVM_ENABLE_THREADS = OFF.
+ inline ThreadPoolStrategy
+ heavyweight_hardware_concurrency(unsigned ThreadCount = 0) {
+ ThreadPoolStrategy S;
+ S.UseHyperThreads = false;
+ S.ThreadsRequested = ThreadCount;
+ return S;
+ }
+
+ /// Like heavyweight_hardware_concurrency() above, but builds a strategy
+ /// based on the rules described for get_threadpool_strategy().
+ /// If \p Num is invalid, returns a default strategy where one thread per
+ /// hardware core is used.
+ inline ThreadPoolStrategy heavyweight_hardware_concurrency(StringRef Num) {
+ std::optional<ThreadPoolStrategy> S =
+ get_threadpool_strategy(Num, heavyweight_hardware_concurrency());
+ if (S)
+ return *S;
+ return heavyweight_hardware_concurrency();
+ }
+
+ /// Returns a default thread strategy where all available hardware resources
+ /// are to be used, except for those initially excluded by an affinity mask.
+ /// This function takes affinity into consideration. Returns 1 when LLVM is
+ /// configured with LLVM_ENABLE_THREADS=OFF.
+ inline ThreadPoolStrategy hardware_concurrency(unsigned ThreadCount = 0) {
+ ThreadPoolStrategy S;
+ S.ThreadsRequested = ThreadCount;
+ return S;
+ }
+
+ /// Returns an optimal thread strategy to execute specified amount of tasks.
+ /// This strategy should prevent us from creating too many threads if we
+ /// occasionaly have an unexpectedly small amount of tasks.
+ inline ThreadPoolStrategy optimal_concurrency(unsigned TaskCount = 0) {
+ ThreadPoolStrategy S;
+ S.Limit = true;
+ S.ThreadsRequested = TaskCount;
+ return S;
+ }
+
+ /// Return the current thread id, as used in various OS system calls.
+ /// Note that not all platforms guarantee that the value returned will be
+ /// unique across the entire system, so portable code should not assume
+ /// this.
+ uint64_t get_threadid();
+
+ /// Get the maximum length of a thread name on this platform.
+ /// A value of 0 means there is no limit.
+ uint32_t get_max_thread_name_length();
+
+ /// Set the name of the current thread. Setting a thread's name can
+ /// be helpful for enabling useful diagnostics under a debugger or when
+ /// logging. The level of support for setting a thread's name varies
+ /// wildly across operating systems, and we only make a best effort to
+ /// perform the operation on supported platforms. No indication of success
+ /// or failure is returned.
+ void set_thread_name(const Twine &Name);
+
+ /// Get the name of the current thread. The level of support for
+ /// getting a thread's name varies wildly across operating systems, and it
+ /// is not even guaranteed that if you can successfully set a thread's name
+ /// that you can later get it back. This function is intended for diagnostic
+ /// purposes, and as with setting a thread's name no indication of whether
+ /// the operation succeeded or failed is returned.
+ void get_thread_name(SmallVectorImpl<char> &Name);
+
+ /// Returns a mask that represents on which hardware thread, core, CPU, NUMA
+ /// group, the calling thread can be executed. On Windows, threads cannot
+ /// cross CPU sockets boundaries.
+ llvm::BitVector get_thread_affinity_mask();
+
+ /// Returns how many physical CPUs or NUMA groups the system has.
+ unsigned get_cpus();
+
+ /// Returns how many physical cores (as opposed to logical cores returned from
+ /// thread::hardware_concurrency(), which includes hyperthreads).
+ /// Returns -1 if unknown for the current host system.
+ int get_physical_cores();
+
+ enum class ThreadPriority {
+ /// Lower the current thread's priority as much as possible. Can be used
+ /// for long-running tasks that are not time critical; more energy-
+ /// efficient than Low.
+ Background = 0,
+
+ /// Lower the current thread's priority such that it does not affect
+ /// foreground tasks significantly. This is a good default for long-
+ /// running, latency-insensitive tasks to make sure cpu is not hogged
+ /// by this task.
+ Low = 1,
+
+ /// Restore the current thread's priority to default scheduling priority.
+ Default = 2,
+ };
+ enum class SetThreadPriorityResult { FAILURE, SUCCESS };
+ SetThreadPriorityResult set_thread_priority(ThreadPriority Priority);
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/TimeProfiler.h b/contrib/libs/llvm16/include/llvm/Support/TimeProfiler.h
new file mode 100644
index 00000000000..3acd8fe2c66
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/TimeProfiler.h
@@ -0,0 +1,173 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/TimeProfiler.h - Hierarchical Time Profiler -*- 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 provides lightweight and dependency-free machinery to trace execution
+// time around arbitrary code. Two API flavors are available.
+//
+// The primary API uses a RAII object to trigger tracing:
+//
+// \code
+// {
+// TimeTraceScope scope("my_event_name");
+// ...my code...
+// }
+// \endcode
+//
+// If the code to be profiled does not have a natural lexical scope then
+// it is also possible to start and end events with respect to an implicit
+// per-thread stack of profiling entries:
+//
+// \code
+// timeTraceProfilerBegin("my_event_name");
+// ...my code...
+// timeTraceProfilerEnd(); // must be called on all control flow paths
+// \endcode
+//
+// Time profiling entries can be given an arbitrary name and, optionally,
+// an arbitrary 'detail' string. The resulting trace will include 'Total'
+// entries summing the time spent for each name. Thus, it's best to choose
+// names to be fairly generic, and rely on the detail field to capture
+// everything else of interest.
+//
+// To avoid lifetime issues name and detail strings are copied into the event
+// entries at their time of creation. Care should be taken to make string
+// construction cheap to prevent 'Heisenperf' effects. In particular, the
+// 'detail' argument may be a string-returning closure:
+//
+// \code
+// int n;
+// {
+// TimeTraceScope scope("my_event_name",
+// [n]() { return (Twine("x=") + Twine(n)).str(); });
+// ...my code...
+// }
+// \endcode
+// The closure will not be called if tracing is disabled. Otherwise, the
+// resulting string will be directly moved into the entry.
+//
+// The main process should begin with a timeTraceProfilerInitialize, and
+// finish with timeTraceProfileWrite and timeTraceProfilerCleanup calls.
+// Each new thread should begin with a timeTraceProfilerInitialize, and
+// finish with a timeTraceProfilerFinishThread call.
+//
+// Timestamps come from std::chrono::stable_clock. Note that threads need
+// not see the same time from that clock, and the resolution may not be
+// the best available.
+//
+// Currently, there are a number of compatible viewers:
+// - chrome://tracing is the original chromium trace viewer.
+// - http://ui.perfetto.dev is the replacement for the above, under active
+// development by Google as part of the 'Perfetto' project.
+// - https://www.speedscope.app/ has also been reported as an option.
+//
+// Future work:
+// - Support akin to LLVM_DEBUG for runtime enable/disable of named tracing
+// families for non-debug builds which wish to support optional tracing.
+// - Evaluate the detail closures at profile write time to avoid
+// stringification costs interfering with tracing.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TIMEPROFILER_H
+#define LLVM_SUPPORT_TIMEPROFILER_H
+
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+
+class raw_pwrite_stream;
+
+struct TimeTraceProfiler;
+TimeTraceProfiler *getTimeTraceProfilerInstance();
+
+/// Initialize the time trace profiler.
+/// This sets up the global \p TimeTraceProfilerInstance
+/// variable to be the profiler instance.
+void timeTraceProfilerInitialize(unsigned TimeTraceGranularity,
+ StringRef ProcName);
+
+/// Cleanup the time trace profiler, if it was initialized.
+void timeTraceProfilerCleanup();
+
+/// Finish a time trace profiler running on a worker thread.
+void timeTraceProfilerFinishThread();
+
+/// Is the time trace profiler enabled, i.e. initialized?
+inline bool timeTraceProfilerEnabled() {
+ return getTimeTraceProfilerInstance() != nullptr;
+}
+
+/// Write profiling data to output stream.
+/// Data produced is JSON, in Chrome "Trace Event" format, see
+/// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+void timeTraceProfilerWrite(raw_pwrite_stream &OS);
+
+/// Write profiling data to a file.
+/// The function will write to \p PreferredFileName if provided, if not
+/// then will write to \p FallbackFileName appending .time-trace.
+/// Returns a StringError indicating a failure if the function is
+/// unable to open the file for writing.
+Error timeTraceProfilerWrite(StringRef PreferredFileName,
+ StringRef FallbackFileName);
+
+/// Manually begin a time section, with the given \p Name and \p Detail.
+/// Profiler copies the string data, so the pointers can be given into
+/// temporaries. Time sections can be hierarchical; every Begin must have a
+/// matching End pair but they can nest.
+void timeTraceProfilerBegin(StringRef Name, StringRef Detail);
+void timeTraceProfilerBegin(StringRef Name,
+ llvm::function_ref<std::string()> Detail);
+
+/// Manually end the last time section.
+void timeTraceProfilerEnd();
+
+/// The TimeTraceScope is a helper class to call the begin and end functions
+/// of the time trace profiler. When the object is constructed, it begins
+/// the section; and when it is destroyed, it stops it. If the time profiler
+/// is not initialized, the overhead is a single branch.
+struct TimeTraceScope {
+
+ TimeTraceScope() = delete;
+ TimeTraceScope(const TimeTraceScope &) = delete;
+ TimeTraceScope &operator=(const TimeTraceScope &) = delete;
+ TimeTraceScope(TimeTraceScope &&) = delete;
+ TimeTraceScope &operator=(TimeTraceScope &&) = delete;
+
+ TimeTraceScope(StringRef Name) {
+ if (getTimeTraceProfilerInstance() != nullptr)
+ timeTraceProfilerBegin(Name, StringRef(""));
+ }
+ TimeTraceScope(StringRef Name, StringRef Detail) {
+ if (getTimeTraceProfilerInstance() != nullptr)
+ timeTraceProfilerBegin(Name, Detail);
+ }
+ TimeTraceScope(StringRef Name, llvm::function_ref<std::string()> Detail) {
+ if (getTimeTraceProfilerInstance() != nullptr)
+ timeTraceProfilerBegin(Name, Detail);
+ }
+ ~TimeTraceScope() {
+ if (getTimeTraceProfilerInstance() != nullptr)
+ timeTraceProfilerEnd();
+ }
+};
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Timer.h b/contrib/libs/llvm16/include/llvm/Support/Timer.h
new file mode 100644
index 00000000000..4e5e0be25ca
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Timer.h
@@ -0,0 +1,267 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/Timer.h - Interval Timing Support ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TIMER_H
+#define LLVM_SUPPORT_TIMER_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace llvm {
+
+class TimerGroup;
+class raw_ostream;
+
+class TimeRecord {
+ double WallTime; ///< Wall clock time elapsed in seconds.
+ double UserTime; ///< User time elapsed.
+ double SystemTime; ///< System time elapsed.
+ ssize_t MemUsed; ///< Memory allocated (in bytes).
+ uint64_t InstructionsExecuted; ///< Number of instructions executed
+public:
+ TimeRecord()
+ : WallTime(0), UserTime(0), SystemTime(0), MemUsed(0),
+ InstructionsExecuted(0) {}
+
+ /// Get the current time and memory usage. If Start is true we get the memory
+ /// usage before the time, otherwise we get time before memory usage. This
+ /// matters if the time to get the memory usage is significant and shouldn't
+ /// be counted as part of a duration.
+ static TimeRecord getCurrentTime(bool Start = true);
+
+ double getProcessTime() const { return UserTime + SystemTime; }
+ double getUserTime() const { return UserTime; }
+ double getSystemTime() const { return SystemTime; }
+ double getWallTime() const { return WallTime; }
+ ssize_t getMemUsed() const { return MemUsed; }
+ uint64_t getInstructionsExecuted() const { return InstructionsExecuted; }
+
+ bool operator<(const TimeRecord &T) const {
+ // Sort by Wall Time elapsed, as it is the only thing really accurate
+ return WallTime < T.WallTime;
+ }
+
+ void operator+=(const TimeRecord &RHS) {
+ WallTime += RHS.WallTime;
+ UserTime += RHS.UserTime;
+ SystemTime += RHS.SystemTime;
+ MemUsed += RHS.MemUsed;
+ InstructionsExecuted += RHS.InstructionsExecuted;
+ }
+ void operator-=(const TimeRecord &RHS) {
+ WallTime -= RHS.WallTime;
+ UserTime -= RHS.UserTime;
+ SystemTime -= RHS.SystemTime;
+ MemUsed -= RHS.MemUsed;
+ InstructionsExecuted -= RHS.InstructionsExecuted;
+ }
+
+ /// Print the current time record to \p OS, with a breakdown showing
+ /// contributions to the \p Total time record.
+ void print(const TimeRecord &Total, raw_ostream &OS) const;
+};
+
+/// This class is used to track the amount of time spent between invocations of
+/// its startTimer()/stopTimer() methods. Given appropriate OS support it can
+/// also keep track of the RSS of the program at various points. By default,
+/// the Timer will print the amount of time it has captured to standard error
+/// when the last timer is destroyed, otherwise it is printed when its
+/// TimerGroup is destroyed. Timers do not print their information if they are
+/// never started.
+class Timer {
+ TimeRecord Time; ///< The total time captured.
+ TimeRecord StartTime; ///< The time startTimer() was last called.
+ std::string Name; ///< The name of this time variable.
+ std::string Description; ///< Description of this time variable.
+ bool Running = false; ///< Is the timer currently running?
+ bool Triggered = false; ///< Has the timer ever been triggered?
+ TimerGroup *TG = nullptr; ///< The TimerGroup this Timer is in.
+
+ Timer **Prev = nullptr; ///< Pointer to \p Next of previous timer in group.
+ Timer *Next = nullptr; ///< Next timer in the group.
+public:
+ explicit Timer(StringRef TimerName, StringRef TimerDescription) {
+ init(TimerName, TimerDescription);
+ }
+ Timer(StringRef TimerName, StringRef TimerDescription, TimerGroup &tg) {
+ init(TimerName, TimerDescription, tg);
+ }
+ Timer(const Timer &RHS) {
+ assert(!RHS.TG && "Can only copy uninitialized timers");
+ }
+ const Timer &operator=(const Timer &T) {
+ assert(!TG && !T.TG && "Can only assign uninit timers");
+ return *this;
+ }
+ ~Timer();
+
+ /// Create an uninitialized timer, client must use 'init'.
+ explicit Timer() = default;
+ void init(StringRef TimerName, StringRef TimerDescription);
+ void init(StringRef TimerName, StringRef TimerDescription, TimerGroup &tg);
+
+ const std::string &getName() const { return Name; }
+ const std::string &getDescription() const { return Description; }
+ bool isInitialized() const { return TG != nullptr; }
+
+ /// Check if the timer is currently running.
+ bool isRunning() const { return Running; }
+
+ /// Check if startTimer() has ever been called on this timer.
+ bool hasTriggered() const { return Triggered; }
+
+ /// Start the timer running. Time between calls to startTimer/stopTimer is
+ /// counted by the Timer class. Note that these calls must be correctly
+ /// paired.
+ void startTimer();
+
+ /// Stop the timer.
+ void stopTimer();
+
+ /// Clear the timer state.
+ void clear();
+
+ /// Return the duration for which this timer has been running.
+ TimeRecord getTotalTime() const { return Time; }
+
+private:
+ friend class TimerGroup;
+};
+
+/// The TimeRegion class is used as a helper class to call the startTimer() and
+/// stopTimer() methods of the Timer class. When the object is constructed, it
+/// starts the timer specified as its argument. When it is destroyed, it stops
+/// the relevant timer. This makes it easy to time a region of code.
+class TimeRegion {
+ Timer *T;
+ TimeRegion(const TimeRegion &) = delete;
+
+public:
+ explicit TimeRegion(Timer &t) : T(&t) {
+ T->startTimer();
+ }
+ explicit TimeRegion(Timer *t) : T(t) {
+ if (T) T->startTimer();
+ }
+ ~TimeRegion() {
+ if (T) T->stopTimer();
+ }
+};
+
+/// This class is basically a combination of TimeRegion and Timer. It allows
+/// you to declare a new timer, AND specify the region to time, all in one
+/// statement. All timers with the same name are merged. This is primarily
+/// used for debugging and for hunting performance problems.
+struct NamedRegionTimer : public TimeRegion {
+ explicit NamedRegionTimer(StringRef Name, StringRef Description,
+ StringRef GroupName,
+ StringRef GroupDescription, bool Enabled = true);
+};
+
+/// The TimerGroup class is used to group together related timers into a single
+/// report that is printed when the TimerGroup is destroyed. It is illegal to
+/// destroy a TimerGroup object before all of the Timers in it are gone. A
+/// TimerGroup can be specified for a newly created timer in its constructor.
+class TimerGroup {
+ struct PrintRecord {
+ TimeRecord Time;
+ std::string Name;
+ std::string Description;
+
+ PrintRecord(const PrintRecord &Other) = default;
+ PrintRecord &operator=(const PrintRecord &Other) = default;
+ PrintRecord(const TimeRecord &Time, const std::string &Name,
+ const std::string &Description)
+ : Time(Time), Name(Name), Description(Description) {}
+
+ bool operator <(const PrintRecord &Other) const {
+ return Time < Other.Time;
+ }
+ };
+ std::string Name;
+ std::string Description;
+ Timer *FirstTimer = nullptr; ///< First timer in the group.
+ std::vector<PrintRecord> TimersToPrint;
+
+ TimerGroup **Prev; ///< Pointer to Next field of previous timergroup in list.
+ TimerGroup *Next; ///< Pointer to next timergroup in list.
+ TimerGroup(const TimerGroup &TG) = delete;
+ void operator=(const TimerGroup &TG) = delete;
+
+public:
+ explicit TimerGroup(StringRef Name, StringRef Description);
+
+ explicit TimerGroup(StringRef Name, StringRef Description,
+ const StringMap<TimeRecord> &Records);
+
+ ~TimerGroup();
+
+ void setName(StringRef NewName, StringRef NewDescription) {
+ Name.assign(NewName.begin(), NewName.end());
+ Description.assign(NewDescription.begin(), NewDescription.end());
+ }
+
+ /// Print any started timers in this group, optionally resetting timers after
+ /// printing them.
+ void print(raw_ostream &OS, bool ResetAfterPrint = false);
+
+ /// Clear all timers in this group.
+ void clear();
+
+ /// This static method prints all timers.
+ static void printAll(raw_ostream &OS);
+
+ /// Clear out all timers. This is mostly used to disable automatic
+ /// printing on shutdown, when timers have already been printed explicitly
+ /// using \c printAll or \c printJSONValues.
+ static void clearAll();
+
+ const char *printJSONValues(raw_ostream &OS, const char *delim);
+
+ /// Prints all timers as JSON key/value pairs.
+ static const char *printAllJSONValues(raw_ostream &OS, const char *delim);
+
+ /// Ensure global objects required for statistics printing are initialized.
+ /// This function is used by the Statistic code to ensure correct order of
+ /// global constructors and destructors.
+ static void constructForStatistics();
+
+ /// This makes the default group unmanaged, and lets the user manage the
+ /// group's lifetime.
+ static std::unique_ptr<TimerGroup> aquireDefaultGroup();
+
+private:
+ friend class Timer;
+ friend void PrintStatisticsJSON(raw_ostream &OS);
+ void addTimer(Timer &T);
+ void removeTimer(Timer &T);
+ void prepareToPrintList(bool reset_time = false);
+ void PrintQueuedTimers(raw_ostream &OS);
+ void printJSONValue(raw_ostream &OS, const PrintRecord &R,
+ const char *suffix, double Value);
+};
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/ToolOutputFile.h b/contrib/libs/llvm16/include/llvm/Support/ToolOutputFile.h
new file mode 100644
index 00000000000..91d0d5ad500
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/ToolOutputFile.h
@@ -0,0 +1,85 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- ToolOutputFile.h - Output files for compiler-like tools --*- 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 defines the ToolOutputFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TOOLOUTPUTFILE_H
+#define LLVM_SUPPORT_TOOLOUTPUTFILE_H
+
+#include "llvm/Support/raw_ostream.h"
+#include <optional>
+
+namespace llvm {
+
+/// This class contains a raw_fd_ostream and adds a few extra features commonly
+/// needed for compiler-like tool output files:
+/// - The file is automatically deleted if the process is killed.
+/// - The file is automatically deleted when the ToolOutputFile
+/// object is destroyed unless the client calls keep().
+class ToolOutputFile {
+ /// This class is declared before the raw_fd_ostream so that it is constructed
+ /// before the raw_fd_ostream is constructed and destructed after the
+ /// raw_fd_ostream is destructed. It installs cleanups in its constructor and
+ /// uninstalls them in its destructor.
+ class CleanupInstaller {
+ public:
+ /// The name of the file.
+ std::string Filename;
+
+ /// The flag which indicates whether we should not delete the file.
+ bool Keep;
+
+ StringRef getFilename() { return Filename; }
+ explicit CleanupInstaller(StringRef Filename);
+ ~CleanupInstaller();
+ } Installer;
+
+ /// Storage for the stream, if we're owning our own stream. This is
+ /// intentionally declared after Installer.
+ std::optional<raw_fd_ostream> OSHolder;
+
+ /// The actual stream to use.
+ raw_fd_ostream *OS;
+
+public:
+ /// This constructor's arguments are passed to raw_fd_ostream's
+ /// constructor.
+ ToolOutputFile(StringRef Filename, std::error_code &EC,
+ sys::fs::OpenFlags Flags);
+
+ ToolOutputFile(StringRef Filename, int FD);
+
+ /// Return the contained raw_fd_ostream.
+ raw_fd_ostream &os() { return *OS; }
+
+ /// Return the filename initialized with.
+ StringRef getFilename() { return Installer.getFilename(); }
+
+ /// Indicate that the tool's job wrt this output file has been successful and
+ /// the file should not be deleted.
+ void keep() { Installer.Keep = true; }
+
+ const std::string &outputFilename() { return Installer.Filename; }
+};
+
+} // end llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/TrailingObjects.h b/contrib/libs/llvm16/include/llvm/Support/TrailingObjects.h
new file mode 100644
index 00000000000..871f69c6e2e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/TrailingObjects.h
@@ -0,0 +1,396 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- TrailingObjects.h - Variable-length classes ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This header defines support for implementing classes that have
+/// some trailing object (or arrays of objects) appended to them. The
+/// main purpose is to make it obvious where this idiom is being used,
+/// and to make the usage more idiomatic and more difficult to get
+/// wrong.
+///
+/// The TrailingObject template abstracts away the reinterpret_cast,
+/// pointer arithmetic, and size calculations used for the allocation
+/// and access of appended arrays of objects, and takes care that they
+/// are all allocated at their required alignment. Additionally, it
+/// ensures that the base type is final -- deriving from a class that
+/// expects data appended immediately after it is typically not safe.
+///
+/// Users are expected to derive from this template, and provide
+/// numTrailingObjects implementations for each trailing type except
+/// the last, e.g. like this sample:
+///
+/// \code
+/// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> {
+/// friend TrailingObjects;
+///
+/// unsigned NumInts, NumDoubles;
+/// size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; }
+/// };
+/// \endcode
+///
+/// You can access the appended arrays via 'getTrailingObjects', and
+/// determine the size needed for allocation via
+/// 'additionalSizeToAlloc' and 'totalSizeToAlloc'.
+///
+/// All the methods implemented by this class are are intended for use
+/// by the implementation of the class, not as part of its interface
+/// (thus, private inheritance is suggested).
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H
+#define LLVM_SUPPORT_TRAILINGOBJECTS_H
+
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/type_traits.h"
+#include <new>
+#include <type_traits>
+
+namespace llvm {
+
+namespace trailing_objects_internal {
+/// Helper template to calculate the max alignment requirement for a set of
+/// objects.
+template <typename First, typename... Rest> class AlignmentCalcHelper {
+private:
+ enum {
+ FirstAlignment = alignof(First),
+ RestAlignment = AlignmentCalcHelper<Rest...>::Alignment,
+ };
+
+public:
+ enum {
+ Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment
+ };
+};
+
+template <typename First> class AlignmentCalcHelper<First> {
+public:
+ enum { Alignment = alignof(First) };
+};
+
+/// The base class for TrailingObjects* classes.
+class TrailingObjectsBase {
+protected:
+ /// OverloadToken's purpose is to allow specifying function overloads
+ /// for different types, without actually taking the types as
+ /// parameters. (Necessary because member function templates cannot
+ /// be specialized, so overloads must be used instead of
+ /// specialization.)
+ template <typename T> struct OverloadToken {};
+};
+
+// Just a little helper for transforming a type pack into the same
+// number of a different type. e.g.:
+// ExtractSecondType<Foo..., int>::type
+template <typename Ty1, typename Ty2> struct ExtractSecondType {
+ typedef Ty2 type;
+};
+
+// TrailingObjectsImpl is somewhat complicated, because it is a
+// recursively inheriting template, in order to handle the template
+// varargs. Each level of inheritance picks off a single trailing type
+// then recurses on the rest. The "Align", "BaseTy", and
+// "TopTrailingObj" arguments are passed through unchanged through the
+// recursion. "PrevTy" is, at each level, the type handled by the
+// level right above it.
+
+template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
+ typename... MoreTys>
+class TrailingObjectsImpl {
+ // The main template definition is never used -- the two
+ // specializations cover all possibilities.
+};
+
+template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
+ typename NextTy, typename... MoreTys>
+class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
+ MoreTys...>
+ : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
+ MoreTys...> {
+
+ typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...>
+ ParentType;
+
+ struct RequiresRealignment {
+ static const bool value = alignof(PrevTy) < alignof(NextTy);
+ };
+
+ static constexpr bool requiresRealignment() {
+ return RequiresRealignment::value;
+ }
+
+protected:
+ // Ensure the inherited getTrailingObjectsImpl is not hidden.
+ using ParentType::getTrailingObjectsImpl;
+
+ // These two functions are helper functions for
+ // TrailingObjects::getTrailingObjects. They recurse to the left --
+ // the result for each type in the list of trailing types depends on
+ // the result of calling the function on the type to the
+ // left. However, the function for the type to the left is
+ // implemented by a *subclass* of this class, so we invoke it via
+ // the TopTrailingObj, which is, via the
+ // curiously-recurring-template-pattern, the most-derived type in
+ // this recursion, and thus, contains all the overloads.
+ static const NextTy *
+ getTrailingObjectsImpl(const BaseTy *Obj,
+ TrailingObjectsBase::OverloadToken<NextTy>) {
+ auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
+ Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
+ TopTrailingObj::callNumTrailingObjects(
+ Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
+
+ if (requiresRealignment())
+ return reinterpret_cast<const NextTy *>(
+ alignAddr(Ptr, Align::Of<NextTy>()));
+ else
+ return reinterpret_cast<const NextTy *>(Ptr);
+ }
+
+ static NextTy *
+ getTrailingObjectsImpl(BaseTy *Obj,
+ TrailingObjectsBase::OverloadToken<NextTy>) {
+ auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
+ Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
+ TopTrailingObj::callNumTrailingObjects(
+ Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
+
+ if (requiresRealignment())
+ return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>()));
+ else
+ return reinterpret_cast<NextTy *>(Ptr);
+ }
+
+ // Helper function for TrailingObjects::additionalSizeToAlloc: this
+ // function recurses to superclasses, each of which requires one
+ // fewer size_t argument, and adds its own size.
+ static constexpr size_t additionalSizeToAllocImpl(
+ size_t SizeSoFar, size_t Count1,
+ typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
+ return ParentType::additionalSizeToAllocImpl(
+ (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar)
+ : SizeSoFar) +
+ sizeof(NextTy) * Count1,
+ MoreCounts...);
+ }
+};
+
+// The base case of the TrailingObjectsImpl inheritance recursion,
+// when there's no more trailing types.
+template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
+class alignas(Align) TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
+ : public TrailingObjectsBase {
+protected:
+ // This is a dummy method, only here so the "using" doesn't fail --
+ // it will never be called, because this function recurses backwards
+ // up the inheritance chain to subclasses.
+ static void getTrailingObjectsImpl();
+
+ static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) {
+ return SizeSoFar;
+ }
+
+ template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {}
+};
+
+} // end namespace trailing_objects_internal
+
+// Finally, the main type defined in this file, the one intended for users...
+
+/// See the file comment for details on the usage of the
+/// TrailingObjects type.
+template <typename BaseTy, typename... TrailingTys>
+class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl<
+ trailing_objects_internal::AlignmentCalcHelper<
+ TrailingTys...>::Alignment,
+ BaseTy, TrailingObjects<BaseTy, TrailingTys...>,
+ BaseTy, TrailingTys...> {
+
+ template <int A, typename B, typename T, typename P, typename... M>
+ friend class trailing_objects_internal::TrailingObjectsImpl;
+
+ template <typename... Tys> class Foo {};
+
+ typedef trailing_objects_internal::TrailingObjectsImpl<
+ trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,
+ BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...>
+ ParentType;
+ using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase;
+
+ using ParentType::getTrailingObjectsImpl;
+
+ // This function contains only a static_assert BaseTy is final. The
+ // static_assert must be in a function, and not at class-level
+ // because BaseTy isn't complete at class instantiation time, but
+ // will be by the time this function is instantiated.
+ static void verifyTrailingObjectsAssertions() {
+ static_assert(std::is_final<BaseTy>(), "BaseTy must be final.");
+ }
+
+ // These two methods are the base of the recursion for this method.
+ static const BaseTy *
+ getTrailingObjectsImpl(const BaseTy *Obj,
+ TrailingObjectsBase::OverloadToken<BaseTy>) {
+ return Obj;
+ }
+
+ static BaseTy *
+ getTrailingObjectsImpl(BaseTy *Obj,
+ TrailingObjectsBase::OverloadToken<BaseTy>) {
+ return Obj;
+ }
+
+ // callNumTrailingObjects simply calls numTrailingObjects on the
+ // provided Obj -- except when the type being queried is BaseTy
+ // itself. There is always only one of the base object, so that case
+ // is handled here. (An additional benefit of indirecting through
+ // this function is that consumers only say "friend
+ // TrailingObjects", and thus, only this class itself can call the
+ // numTrailingObjects function.)
+ static size_t
+ callNumTrailingObjects(const BaseTy *Obj,
+ TrailingObjectsBase::OverloadToken<BaseTy>) {
+ return 1;
+ }
+
+ template <typename T>
+ static size_t callNumTrailingObjects(const BaseTy *Obj,
+ TrailingObjectsBase::OverloadToken<T>) {
+ return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>());
+ }
+
+public:
+ // Make this (privately inherited) member public.
+#ifndef _MSC_VER
+ using ParentType::OverloadToken;
+#else
+ // An MSVC bug prevents the above from working, (last tested at CL version
+ // 19.28). "Class5" in TrailingObjectsTest.cpp tests the problematic case.
+ template <typename T>
+ using OverloadToken = typename ParentType::template OverloadToken<T>;
+#endif
+
+ /// Returns a pointer to the trailing object array of the given type
+ /// (which must be one of those specified in the class template). The
+ /// array may have zero or more elements in it.
+ template <typename T> const T *getTrailingObjects() const {
+ verifyTrailingObjectsAssertions();
+ // Forwards to an impl function with overloads, since member
+ // function templates can't be specialized.
+ return this->getTrailingObjectsImpl(
+ static_cast<const BaseTy *>(this),
+ TrailingObjectsBase::OverloadToken<T>());
+ }
+
+ /// Returns a pointer to the trailing object array of the given type
+ /// (which must be one of those specified in the class template). The
+ /// array may have zero or more elements in it.
+ template <typename T> T *getTrailingObjects() {
+ verifyTrailingObjectsAssertions();
+ // Forwards to an impl function with overloads, since member
+ // function templates can't be specialized.
+ return this->getTrailingObjectsImpl(
+ static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>());
+ }
+
+ /// Returns the size of the trailing data, if an object were
+ /// allocated with the given counts (The counts are in the same order
+ /// as the template arguments). This does not include the size of the
+ /// base object. The template arguments must be the same as those
+ /// used in the class; they are supplied here redundantly only so
+ /// that it's clear what the counts are counting in callers.
+ template <typename... Tys>
+ static constexpr std::enable_if_t<
+ std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>
+ additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<
+ TrailingTys, size_t>::type... Counts) {
+ return ParentType::additionalSizeToAllocImpl(0, Counts...);
+ }
+
+ /// Returns the total size of an object if it were allocated with the
+ /// given trailing object counts. This is the same as
+ /// additionalSizeToAlloc, except it *does* include the size of the base
+ /// object.
+ template <typename... Tys>
+ static constexpr std::enable_if_t<
+ std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>
+ totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<
+ TrailingTys, size_t>::type... Counts) {
+ return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
+ }
+
+ TrailingObjects() = default;
+ TrailingObjects(const TrailingObjects &) = delete;
+ TrailingObjects(TrailingObjects &&) = delete;
+ TrailingObjects &operator=(const TrailingObjects &) = delete;
+ TrailingObjects &operator=(TrailingObjects &&) = delete;
+
+ /// A type where its ::with_counts template member has a ::type member
+ /// suitable for use as uninitialized storage for an object with the given
+ /// trailing object counts. The template arguments are similar to those
+ /// of additionalSizeToAlloc.
+ ///
+ /// Use with FixedSizeStorageOwner, e.g.:
+ ///
+ /// \code{.cpp}
+ ///
+ /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage;
+ /// MyObj::FixedSizeStorageOwner
+ /// myStackObjOwner(new ((void *)&myStackObjStorage) MyObj);
+ /// MyObj *const myStackObjPtr = myStackObjOwner.get();
+ ///
+ /// \endcode
+ template <typename... Tys> struct FixedSizeStorage {
+ template <size_t... Counts> struct with_counts {
+ enum { Size = totalSizeToAlloc<Tys...>(Counts...) };
+ struct type {
+ alignas(BaseTy) char buffer[Size];
+ };
+ };
+ };
+
+ /// A type that acts as the owner for an object placed into fixed storage.
+ class FixedSizeStorageOwner {
+ public:
+ FixedSizeStorageOwner(BaseTy *p) : p(p) {}
+ ~FixedSizeStorageOwner() {
+ assert(p && "FixedSizeStorageOwner owns null?");
+ p->~BaseTy();
+ }
+
+ BaseTy *get() { return p; }
+ const BaseTy *get() const { return p; }
+
+ private:
+ FixedSizeStorageOwner(const FixedSizeStorageOwner &) = delete;
+ FixedSizeStorageOwner(FixedSizeStorageOwner &&) = delete;
+ FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete;
+ FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete;
+
+ BaseTy *const p;
+ };
+};
+
+} // end namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/TrigramIndex.h b/contrib/libs/llvm16/include/llvm/Support/TrigramIndex.h
new file mode 100644
index 00000000000..d8ad0884f6a
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/TrigramIndex.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- TrigramIndex.h - a heuristic for SpecialCaseList --------*- 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
+//===----------------------------------------------------------------------===//
+//
+// TrigramIndex implements a heuristic for SpecialCaseList that allows to
+// filter out ~99% incoming queries when all regular expressions in the
+// SpecialCaseList are simple wildcards with '*' and '.'. If rules are more
+// complicated, the check is defeated and it will always pass the queries to a
+// full regex.
+//
+// The basic idea is that in order for a wildcard to match a query, the query
+// needs to have all trigrams which occur in the wildcard. We create a trigram
+// index (trigram -> list of rules with it) and then count trigrams in the query
+// for each rule. If the count for one of the rules reaches the expected value,
+// the check passes the query to a regex. If none of the rules got enough
+// trigrams, the check tells that the query is definitely not matched by any
+// of the rules, and no regex matching is needed.
+// A similar idea was used in Google Code Search as described in the blog post:
+// https://swtch.com/~rsc/regexp/regexp4.html
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TRIGRAMINDEX_H
+#define LLVM_SUPPORT_TRIGRAMINDEX_H
+
+#include "llvm/ADT/SmallVector.h"
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace llvm {
+class StringRef;
+
+class TrigramIndex {
+ public:
+ /// Inserts a new Regex into the index.
+ void insert(const std::string &Regex);
+
+ /// Returns true, if special case list definitely does not have a line
+ /// that matches the query. Returns false, if it's not sure.
+ bool isDefinitelyOut(StringRef Query) const;
+
+ /// Returned true, iff the heuristic is defeated and not useful.
+ /// In this case isDefinitelyOut always returns false.
+ bool isDefeated() { return Defeated; }
+ private:
+ // If true, the rules are too complicated for the check to work, and full
+ // regex matching is needed for every rule.
+ bool Defeated = false;
+ // The minimum number of trigrams which should match for a rule to have a
+ // chance to match the query. The number of elements equals the number of
+ // regex rules in the SpecialCaseList.
+ std::vector<unsigned> Counts;
+ // Index holds a list of rules indices for each trigram. The same indices
+ // are used in Counts to store per-rule limits.
+ // If a trigram is too common (>4 rules with it), we stop tracking it,
+ // which increases the probability for a need to match using regex, but
+ // decreases the costs in the regular case.
+ std::unordered_map<unsigned, SmallVector<size_t, 4>> Index{256};
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_TRIGRAMINDEX_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/TypeName.h b/contrib/libs/llvm16/include/llvm/Support/TypeName.h
new file mode 100644
index 00000000000..5f993e83f51
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/TypeName.h
@@ -0,0 +1,75 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- TypeName.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TYPENAME_H
+#define LLVM_SUPPORT_TYPENAME_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+/// We provide a function which tries to compute the (demangled) name of a type
+/// statically.
+///
+/// This routine may fail on some platforms or for particularly unusual types.
+/// Do not use it for anything other than logging and debugging aids. It isn't
+/// portable or dependendable in any real sense.
+///
+/// The returned StringRef will point into a static storage duration string.
+/// However, it may not be null terminated and may be some strangely aligned
+/// inner substring of a larger string.
+template <typename DesiredTypeName>
+inline StringRef getTypeName() {
+#if defined(__clang__) || defined(__GNUC__)
+ StringRef Name = __PRETTY_FUNCTION__;
+
+ StringRef Key = "DesiredTypeName = ";
+ Name = Name.substr(Name.find(Key));
+ assert(!Name.empty() && "Unable to find the template parameter!");
+ Name = Name.drop_front(Key.size());
+
+ assert(Name.endswith("]") && "Name doesn't end in the substitution key!");
+ return Name.drop_back(1);
+#elif defined(_MSC_VER)
+ StringRef Name = __FUNCSIG__;
+
+ StringRef Key = "getTypeName<";
+ Name = Name.substr(Name.find(Key));
+ assert(!Name.empty() && "Unable to find the function name!");
+ Name = Name.drop_front(Key.size());
+
+ for (StringRef Prefix : {"class ", "struct ", "union ", "enum "})
+ if (Name.startswith(Prefix)) {
+ Name = Name.drop_front(Prefix.size());
+ break;
+ }
+
+ auto AnglePos = Name.rfind('>');
+ assert(AnglePos != StringRef::npos && "Unable to find the closing '>'!");
+ return Name.substr(0, AnglePos);
+#else
+ // No known technique for statically extracting a type name on this compiler.
+ // We return a string that is unlikely to look like any type in LLVM.
+ return "UNKNOWN_TYPE";
+#endif
+}
+
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/TypeSize.h b/contrib/libs/llvm16/include/llvm/Support/TypeSize.h
new file mode 100644
index 00000000000..64cd61d0a63
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/TypeSize.h
@@ -0,0 +1,451 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- TypeSize.h - Wrapper around type sizes -------------------*- 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 provides a struct that can be used to query the size of IR types
+// which may be scalable vectors. It provides convenience operators so that
+// it can be used in much the same way as a single scalar value.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TYPESIZE_H
+#define LLVM_SUPPORT_TYPESIZE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cstdint>
+#include <type_traits>
+
+namespace llvm {
+
+/// Reports a diagnostic message to indicate an invalid size request has been
+/// done on a scalable vector. This function may not return.
+void reportInvalidSizeRequest(const char *Msg);
+
+/// StackOffset holds a fixed and a scalable offset in bytes.
+class StackOffset {
+ int64_t Fixed = 0;
+ int64_t Scalable = 0;
+
+ StackOffset(int64_t Fixed, int64_t Scalable)
+ : Fixed(Fixed), Scalable(Scalable) {}
+
+public:
+ StackOffset() = default;
+ static StackOffset getFixed(int64_t Fixed) { return {Fixed, 0}; }
+ static StackOffset getScalable(int64_t Scalable) { return {0, Scalable}; }
+ static StackOffset get(int64_t Fixed, int64_t Scalable) {
+ return {Fixed, Scalable};
+ }
+
+ /// Returns the fixed component of the stack.
+ int64_t getFixed() const { return Fixed; }
+
+ /// Returns the scalable component of the stack.
+ int64_t getScalable() const { return Scalable; }
+
+ // Arithmetic operations.
+ StackOffset operator+(const StackOffset &RHS) const {
+ return {Fixed + RHS.Fixed, Scalable + RHS.Scalable};
+ }
+ StackOffset operator-(const StackOffset &RHS) const {
+ return {Fixed - RHS.Fixed, Scalable - RHS.Scalable};
+ }
+ StackOffset &operator+=(const StackOffset &RHS) {
+ Fixed += RHS.Fixed;
+ Scalable += RHS.Scalable;
+ return *this;
+ }
+ StackOffset &operator-=(const StackOffset &RHS) {
+ Fixed -= RHS.Fixed;
+ Scalable -= RHS.Scalable;
+ return *this;
+ }
+ StackOffset operator-() const { return {-Fixed, -Scalable}; }
+
+ // Equality comparisons.
+ bool operator==(const StackOffset &RHS) const {
+ return Fixed == RHS.Fixed && Scalable == RHS.Scalable;
+ }
+ bool operator!=(const StackOffset &RHS) const {
+ return Fixed != RHS.Fixed || Scalable != RHS.Scalable;
+ }
+
+ // The bool operator returns true iff any of the components is non zero.
+ explicit operator bool() const { return Fixed != 0 || Scalable != 0; }
+};
+
+namespace details {
+
+// Base class for ElementCount and TypeSize below.
+template <typename LeafTy, typename ValueTy> class FixedOrScalableQuantity {
+public:
+ using ScalarTy = ValueTy;
+
+protected:
+ ScalarTy Quantity = 0;
+ bool Scalable = false;
+
+ constexpr FixedOrScalableQuantity() = default;
+ constexpr FixedOrScalableQuantity(ScalarTy Quantity, bool Scalable)
+ : Quantity(Quantity), Scalable(Scalable) {}
+
+ friend constexpr LeafTy &operator+=(LeafTy &LHS, const LeafTy &RHS) {
+ assert(LHS.Scalable == RHS.Scalable && "Incompatible types");
+ LHS.Quantity += RHS.Quantity;
+ return LHS;
+ }
+
+ friend constexpr LeafTy &operator-=(LeafTy &LHS, const LeafTy &RHS) {
+ assert(LHS.Scalable == RHS.Scalable && "Incompatible types");
+ LHS.Quantity -= RHS.Quantity;
+ return LHS;
+ }
+
+ friend constexpr LeafTy &operator*=(LeafTy &LHS, ScalarTy RHS) {
+ LHS.Quantity *= RHS;
+ return LHS;
+ }
+
+ friend constexpr LeafTy operator+(const LeafTy &LHS, const LeafTy &RHS) {
+ LeafTy Copy = LHS;
+ return Copy += RHS;
+ }
+
+ friend constexpr LeafTy operator-(const LeafTy &LHS, const LeafTy &RHS) {
+ LeafTy Copy = LHS;
+ return Copy -= RHS;
+ }
+
+ friend constexpr LeafTy operator*(const LeafTy &LHS, ScalarTy RHS) {
+ LeafTy Copy = LHS;
+ return Copy *= RHS;
+ }
+
+ template <typename U = ScalarTy>
+ friend constexpr std::enable_if_t<std::is_signed<U>::value, LeafTy>
+ operator-(const LeafTy &LHS) {
+ LeafTy Copy = LHS;
+ return Copy *= -1;
+ }
+
+public:
+ constexpr bool operator==(const FixedOrScalableQuantity &RHS) const {
+ return Quantity == RHS.Quantity && Scalable == RHS.Scalable;
+ }
+
+ constexpr bool operator!=(const FixedOrScalableQuantity &RHS) const {
+ return Quantity != RHS.Quantity || Scalable != RHS.Scalable;
+ }
+
+ constexpr bool isZero() const { return Quantity == 0; }
+
+ constexpr bool isNonZero() const { return Quantity != 0; }
+
+ explicit operator bool() const { return isNonZero(); }
+
+ /// Add \p RHS to the underlying quantity.
+ constexpr LeafTy getWithIncrement(ScalarTy RHS) const {
+ return LeafTy::get(Quantity + RHS, Scalable);
+ }
+
+ /// Returns the minimum value this quantity can represent.
+ constexpr ScalarTy getKnownMinValue() const { return Quantity; }
+
+ /// Returns whether the quantity is scaled by a runtime quantity (vscale).
+ constexpr bool isScalable() const { return Scalable; }
+
+ /// A return value of true indicates we know at compile time that the number
+ /// of elements (vscale * Min) is definitely even. However, returning false
+ /// does not guarantee that the total number of elements is odd.
+ constexpr bool isKnownEven() const { return (getKnownMinValue() & 0x1) == 0; }
+
+ /// This function tells the caller whether the element count is known at
+ /// compile time to be a multiple of the scalar value RHS.
+ constexpr bool isKnownMultipleOf(ScalarTy RHS) const {
+ return getKnownMinValue() % RHS == 0;
+ }
+
+ // Return the minimum value with the assumption that the count is exact.
+ // Use in places where a scalable count doesn't make sense (e.g. non-vector
+ // types, or vectors in backends which don't support scalable vectors).
+ constexpr ScalarTy getFixedValue() const {
+ assert(!isScalable() &&
+ "Request for a fixed element count on a scalable object");
+ return getKnownMinValue();
+ }
+
+ // For some cases, quantity ordering between scalable and fixed quantity types
+ // cannot be determined at compile time, so such comparisons aren't allowed.
+ //
+ // e.g. <vscale x 2 x i16> could be bigger than <4 x i32> with a runtime
+ // vscale >= 5, equal sized with a vscale of 4, and smaller with
+ // a vscale <= 3.
+ //
+ // All the functions below make use of the fact vscale is always >= 1, which
+ // means that <vscale x 4 x i32> is guaranteed to be >= <4 x i32>, etc.
+
+ static constexpr bool isKnownLT(const FixedOrScalableQuantity &LHS,
+ const FixedOrScalableQuantity &RHS) {
+ if (!LHS.isScalable() || RHS.isScalable())
+ return LHS.getKnownMinValue() < RHS.getKnownMinValue();
+ return false;
+ }
+
+ static constexpr bool isKnownGT(const FixedOrScalableQuantity &LHS,
+ const FixedOrScalableQuantity &RHS) {
+ if (LHS.isScalable() || !RHS.isScalable())
+ return LHS.getKnownMinValue() > RHS.getKnownMinValue();
+ return false;
+ }
+
+ static constexpr bool isKnownLE(const FixedOrScalableQuantity &LHS,
+ const FixedOrScalableQuantity &RHS) {
+ if (!LHS.isScalable() || RHS.isScalable())
+ return LHS.getKnownMinValue() <= RHS.getKnownMinValue();
+ return false;
+ }
+
+ static constexpr bool isKnownGE(const FixedOrScalableQuantity &LHS,
+ const FixedOrScalableQuantity &RHS) {
+ if (LHS.isScalable() || !RHS.isScalable())
+ return LHS.getKnownMinValue() >= RHS.getKnownMinValue();
+ return false;
+ }
+
+ /// We do not provide the '/' operator here because division for polynomial
+ /// types does not work in the same way as for normal integer types. We can
+ /// only divide the minimum value (or coefficient) by RHS, which is not the
+ /// same as
+ /// (Min * Vscale) / RHS
+ /// The caller is recommended to use this function in combination with
+ /// isKnownMultipleOf(RHS), which lets the caller know if it's possible to
+ /// perform a lossless divide by RHS.
+ constexpr LeafTy divideCoefficientBy(ScalarTy RHS) const {
+ return LeafTy::get(getKnownMinValue() / RHS, isScalable());
+ }
+
+ constexpr LeafTy multiplyCoefficientBy(ScalarTy RHS) const {
+ return LeafTy::get(getKnownMinValue() * RHS, isScalable());
+ }
+
+ constexpr LeafTy coefficientNextPowerOf2() const {
+ return LeafTy::get(
+ static_cast<ScalarTy>(llvm::NextPowerOf2(getKnownMinValue())),
+ isScalable());
+ }
+
+ /// Returns true if there exists a value X where RHS.multiplyCoefficientBy(X)
+ /// will result in a value whose quantity matches our own.
+ constexpr bool
+ hasKnownScalarFactor(const FixedOrScalableQuantity &RHS) const {
+ return isScalable() == RHS.isScalable() &&
+ getKnownMinValue() % RHS.getKnownMinValue() == 0;
+ }
+
+ /// Returns a value X where RHS.multiplyCoefficientBy(X) will result in a
+ /// value whose quantity matches our own.
+ constexpr ScalarTy
+ getKnownScalarFactor(const FixedOrScalableQuantity &RHS) const {
+ assert(hasKnownScalarFactor(RHS) && "Expected RHS to be a known factor!");
+ return getKnownMinValue() / RHS.getKnownMinValue();
+ }
+
+ /// Printing function.
+ void print(raw_ostream &OS) const {
+ if (isScalable())
+ OS << "vscale x ";
+ OS << getKnownMinValue();
+ }
+};
+
+} // namespace details
+
+// Stores the number of elements for a type and whether this type is fixed
+// (N-Elements) or scalable (e.g., SVE).
+// - ElementCount::getFixed(1) : A scalar value.
+// - ElementCount::getFixed(2) : A vector type holding 2 values.
+// - ElementCount::getScalable(4) : A scalable vector type holding 4 values.
+class ElementCount
+ : public details::FixedOrScalableQuantity<ElementCount, unsigned> {
+ constexpr ElementCount(ScalarTy MinVal, bool Scalable)
+ : FixedOrScalableQuantity(MinVal, Scalable) {}
+
+ constexpr ElementCount(
+ const FixedOrScalableQuantity<ElementCount, unsigned> &V)
+ : FixedOrScalableQuantity(V) {}
+
+public:
+ constexpr ElementCount() : FixedOrScalableQuantity() {}
+
+ static constexpr ElementCount getFixed(ScalarTy MinVal) {
+ return ElementCount(MinVal, false);
+ }
+ static constexpr ElementCount getScalable(ScalarTy MinVal) {
+ return ElementCount(MinVal, true);
+ }
+ static constexpr ElementCount get(ScalarTy MinVal, bool Scalable) {
+ return ElementCount(MinVal, Scalable);
+ }
+
+ /// Exactly one element.
+ constexpr bool isScalar() const {
+ return !isScalable() && getKnownMinValue() == 1;
+ }
+ /// One or more elements.
+ constexpr bool isVector() const {
+ return (isScalable() && getKnownMinValue() != 0) || getKnownMinValue() > 1;
+ }
+};
+
+// Stores the size of a type. If the type is of fixed size, it will represent
+// the exact size. If the type is a scalable vector, it will represent the known
+// minimum size.
+class TypeSize : public details::FixedOrScalableQuantity<TypeSize, uint64_t> {
+ TypeSize(const FixedOrScalableQuantity<TypeSize, uint64_t> &V)
+ : FixedOrScalableQuantity(V) {}
+
+public:
+ constexpr TypeSize(ScalarTy Quantity, bool Scalable)
+ : FixedOrScalableQuantity(Quantity, Scalable) {}
+
+ static constexpr TypeSize getFixed(ScalarTy ExactSize) {
+ return TypeSize(ExactSize, false);
+ }
+ static constexpr TypeSize getScalable(ScalarTy MinimunSize) {
+ return TypeSize(MinimunSize, true);
+ }
+ static constexpr TypeSize get(ScalarTy Quantity, bool Scalable) {
+ return TypeSize(Quantity, Scalable);
+ }
+ static constexpr TypeSize Fixed(ScalarTy ExactSize) {
+ return TypeSize(ExactSize, false);
+ }
+ static constexpr TypeSize Scalable(ScalarTy MinimumSize) {
+ return TypeSize(MinimumSize, true);
+ }
+
+ LLVM_DEPRECATED("Use getFixedValue() instead", "getFixedValue")
+ constexpr ScalarTy getFixedSize() const { return getFixedValue(); }
+
+ LLVM_DEPRECATED("Use getKnownMinValue() instead", "getKnownMinValue")
+ constexpr ScalarTy getKnownMinSize() const { return getKnownMinValue(); }
+
+ // All code for this class below this point is needed because of the
+ // temporary implicit conversion to uint64_t. The operator overloads are
+ // needed because otherwise the conversion of the parent class
+ // UnivariateLinearPolyBase -> TypeSize is ambiguous.
+ // TODO: Remove the implicit conversion.
+
+ // Casts to a uint64_t if this is a fixed-width size.
+ //
+ // This interface is deprecated and will be removed in a future version
+ // of LLVM in favour of upgrading uses that rely on this implicit conversion
+ // to uint64_t. Calls to functions that return a TypeSize should use the
+ // proper interfaces to TypeSize.
+ // In practice this is mostly calls to MVT/EVT::getSizeInBits().
+ //
+ // To determine how to upgrade the code:
+ //
+ // if (<algorithm works for both scalable and fixed-width vectors>)
+ // use getKnownMinValue()
+ // else if (<algorithm works only for fixed-width vectors>) {
+ // if <algorithm can be adapted for both scalable and fixed-width vectors>
+ // update the algorithm and use getKnownMinValue()
+ // else
+ // bail out early for scalable vectors and use getFixedValue()
+ // }
+ operator ScalarTy() const;
+
+ // Additional operators needed to avoid ambiguous parses
+ // because of the implicit conversion hack.
+ friend constexpr TypeSize operator*(const TypeSize &LHS, const int RHS) {
+ return LHS * (ScalarTy)RHS;
+ }
+ friend constexpr TypeSize operator*(const TypeSize &LHS, const unsigned RHS) {
+ return LHS * (ScalarTy)RHS;
+ }
+ friend constexpr TypeSize operator*(const TypeSize &LHS, const int64_t RHS) {
+ return LHS * (ScalarTy)RHS;
+ }
+ friend constexpr TypeSize operator*(const int LHS, const TypeSize &RHS) {
+ return RHS * LHS;
+ }
+ friend constexpr TypeSize operator*(const unsigned LHS, const TypeSize &RHS) {
+ return RHS * LHS;
+ }
+ friend constexpr TypeSize operator*(const int64_t LHS, const TypeSize &RHS) {
+ return RHS * LHS;
+ }
+ friend constexpr TypeSize operator*(const uint64_t LHS, const TypeSize &RHS) {
+ return RHS * LHS;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Utilities
+//===----------------------------------------------------------------------===//
+
+/// Returns a TypeSize with a known minimum size that is the next integer
+/// (mod 2**64) that is greater than or equal to \p Quantity and is a multiple
+/// of \p Align. \p Align must be non-zero.
+///
+/// Similar to the alignTo functions in MathExtras.h
+inline constexpr TypeSize alignTo(TypeSize Size, uint64_t Align) {
+ assert(Align != 0u && "Align must be non-zero");
+ return {(Size.getKnownMinValue() + Align - 1) / Align * Align,
+ Size.isScalable()};
+}
+
+/// Stream operator function for `FixedOrScalableQuantity`.
+template <typename LeafTy, typename ScalarTy>
+inline raw_ostream &
+operator<<(raw_ostream &OS,
+ const details::FixedOrScalableQuantity<LeafTy, ScalarTy> &PS) {
+ PS.print(OS);
+ return OS;
+}
+
+template <> struct DenseMapInfo<ElementCount, void> {
+ static inline ElementCount getEmptyKey() {
+ return ElementCount::getScalable(~0U);
+ }
+ static inline ElementCount getTombstoneKey() {
+ return ElementCount::getFixed(~0U - 1);
+ }
+ static unsigned getHashValue(const ElementCount &EltCnt) {
+ unsigned HashVal = EltCnt.getKnownMinValue() * 37U;
+ if (EltCnt.isScalable())
+ return (HashVal - 1U);
+
+ return HashVal;
+ }
+ static bool isEqual(const ElementCount &LHS, const ElementCount &RHS) {
+ return LHS == RHS;
+ }
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_TYPESIZE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Unicode.h b/contrib/libs/llvm16/include/llvm/Support/Unicode.h
new file mode 100644
index 00000000000..6a0590d75bc
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Unicode.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Unicode.h - Unicode character properties -*- 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 defines functions that allow querying certain properties of Unicode
+// characters.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_UNICODE_H
+#define LLVM_SUPPORT_UNICODE_H
+
+#include "llvm/ADT/SmallString.h"
+#include <optional>
+#include <string>
+
+namespace llvm {
+class StringRef;
+
+namespace sys {
+namespace unicode {
+
+enum ColumnWidthErrors {
+ ErrorInvalidUTF8 = -2,
+ ErrorNonPrintableCharacter = -1
+};
+
+/// Determines if a character is likely to be displayed correctly on the
+/// terminal. Exact implementation would have to depend on the specific
+/// terminal, so we define the semantic that should be suitable for generic case
+/// of a terminal capable to output Unicode characters.
+///
+/// Printable codepoints are those in the categories L, M, N, P, S and Zs
+/// \return true if the character is considered printable.
+bool isPrintable(int UCS);
+
+// Formatting codepoints are codepoints in the Cf category.
+bool isFormatting(int UCS);
+
+/// Gets the number of positions the UTF8-encoded \p Text is likely to occupy
+/// when output on a terminal ("character width"). This depends on the
+/// implementation of the terminal, and there's no standard definition of
+/// character width.
+///
+/// The implementation defines it in a way that is expected to be compatible
+/// with a generic Unicode-capable terminal.
+///
+/// \return Character width:
+/// * ErrorNonPrintableCharacter (-1) if \p Text contains non-printable
+/// characters (as identified by isPrintable);
+/// * 0 for each non-spacing and enclosing combining mark;
+/// * 2 for each CJK character excluding halfwidth forms;
+/// * 1 for each of the remaining characters.
+int columnWidthUTF8(StringRef Text);
+
+/// Fold input unicode character according the Simple unicode case folding
+/// rules.
+int foldCharSimple(int C);
+
+/// Maps the name or the alias of a Unicode character to its associated
+/// codepoints.
+/// The names and aliases are derived from UnicodeData.txt and NameAliases.txt
+/// For compatibility with the semantics of named character escape sequences in
+/// C++, this mapping does an exact match sensitive to casing and spacing.
+/// \return The codepoint of the corresponding character, if any.
+std::optional<char32_t> nameToCodepointStrict(StringRef Name);
+
+struct LooseMatchingResult {
+ char32_t CodePoint;
+ SmallString<64> Name;
+};
+
+std::optional<LooseMatchingResult> nameToCodepointLooseMatching(StringRef Name);
+
+struct MatchForCodepointName {
+ std::string Name;
+ uint32_t Distance = 0;
+ char32_t Value = 0;
+};
+
+SmallVector<MatchForCodepointName>
+nearestMatchesForCodepointName(StringRef Pattern, std::size_t MaxMatchesCount);
+
+} // namespace unicode
+} // namespace sys
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/UnicodeCharRanges.h b/contrib/libs/llvm16/include/llvm/Support/UnicodeCharRanges.h
new file mode 100644
index 00000000000..2aaa878b600
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/UnicodeCharRanges.h
@@ -0,0 +1,114 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- UnicodeCharRanges.h - Types and functions for character ranges ---===//
+//
+// 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 LLVM_SUPPORT_UNICODECHARRANGES_H
+#define LLVM_SUPPORT_UNICODECHARRANGES_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+#define DEBUG_TYPE "unicode"
+
+namespace llvm {
+namespace sys {
+
+/// Represents a closed range of Unicode code points [Lower, Upper].
+struct UnicodeCharRange {
+ uint32_t Lower;
+ uint32_t Upper;
+};
+
+inline bool operator<(uint32_t Value, UnicodeCharRange Range) {
+ return Value < Range.Lower;
+}
+inline bool operator<(UnicodeCharRange Range, uint32_t Value) {
+ return Range.Upper < Value;
+}
+
+/// Holds a reference to an ordered array of UnicodeCharRange and allows
+/// to quickly check if a code point is contained in the set represented by this
+/// array.
+class UnicodeCharSet {
+public:
+ typedef ArrayRef<UnicodeCharRange> CharRanges;
+
+ /// Constructs a UnicodeCharSet instance from an array of
+ /// UnicodeCharRanges.
+ ///
+ /// Array pointed by \p Ranges should have the lifetime at least as long as
+ /// the UnicodeCharSet instance, and should not change. Array is validated by
+ /// the constructor, so it makes sense to create as few UnicodeCharSet
+ /// instances per each array of ranges, as possible.
+#ifdef NDEBUG
+
+ // FIXME: This could use constexpr + static_assert. This way we
+ // may get rid of NDEBUG in this header. Unfortunately there are some
+ // problems to get this working with MSVC 2013. Change this when
+ // the support for MSVC 2013 is dropped.
+ constexpr UnicodeCharSet(CharRanges Ranges) : Ranges(Ranges) {}
+#else
+ UnicodeCharSet(CharRanges Ranges) : Ranges(Ranges) {
+ assert(rangesAreValid());
+ }
+#endif
+
+ /// Returns true if the character set contains the Unicode code point
+ /// \p C.
+ bool contains(uint32_t C) const {
+ return std::binary_search(Ranges.begin(), Ranges.end(), C);
+ }
+
+private:
+ /// Returns true if each of the ranges is a proper closed range
+ /// [min, max], and if the ranges themselves are ordered and non-overlapping.
+ bool rangesAreValid() const {
+ uint32_t Prev = 0;
+ for (CharRanges::const_iterator I = Ranges.begin(), E = Ranges.end();
+ I != E; ++I) {
+ if (I != Ranges.begin() && Prev >= I->Lower) {
+ LLVM_DEBUG(dbgs() << "Upper bound 0x");
+ LLVM_DEBUG(dbgs().write_hex(Prev));
+ LLVM_DEBUG(dbgs() << " should be less than succeeding lower bound 0x");
+ LLVM_DEBUG(dbgs().write_hex(I->Lower) << "\n");
+ return false;
+ }
+ if (I->Upper < I->Lower) {
+ LLVM_DEBUG(dbgs() << "Upper bound 0x");
+ LLVM_DEBUG(dbgs().write_hex(I->Lower));
+ LLVM_DEBUG(dbgs() << " should not be less than lower bound 0x");
+ LLVM_DEBUG(dbgs().write_hex(I->Upper) << "\n");
+ return false;
+ }
+ Prev = I->Upper;
+ }
+
+ return true;
+ }
+
+ const CharRanges Ranges;
+};
+
+} // namespace sys
+} // namespace llvm
+
+#undef DEBUG_TYPE // "unicode"
+
+#endif // LLVM_SUPPORT_UNICODECHARRANGES_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/VCSRevision.h b/contrib/libs/llvm16/include/llvm/Support/VCSRevision.h
new file mode 100644
index 00000000000..c4940ef5ffe
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/VCSRevision.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+#undef LLVM_REVISION
+#undef LLVM_REPOSITORY
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Valgrind.h b/contrib/libs/llvm16/include/llvm/Support/Valgrind.h
new file mode 100644
index 00000000000..15c6803100d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Valgrind.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/Valgrind.h - Communication with Valgrind ----*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Methods for communicating with a valgrind instance this program is running
+// under. These are all no-ops unless LLVM was configured on a system with the
+// valgrind headers installed and valgrind is controlling this process.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_VALGRIND_H
+#define LLVM_SUPPORT_VALGRIND_H
+
+#include <cstddef>
+
+namespace llvm {
+namespace sys {
+ // True if Valgrind is controlling this process.
+ bool RunningOnValgrind();
+
+ // Discard valgrind's translation of code in the range [Addr .. Addr + Len).
+ // Otherwise valgrind may continue to execute the old version of the code.
+ void ValgrindDiscardTranslations(const void *Addr, size_t Len);
+} // namespace sys
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_VALGRIND_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/VersionTuple.h b/contrib/libs/llvm16/include/llvm/Support/VersionTuple.h
new file mode 100644
index 00000000000..a0e442498e4
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/VersionTuple.h
@@ -0,0 +1,230 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the llvm::VersionTuple class, which represents a version in
+/// the form major[.minor[.subminor]].
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_SUPPORT_VERSIONTUPLE_H
+#define LLVM_SUPPORT_VERSIONTUPLE_H
+
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/Support/Endian.h"
+#include <optional>
+#include <string>
+#include <tuple>
+
+namespace llvm {
+template <typename HasherT, support::endianness Endianness>
+class HashBuilderImpl;
+class raw_ostream;
+class StringRef;
+
+/// Represents a version number in the form major[.minor[.subminor[.build]]].
+class VersionTuple {
+ unsigned Major : 32;
+
+ unsigned Minor : 31;
+ unsigned HasMinor : 1;
+
+ unsigned Subminor : 31;
+ unsigned HasSubminor : 1;
+
+ unsigned Build : 31;
+ unsigned HasBuild : 1;
+
+public:
+ constexpr VersionTuple()
+ : Major(0), Minor(0), HasMinor(false), Subminor(0), HasSubminor(false),
+ Build(0), HasBuild(false) {}
+
+ explicit constexpr VersionTuple(unsigned Major)
+ : Major(Major), Minor(0), HasMinor(false), Subminor(0),
+ HasSubminor(false), Build(0), HasBuild(false) {}
+
+ explicit constexpr VersionTuple(unsigned Major, unsigned Minor)
+ : Major(Major), Minor(Minor), HasMinor(true), Subminor(0),
+ HasSubminor(false), Build(0), HasBuild(false) {}
+
+ explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
+ unsigned Subminor)
+ : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
+ HasSubminor(true), Build(0), HasBuild(false) {}
+
+ explicit constexpr VersionTuple(unsigned Major, unsigned Minor,
+ unsigned Subminor, unsigned Build)
+ : Major(Major), Minor(Minor), HasMinor(true), Subminor(Subminor),
+ HasSubminor(true), Build(Build), HasBuild(true) {}
+
+ /// Determine whether this version information is empty
+ /// (e.g., all version components are zero).
+ bool empty() const {
+ return Major == 0 && Minor == 0 && Subminor == 0 && Build == 0;
+ }
+
+ /// Retrieve the major version number.
+ unsigned getMajor() const { return Major; }
+
+ /// Retrieve the minor version number, if provided.
+ std::optional<unsigned> getMinor() const {
+ if (!HasMinor)
+ return std::nullopt;
+ return Minor;
+ }
+
+ /// Retrieve the subminor version number, if provided.
+ std::optional<unsigned> getSubminor() const {
+ if (!HasSubminor)
+ return std::nullopt;
+ return Subminor;
+ }
+
+ /// Retrieve the build version number, if provided.
+ std::optional<unsigned> getBuild() const {
+ if (!HasBuild)
+ return std::nullopt;
+ return Build;
+ }
+
+ /// Return a version tuple that contains only the first 3 version components.
+ VersionTuple withoutBuild() const {
+ if (HasBuild)
+ return VersionTuple(Major, Minor, Subminor);
+ return *this;
+ }
+
+ /// Return a version tuple that contains a different major version but
+ /// everything else is the same.
+ VersionTuple withMajorReplaced(unsigned NewMajor) const {
+ return VersionTuple(NewMajor, Minor, Subminor, Build);
+ }
+
+ /// Return a version tuple that contains only components that are non-zero.
+ VersionTuple normalize() const {
+ VersionTuple Result = *this;
+ if (Result.Build == 0) {
+ Result.HasBuild = false;
+ if (Result.Subminor == 0) {
+ Result.HasSubminor = false;
+ if (Result.Minor == 0)
+ Result.HasMinor = false;
+ }
+ }
+ return Result;
+ }
+
+ /// Determine if two version numbers are equivalent. If not
+ /// provided, minor and subminor version numbers are considered to be zero.
+ friend bool operator==(const VersionTuple &X, const VersionTuple &Y) {
+ return X.Major == Y.Major && X.Minor == Y.Minor &&
+ X.Subminor == Y.Subminor && X.Build == Y.Build;
+ }
+
+ /// Determine if two version numbers are not equivalent.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(X == Y);
+ }
+
+ /// Determine whether one version number precedes another.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator<(const VersionTuple &X, const VersionTuple &Y) {
+ return std::tie(X.Major, X.Minor, X.Subminor, X.Build) <
+ std::tie(Y.Major, Y.Minor, Y.Subminor, Y.Build);
+ }
+
+ /// Determine whether one version number follows another.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator>(const VersionTuple &X, const VersionTuple &Y) {
+ return Y < X;
+ }
+
+ /// Determine whether one version number precedes or is
+ /// equivalent to another.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(Y < X);
+ }
+
+ /// Determine whether one version number follows or is
+ /// equivalent to another.
+ ///
+ /// If not provided, minor and subminor version numbers are considered to be
+ /// zero.
+ friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) {
+ return !(X < Y);
+ }
+
+ friend hash_code hash_value(const VersionTuple &VT) {
+ return hash_combine(VT.Major, VT.Minor, VT.Subminor, VT.Build);
+ }
+
+ template <typename HasherT, llvm::support::endianness Endianness>
+ friend void addHash(HashBuilderImpl<HasherT, Endianness> &HBuilder,
+ const VersionTuple &VT) {
+ HBuilder.add(VT.Major, VT.Minor, VT.Subminor, VT.Build);
+ }
+
+ /// Retrieve a string representation of the version number.
+ std::string getAsString() const;
+
+ /// Try to parse the given string as a version number.
+ /// \returns \c true if the string does not match the regular expression
+ /// [0-9]+(\.[0-9]+){0,3}
+ bool tryParse(StringRef string);
+};
+
+/// Print a version number.
+raw_ostream &operator<<(raw_ostream &Out, const VersionTuple &V);
+
+// Provide DenseMapInfo for version tuples.
+template <> struct DenseMapInfo<VersionTuple> {
+ static inline VersionTuple getEmptyKey() { return VersionTuple(0x7FFFFFFF); }
+ static inline VersionTuple getTombstoneKey() {
+ return VersionTuple(0x7FFFFFFE);
+ }
+ static unsigned getHashValue(const VersionTuple &Value) {
+ unsigned Result = Value.getMajor();
+ if (auto Minor = Value.getMinor())
+ Result = detail::combineHashValue(Result, *Minor);
+ if (auto Subminor = Value.getSubminor())
+ Result = detail::combineHashValue(Result, *Subminor);
+ if (auto Build = Value.getBuild())
+ Result = detail::combineHashValue(Result, *Build);
+
+ return Result;
+ }
+
+ static bool isEqual(const VersionTuple &LHS, const VersionTuple &RHS) {
+ return LHS == RHS;
+ }
+};
+
+} // end namespace llvm
+#endif // LLVM_SUPPORT_VERSIONTUPLE_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/VirtualFileSystem.h b/contrib/libs/llvm16/include/llvm/Support/VirtualFileSystem.h
new file mode 100644
index 00000000000..50cfd62002a
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/VirtualFileSystem.h
@@ -0,0 +1,1135 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file
+/// Defines the virtual file system interface vfs::FileSystem.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_VIRTUALFILESYSTEM_H
+#define LLVM_SUPPORT_VIRTUALFILESYSTEM_H
+
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
+#include <cassert>
+#include <cstdint>
+#include <ctime>
+#include <memory>
+#include <optional>
+#include <stack>
+#include <string>
+#include <system_error>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+class MemoryBuffer;
+class MemoryBufferRef;
+class Twine;
+
+namespace vfs {
+
+/// The result of a \p status operation.
+class Status {
+ std::string Name;
+ llvm::sys::fs::UniqueID UID;
+ llvm::sys::TimePoint<> MTime;
+ uint32_t User;
+ uint32_t Group;
+ uint64_t Size;
+ llvm::sys::fs::file_type Type = llvm::sys::fs::file_type::status_error;
+ llvm::sys::fs::perms Perms;
+
+public:
+ // FIXME: remove when files support multiple names
+ bool IsVFSMapped = false;
+
+ /// Whether this entity has an external path different from the virtual path,
+ /// and the external path is exposed by leaking it through the abstraction.
+ /// For example, a RedirectingFileSystem will set this for paths where
+ /// UseExternalName is true.
+ ///
+ /// FIXME: Currently the external path is exposed by replacing the virtual
+ /// path in this Status object. Instead, we should leave the path in the
+ /// Status intact (matching the requested virtual path) - see
+ /// FileManager::getFileRef for how how we plan to fix this.
+ bool ExposesExternalVFSPath = false;
+
+ Status() = default;
+ Status(const llvm::sys::fs::file_status &Status);
+ Status(const Twine &Name, llvm::sys::fs::UniqueID UID,
+ llvm::sys::TimePoint<> MTime, uint32_t User, uint32_t Group,
+ uint64_t Size, llvm::sys::fs::file_type Type,
+ llvm::sys::fs::perms Perms);
+
+ /// Get a copy of a Status with a different size.
+ static Status copyWithNewSize(const Status &In, uint64_t NewSize);
+ /// Get a copy of a Status with a different name.
+ static Status copyWithNewName(const Status &In, const Twine &NewName);
+ static Status copyWithNewName(const llvm::sys::fs::file_status &In,
+ const Twine &NewName);
+
+ /// Returns the name that should be used for this file or directory.
+ StringRef getName() const { return Name; }
+
+ /// @name Status interface from llvm::sys::fs
+ /// @{
+ llvm::sys::fs::file_type getType() const { return Type; }
+ llvm::sys::fs::perms getPermissions() const { return Perms; }
+ llvm::sys::TimePoint<> getLastModificationTime() const { return MTime; }
+ llvm::sys::fs::UniqueID getUniqueID() const { return UID; }
+ uint32_t getUser() const { return User; }
+ uint32_t getGroup() const { return Group; }
+ uint64_t getSize() const { return Size; }
+ /// @}
+ /// @name Status queries
+ /// These are static queries in llvm::sys::fs.
+ /// @{
+ bool equivalent(const Status &Other) const;
+ bool isDirectory() const;
+ bool isRegularFile() const;
+ bool isOther() const;
+ bool isSymlink() const;
+ bool isStatusKnown() const;
+ bool exists() const;
+ /// @}
+};
+
+/// Represents an open file.
+class File {
+public:
+ /// Destroy the file after closing it (if open).
+ /// Sub-classes should generally call close() inside their destructors. We
+ /// cannot do that from the base class, since close is virtual.
+ virtual ~File();
+
+ /// Get the status of the file.
+ virtual llvm::ErrorOr<Status> status() = 0;
+
+ /// Get the name of the file
+ virtual llvm::ErrorOr<std::string> getName() {
+ if (auto Status = status())
+ return Status->getName().str();
+ else
+ return Status.getError();
+ }
+
+ /// Get the contents of the file as a \p MemoryBuffer.
+ virtual llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBuffer(const Twine &Name, int64_t FileSize = -1,
+ bool RequiresNullTerminator = true, bool IsVolatile = false) = 0;
+
+ /// Closes the file.
+ virtual std::error_code close() = 0;
+
+ // Get the same file with a different path.
+ static ErrorOr<std::unique_ptr<File>>
+ getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P);
+
+protected:
+ // Set the file's underlying path.
+ virtual void setPath(const Twine &Path) {}
+};
+
+/// A member of a directory, yielded by a directory_iterator.
+/// Only information available on most platforms is included.
+class directory_entry {
+ std::string Path;
+ llvm::sys::fs::file_type Type = llvm::sys::fs::file_type::type_unknown;
+
+public:
+ directory_entry() = default;
+ directory_entry(std::string Path, llvm::sys::fs::file_type Type)
+ : Path(std::move(Path)), Type(Type) {}
+
+ llvm::StringRef path() const { return Path; }
+ llvm::sys::fs::file_type type() const { return Type; }
+};
+
+namespace detail {
+
+/// An interface for virtual file systems to provide an iterator over the
+/// (non-recursive) contents of a directory.
+struct DirIterImpl {
+ virtual ~DirIterImpl();
+
+ /// Sets \c CurrentEntry to the next entry in the directory on success,
+ /// to directory_entry() at end, or returns a system-defined \c error_code.
+ virtual std::error_code increment() = 0;
+
+ directory_entry CurrentEntry;
+};
+
+} // namespace detail
+
+/// An input iterator over the entries in a virtual path, similar to
+/// llvm::sys::fs::directory_iterator.
+class directory_iterator {
+ std::shared_ptr<detail::DirIterImpl> Impl; // Input iterator semantics on copy
+
+public:
+ directory_iterator(std::shared_ptr<detail::DirIterImpl> I)
+ : Impl(std::move(I)) {
+ assert(Impl.get() != nullptr && "requires non-null implementation");
+ if (Impl->CurrentEntry.path().empty())
+ Impl.reset(); // Normalize the end iterator to Impl == nullptr.
+ }
+
+ /// Construct an 'end' iterator.
+ directory_iterator() = default;
+
+ /// Equivalent to operator++, with an error code.
+ directory_iterator &increment(std::error_code &EC) {
+ assert(Impl && "attempting to increment past end");
+ EC = Impl->increment();
+ if (Impl->CurrentEntry.path().empty())
+ Impl.reset(); // Normalize the end iterator to Impl == nullptr.
+ return *this;
+ }
+
+ const directory_entry &operator*() const { return Impl->CurrentEntry; }
+ const directory_entry *operator->() const { return &Impl->CurrentEntry; }
+
+ bool operator==(const directory_iterator &RHS) const {
+ if (Impl && RHS.Impl)
+ return Impl->CurrentEntry.path() == RHS.Impl->CurrentEntry.path();
+ return !Impl && !RHS.Impl;
+ }
+ bool operator!=(const directory_iterator &RHS) const {
+ return !(*this == RHS);
+ }
+};
+
+class FileSystem;
+
+namespace detail {
+
+/// Keeps state for the recursive_directory_iterator.
+struct RecDirIterState {
+ std::stack<directory_iterator, std::vector<directory_iterator>> Stack;
+ bool HasNoPushRequest = false;
+};
+
+} // end namespace detail
+
+/// An input iterator over the recursive contents of a virtual path,
+/// similar to llvm::sys::fs::recursive_directory_iterator.
+class recursive_directory_iterator {
+ FileSystem *FS;
+ std::shared_ptr<detail::RecDirIterState>
+ State; // Input iterator semantics on copy.
+
+public:
+ recursive_directory_iterator(FileSystem &FS, const Twine &Path,
+ std::error_code &EC);
+
+ /// Construct an 'end' iterator.
+ recursive_directory_iterator() = default;
+
+ /// Equivalent to operator++, with an error code.
+ recursive_directory_iterator &increment(std::error_code &EC);
+
+ const directory_entry &operator*() const { return *State->Stack.top(); }
+ const directory_entry *operator->() const { return &*State->Stack.top(); }
+
+ bool operator==(const recursive_directory_iterator &Other) const {
+ return State == Other.State; // identity
+ }
+ bool operator!=(const recursive_directory_iterator &RHS) const {
+ return !(*this == RHS);
+ }
+
+ /// Gets the current level. Starting path is at level 0.
+ int level() const {
+ assert(!State->Stack.empty() &&
+ "Cannot get level without any iteration state");
+ return State->Stack.size() - 1;
+ }
+
+ void no_push() { State->HasNoPushRequest = true; }
+};
+
+/// The virtual file system interface.
+class FileSystem : public llvm::ThreadSafeRefCountedBase<FileSystem> {
+public:
+ virtual ~FileSystem();
+
+ /// Get the status of the entry at \p Path, if one exists.
+ virtual llvm::ErrorOr<Status> status(const Twine &Path) = 0;
+
+ /// Get a \p File object for the file at \p Path, if one exists.
+ virtual llvm::ErrorOr<std::unique_ptr<File>>
+ openFileForRead(const Twine &Path) = 0;
+
+ /// This is a convenience method that opens a file, gets its content and then
+ /// closes the file.
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ getBufferForFile(const Twine &Name, int64_t FileSize = -1,
+ bool RequiresNullTerminator = true, bool IsVolatile = false);
+
+ /// Get a directory_iterator for \p Dir.
+ /// \note The 'end' iterator is directory_iterator().
+ virtual directory_iterator dir_begin(const Twine &Dir,
+ std::error_code &EC) = 0;
+
+ /// Set the working directory. This will affect all following operations on
+ /// this file system and may propagate down for nested file systems.
+ virtual std::error_code setCurrentWorkingDirectory(const Twine &Path) = 0;
+
+ /// Get the working directory of this file system.
+ virtual llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const = 0;
+
+ /// Gets real path of \p Path e.g. collapse all . and .. patterns, resolve
+ /// symlinks. For real file system, this uses `llvm::sys::fs::real_path`.
+ /// This returns errc::operation_not_permitted if not implemented by subclass.
+ virtual std::error_code getRealPath(const Twine &Path,
+ SmallVectorImpl<char> &Output) const;
+
+ /// Check whether a file exists. Provided for convenience.
+ bool exists(const Twine &Path);
+
+ /// Is the file mounted on a local filesystem?
+ virtual std::error_code isLocal(const Twine &Path, bool &Result);
+
+ /// Make \a Path an absolute path.
+ ///
+ /// Makes \a Path absolute using the current directory if it is not already.
+ /// An empty \a Path will result in the current directory.
+ ///
+ /// /absolute/path => /absolute/path
+ /// relative/../path => <current-directory>/relative/../path
+ ///
+ /// \param Path A path that is modified to be an absolute path.
+ /// \returns success if \a path has been made absolute, otherwise a
+ /// platform-specific error_code.
+ virtual std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const;
+
+ enum class PrintType { Summary, Contents, RecursiveContents };
+ void print(raw_ostream &OS, PrintType Type = PrintType::Contents,
+ unsigned IndentLevel = 0) const {
+ printImpl(OS, Type, IndentLevel);
+ }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ LLVM_DUMP_METHOD void dump() const;
+#endif
+
+protected:
+ virtual void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const {
+ printIndent(OS, IndentLevel);
+ OS << "FileSystem\n";
+ }
+
+ void printIndent(raw_ostream &OS, unsigned IndentLevel) const {
+ for (unsigned i = 0; i < IndentLevel; ++i)
+ OS << " ";
+ }
+};
+
+/// Gets an \p vfs::FileSystem for the 'real' file system, as seen by
+/// the operating system.
+/// The working directory is linked to the process's working directory.
+/// (This is usually thread-hostile).
+IntrusiveRefCntPtr<FileSystem> getRealFileSystem();
+
+/// Create an \p vfs::FileSystem for the 'real' file system, as seen by
+/// the operating system.
+/// It has its own working directory, independent of (but initially equal to)
+/// that of the process.
+std::unique_ptr<FileSystem> createPhysicalFileSystem();
+
+/// A file system that allows overlaying one \p AbstractFileSystem on top
+/// of another.
+///
+/// Consists of a stack of >=1 \p FileSystem objects, which are treated as being
+/// one merged file system. When there is a directory that exists in more than
+/// one file system, the \p OverlayFileSystem contains a directory containing
+/// the union of their contents. The attributes (permissions, etc.) of the
+/// top-most (most recently added) directory are used. When there is a file
+/// that exists in more than one file system, the file in the top-most file
+/// system overrides the other(s).
+class OverlayFileSystem : public FileSystem {
+ using FileSystemList = SmallVector<IntrusiveRefCntPtr<FileSystem>, 1>;
+
+ /// The stack of file systems, implemented as a list in order of
+ /// their addition.
+ FileSystemList FSList;
+
+public:
+ OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> Base);
+
+ /// Pushes a file system on top of the stack.
+ void pushOverlay(IntrusiveRefCntPtr<FileSystem> FS);
+
+ llvm::ErrorOr<Status> status(const Twine &Path) override;
+ llvm::ErrorOr<std::unique_ptr<File>>
+ openFileForRead(const Twine &Path) override;
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+ llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
+ std::error_code isLocal(const Twine &Path, bool &Result) override;
+ std::error_code getRealPath(const Twine &Path,
+ SmallVectorImpl<char> &Output) const override;
+
+ using iterator = FileSystemList::reverse_iterator;
+ using const_iterator = FileSystemList::const_reverse_iterator;
+ using reverse_iterator = FileSystemList::iterator;
+ using const_reverse_iterator = FileSystemList::const_iterator;
+ using range = iterator_range<iterator>;
+ using const_range = iterator_range<const_iterator>;
+
+ /// Get an iterator pointing to the most recently added file system.
+ iterator overlays_begin() { return FSList.rbegin(); }
+ const_iterator overlays_begin() const { return FSList.rbegin(); }
+
+ /// Get an iterator pointing one-past the least recently added file system.
+ iterator overlays_end() { return FSList.rend(); }
+ const_iterator overlays_end() const { return FSList.rend(); }
+
+ /// Get an iterator pointing to the least recently added file system.
+ reverse_iterator overlays_rbegin() { return FSList.begin(); }
+ const_reverse_iterator overlays_rbegin() const { return FSList.begin(); }
+
+ /// Get an iterator pointing one-past the most recently added file system.
+ reverse_iterator overlays_rend() { return FSList.end(); }
+ const_reverse_iterator overlays_rend() const { return FSList.end(); }
+
+ range overlays_range() { return llvm::reverse(FSList); }
+ const_range overlays_range() const { return llvm::reverse(FSList); }
+
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override;
+};
+
+class CaseInsensitiveFileSystem : public FileSystem {
+ IntrusiveRefCntPtr<FileSystem> Base;
+
+ /// Try to find Path by means of case-insensitive lookup. Stores the result in
+ /// FoundPath on success, or returns an error code otherwise.
+ std::error_code findCaseInsensitivePath(StringRef Path,
+ SmallVectorImpl<char> &FoundPath);
+
+ /// Attempt to exclude the possibility that File exists in Dir based on
+ /// previous information.
+ bool exclude(StringRef Dir, StringRef File);
+
+ /// Map from directory to map from lowercase to real-case filename.
+ llvm::StringMap<llvm::StringMap<std::string>> Maps;
+
+public:
+ CaseInsensitiveFileSystem(IntrusiveRefCntPtr<FileSystem> Base) : Base(Base) {}
+
+ llvm::ErrorOr<Status> status(const Twine &Path) override;
+ llvm::ErrorOr<std::unique_ptr<File>>
+ openFileForRead(const Twine &Path) override;
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+ llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
+ return Base->getCurrentWorkingDirectory();
+ }
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+ Maps.clear();
+ return Base->setCurrentWorkingDirectory(Path);
+ }
+};
+
+/// By default, this delegates all calls to the underlying file system. This
+/// is useful when derived file systems want to override some calls and still
+/// proxy other calls.
+class ProxyFileSystem : public FileSystem {
+public:
+ explicit ProxyFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
+ : FS(std::move(FS)) {}
+
+ llvm::ErrorOr<Status> status(const Twine &Path) override {
+ return FS->status(Path);
+ }
+ llvm::ErrorOr<std::unique_ptr<File>>
+ openFileForRead(const Twine &Path) override {
+ return FS->openFileForRead(Path);
+ }
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override {
+ return FS->dir_begin(Dir, EC);
+ }
+ llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
+ return FS->getCurrentWorkingDirectory();
+ }
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
+ return FS->setCurrentWorkingDirectory(Path);
+ }
+ std::error_code getRealPath(const Twine &Path,
+ SmallVectorImpl<char> &Output) const override {
+ return FS->getRealPath(Path, Output);
+ }
+ std::error_code isLocal(const Twine &Path, bool &Result) override {
+ return FS->isLocal(Path, Result);
+ }
+
+protected:
+ FileSystem &getUnderlyingFS() const { return *FS; }
+
+private:
+ IntrusiveRefCntPtr<FileSystem> FS;
+
+ virtual void anchor();
+};
+
+namespace detail {
+
+class InMemoryDirectory;
+class InMemoryNode;
+
+struct NewInMemoryNodeInfo {
+ llvm::sys::fs::UniqueID DirUID;
+ StringRef Path;
+ StringRef Name;
+ time_t ModificationTime;
+ std::unique_ptr<llvm::MemoryBuffer> Buffer;
+ uint32_t User;
+ uint32_t Group;
+ llvm::sys::fs::file_type Type;
+ llvm::sys::fs::perms Perms;
+
+ Status makeStatus() const;
+};
+
+class NamedNodeOrError {
+ ErrorOr<std::pair<llvm::SmallString<128>, const detail::InMemoryNode *>>
+ Value;
+
+public:
+ NamedNodeOrError(llvm::SmallString<128> Name,
+ const detail::InMemoryNode *Node)
+ : Value(std::make_pair(Name, Node)) {}
+ NamedNodeOrError(std::error_code EC) : Value(EC) {}
+ NamedNodeOrError(llvm::errc EC) : Value(EC) {}
+
+ StringRef getName() const { return (*Value).first; }
+ explicit operator bool() const { return static_cast<bool>(Value); }
+ operator std::error_code() const { return Value.getError(); }
+ std::error_code getError() const { return Value.getError(); }
+ const detail::InMemoryNode *operator*() const { return (*Value).second; }
+};
+
+} // namespace detail
+
+/// An in-memory file system.
+class InMemoryFileSystem : public FileSystem {
+ std::unique_ptr<detail::InMemoryDirectory> Root;
+ std::string WorkingDirectory;
+ bool UseNormalizedPaths = true;
+
+ using MakeNodeFn = llvm::function_ref<std::unique_ptr<detail::InMemoryNode>(
+ detail::NewInMemoryNodeInfo)>;
+
+ /// Create node with \p MakeNode and add it into this filesystem at \p Path.
+ bool addFile(const Twine &Path, time_t ModificationTime,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ std::optional<uint32_t> User, std::optional<uint32_t> Group,
+ std::optional<llvm::sys::fs::file_type> Type,
+ std::optional<llvm::sys::fs::perms> Perms, MakeNodeFn MakeNode);
+
+ /// Looks up the in-memory node for the path \p P.
+ /// If \p FollowFinalSymlink is true, the returned node is guaranteed to
+ /// not be a symlink and its path may differ from \p P.
+ detail::NamedNodeOrError lookupNode(const Twine &P, bool FollowFinalSymlink,
+ size_t SymlinkDepth = 0) const;
+
+ class DirIterator;
+
+public:
+ explicit InMemoryFileSystem(bool UseNormalizedPaths = true);
+ ~InMemoryFileSystem() override;
+
+ /// Add a file containing a buffer or a directory to the VFS with a
+ /// path. The VFS owns the buffer. If present, User, Group, Type
+ /// and Perms apply to the newly-created file or directory.
+ /// \return true if the file or directory was successfully added,
+ /// false if the file or directory already exists in the file system with
+ /// different contents.
+ bool addFile(const Twine &Path, time_t ModificationTime,
+ std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ std::optional<uint32_t> User = std::nullopt,
+ std::optional<uint32_t> Group = std::nullopt,
+ std::optional<llvm::sys::fs::file_type> Type = std::nullopt,
+ std::optional<llvm::sys::fs::perms> Perms = std::nullopt);
+
+ /// Add a hard link to a file.
+ ///
+ /// Here hard links are not intended to be fully equivalent to the classical
+ /// filesystem. Both the hard link and the file share the same buffer and
+ /// status (and thus have the same UniqueID). Because of this there is no way
+ /// to distinguish between the link and the file after the link has been
+ /// added.
+ ///
+ /// The \p Target path must be an existing file or a hardlink. The
+ /// \p NewLink file must not have been added before. The \p Target
+ /// path must not be a directory. The \p NewLink node is added as a hard
+ /// link which points to the resolved file of \p Target node.
+ /// \return true if the above condition is satisfied and hardlink was
+ /// successfully created, false otherwise.
+ bool addHardLink(const Twine &NewLink, const Twine &Target);
+
+ /// Arbitrary max depth to search through symlinks. We can get into problems
+ /// if a link links to a link that links back to the link, for example.
+ static constexpr size_t MaxSymlinkDepth = 16;
+
+ /// Add a symbolic link. Unlike a HardLink, because \p Target doesn't need
+ /// to refer to a file (or refer to anything, as it happens). Also, an
+ /// in-memory directory for \p Target isn't automatically created.
+ bool
+ addSymbolicLink(const Twine &NewLink, const Twine &Target,
+ time_t ModificationTime,
+ std::optional<uint32_t> User = std::nullopt,
+ std::optional<uint32_t> Group = std::nullopt,
+ std::optional<llvm::sys::fs::perms> Perms = std::nullopt);
+
+ /// Add a buffer to the VFS with a path. The VFS does not own the buffer.
+ /// If present, User, Group, Type and Perms apply to the newly-created file
+ /// or directory.
+ /// \return true if the file or directory was successfully added,
+ /// false if the file or directory already exists in the file system with
+ /// different contents.
+ bool addFileNoOwn(const Twine &Path, time_t ModificationTime,
+ const llvm::MemoryBufferRef &Buffer,
+ std::optional<uint32_t> User = std::nullopt,
+ std::optional<uint32_t> Group = std::nullopt,
+ std::optional<llvm::sys::fs::file_type> Type = std::nullopt,
+ std::optional<llvm::sys::fs::perms> Perms = std::nullopt);
+
+ std::string toString() const;
+
+ /// Return true if this file system normalizes . and .. in paths.
+ bool useNormalizedPaths() const { return UseNormalizedPaths; }
+
+ llvm::ErrorOr<Status> status(const Twine &Path) override;
+ llvm::ErrorOr<std::unique_ptr<File>>
+ openFileForRead(const Twine &Path) override;
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+
+ llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
+ return WorkingDirectory;
+ }
+ /// Canonicalizes \p Path by combining with the current working
+ /// directory and normalizing the path (e.g. remove dots). If the current
+ /// working directory is not set, this returns errc::operation_not_permitted.
+ ///
+ /// This doesn't resolve symlinks as they are not supported in in-memory file
+ /// system.
+ std::error_code getRealPath(const Twine &Path,
+ SmallVectorImpl<char> &Output) const override;
+ std::error_code isLocal(const Twine &Path, bool &Result) override;
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
+
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override;
+};
+
+/// Get a globally unique ID for a virtual file or directory.
+llvm::sys::fs::UniqueID getNextVirtualUniqueID();
+
+/// Gets a \p FileSystem for a virtual file system described in YAML
+/// format.
+std::unique_ptr<FileSystem>
+getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ llvm::SourceMgr::DiagHandlerTy DiagHandler,
+ StringRef YAMLFilePath, void *DiagContext = nullptr,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
+
+struct YAMLVFSEntry {
+ template <typename T1, typename T2>
+ YAMLVFSEntry(T1 &&VPath, T2 &&RPath, bool IsDirectory = false)
+ : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)),
+ IsDirectory(IsDirectory) {}
+ std::string VPath;
+ std::string RPath;
+ bool IsDirectory = false;
+};
+
+class RedirectingFSDirIterImpl;
+class RedirectingFileSystemParser;
+
+/// A virtual file system parsed from a YAML file.
+///
+/// Currently, this class allows creating virtual files and directories. Virtual
+/// files map to existing external files in \c ExternalFS, and virtual
+/// directories may either map to existing directories in \c ExternalFS or list
+/// their contents in the form of other virtual directories and/or files.
+///
+/// The basic structure of the parsed file is:
+/// \verbatim
+/// {
+/// 'version': <version number>,
+/// <optional configuration>
+/// 'roots': [
+/// <directory entries>
+/// ]
+/// }
+/// \endverbatim
+///
+/// The roots may be absolute or relative. If relative they will be made
+/// absolute against either current working directory or the directory where
+/// the Overlay YAML file is located, depending on the 'root-relative'
+/// configuration.
+///
+/// All configuration options are optional.
+/// 'case-sensitive': <boolean, default=(true for Posix, false for Windows)>
+/// 'use-external-names': <boolean, default=true>
+/// 'root-relative': <string, one of 'cwd' or 'overlay-dir', default='cwd'>
+/// 'overlay-relative': <boolean, default=false>
+/// 'fallthrough': <boolean, default=true, deprecated - use 'redirecting-with'
+/// instead>
+/// 'redirecting-with': <string, one of 'fallthrough', 'fallback', or
+/// 'redirect-only', default='fallthrough'>
+///
+/// To clarify, 'root-relative' option will prepend the current working
+/// directory, or the overlay directory to the 'roots->name' field only if
+/// 'roots->name' is a relative path. On the other hand, when 'overlay-relative'
+/// is set to 'true', external paths will always be prepended with the overlay
+/// directory, even if external paths are not relative paths. The
+/// 'root-relative' option has no interaction with the 'overlay-relative'
+/// option.
+///
+/// Virtual directories that list their contents are represented as
+/// \verbatim
+/// {
+/// 'type': 'directory',
+/// 'name': <string>,
+/// 'contents': [ <file or directory entries> ]
+/// }
+/// \endverbatim
+///
+/// The default attributes for such virtual directories are:
+/// \verbatim
+/// MTime = now() when created
+/// Perms = 0777
+/// User = Group = 0
+/// Size = 0
+/// UniqueID = unspecified unique value
+/// \endverbatim
+///
+/// When a path prefix matches such a directory, the next component in the path
+/// is matched against the entries in the 'contents' array.
+///
+/// Re-mapped directories, on the other hand, are represented as
+/// /// \verbatim
+/// {
+/// 'type': 'directory-remap',
+/// 'name': <string>,
+/// 'use-external-name': <boolean>, # Optional
+/// 'external-contents': <path to external directory>
+/// }
+/// \endverbatim
+///
+/// and inherit their attributes from the external directory. When a path
+/// prefix matches such an entry, the unmatched components are appended to the
+/// 'external-contents' path, and the resulting path is looked up in the
+/// external file system instead.
+///
+/// Re-mapped files are represented as
+/// \verbatim
+/// {
+/// 'type': 'file',
+/// 'name': <string>,
+/// 'use-external-name': <boolean>, # Optional
+/// 'external-contents': <path to external file>
+/// }
+/// \endverbatim
+///
+/// Their attributes and file contents are determined by looking up the file at
+/// their 'external-contents' path in the external file system.
+///
+/// For 'file', 'directory' and 'directory-remap' entries the 'name' field may
+/// contain multiple path components (e.g. /path/to/file). However, any
+/// directory in such a path that contains more than one child must be uniquely
+/// represented by a 'directory' entry.
+///
+/// When the 'use-external-name' field is set, calls to \a vfs::File::status()
+/// give the external (remapped) filesystem name instead of the name the file
+/// was accessed by. This is an intentional leak through the \a
+/// RedirectingFileSystem abstraction layer. It enables clients to discover
+/// (and use) the external file location when communicating with users or tools
+/// that don't use the same VFS overlay.
+///
+/// FIXME: 'use-external-name' causes behaviour that's inconsistent with how
+/// "real" filesystems behave. Maybe there should be a separate channel for
+/// this information.
+class RedirectingFileSystem : public vfs::FileSystem {
+public:
+ enum EntryKind { EK_Directory, EK_DirectoryRemap, EK_File };
+ enum NameKind { NK_NotSet, NK_External, NK_Virtual };
+
+ /// The type of redirection to perform.
+ enum class RedirectKind {
+ /// Lookup the redirected path first (ie. the one specified in
+ /// 'external-contents') and if that fails "fallthrough" to a lookup of the
+ /// originally provided path.
+ Fallthrough,
+ /// Lookup the provided path first and if that fails, "fallback" to a
+ /// lookup of the redirected path.
+ Fallback,
+ /// Only lookup the redirected path, do not lookup the originally provided
+ /// path.
+ RedirectOnly
+ };
+
+ /// The type of relative path used by Roots.
+ enum class RootRelativeKind {
+ /// The roots are relative to the current working directory.
+ CWD,
+ /// The roots are relative to the directory where the Overlay YAML file
+ // locates.
+ OverlayDir
+ };
+
+ /// A single file or directory in the VFS.
+ class Entry {
+ EntryKind Kind;
+ std::string Name;
+
+ public:
+ Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
+ virtual ~Entry() = default;
+
+ StringRef getName() const { return Name; }
+ EntryKind getKind() const { return Kind; }
+ };
+
+ /// A directory in the vfs with explicitly specified contents.
+ class DirectoryEntry : public Entry {
+ std::vector<std::unique_ptr<Entry>> Contents;
+ Status S;
+
+ public:
+ /// Constructs a directory entry with explicitly specified contents.
+ DirectoryEntry(StringRef Name, std::vector<std::unique_ptr<Entry>> Contents,
+ Status S)
+ : Entry(EK_Directory, Name), Contents(std::move(Contents)),
+ S(std::move(S)) {}
+
+ /// Constructs an empty directory entry.
+ DirectoryEntry(StringRef Name, Status S)
+ : Entry(EK_Directory, Name), S(std::move(S)) {}
+
+ Status getStatus() { return S; }
+
+ void addContent(std::unique_ptr<Entry> Content) {
+ Contents.push_back(std::move(Content));
+ }
+
+ Entry *getLastContent() const { return Contents.back().get(); }
+
+ using iterator = decltype(Contents)::iterator;
+
+ iterator contents_begin() { return Contents.begin(); }
+ iterator contents_end() { return Contents.end(); }
+
+ static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
+ };
+
+ /// A file or directory in the vfs that is mapped to a file or directory in
+ /// the external filesystem.
+ class RemapEntry : public Entry {
+ std::string ExternalContentsPath;
+ NameKind UseName;
+
+ protected:
+ RemapEntry(EntryKind K, StringRef Name, StringRef ExternalContentsPath,
+ NameKind UseName)
+ : Entry(K, Name), ExternalContentsPath(ExternalContentsPath),
+ UseName(UseName) {}
+
+ public:
+ StringRef getExternalContentsPath() const { return ExternalContentsPath; }
+
+ /// Whether to use the external path as the name for this file or directory.
+ bool useExternalName(bool GlobalUseExternalName) const {
+ return UseName == NK_NotSet ? GlobalUseExternalName
+ : (UseName == NK_External);
+ }
+
+ NameKind getUseName() const { return UseName; }
+
+ static bool classof(const Entry *E) {
+ switch (E->getKind()) {
+ case EK_DirectoryRemap:
+ [[fallthrough]];
+ case EK_File:
+ return true;
+ case EK_Directory:
+ return false;
+ }
+ llvm_unreachable("invalid entry kind");
+ }
+ };
+
+ /// A directory in the vfs that maps to a directory in the external file
+ /// system.
+ class DirectoryRemapEntry : public RemapEntry {
+ public:
+ DirectoryRemapEntry(StringRef Name, StringRef ExternalContentsPath,
+ NameKind UseName)
+ : RemapEntry(EK_DirectoryRemap, Name, ExternalContentsPath, UseName) {}
+
+ static bool classof(const Entry *E) {
+ return E->getKind() == EK_DirectoryRemap;
+ }
+ };
+
+ /// A file in the vfs that maps to a file in the external file system.
+ class FileEntry : public RemapEntry {
+ public:
+ FileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName)
+ : RemapEntry(EK_File, Name, ExternalContentsPath, UseName) {}
+
+ static bool classof(const Entry *E) { return E->getKind() == EK_File; }
+ };
+
+ /// Represents the result of a path lookup into the RedirectingFileSystem.
+ struct LookupResult {
+ /// The entry the looked-up path corresponds to.
+ Entry *E;
+
+ private:
+ /// When the found Entry is a DirectoryRemapEntry, stores the path in the
+ /// external file system that the looked-up path in the virtual file system
+ // corresponds to.
+ std::optional<std::string> ExternalRedirect;
+
+ public:
+ LookupResult(Entry *E, sys::path::const_iterator Start,
+ sys::path::const_iterator End);
+
+ /// If the found Entry maps the the input path to a path in the external
+ /// file system (i.e. it is a FileEntry or DirectoryRemapEntry), returns
+ /// that path.
+ std::optional<StringRef> getExternalRedirect() const {
+ if (isa<DirectoryRemapEntry>(E))
+ return StringRef(*ExternalRedirect);
+ if (auto *FE = dyn_cast<FileEntry>(E))
+ return FE->getExternalContentsPath();
+ return std::nullopt;
+ }
+ };
+
+private:
+ friend class RedirectingFSDirIterImpl;
+ friend class RedirectingFileSystemParser;
+
+ /// Canonicalize path by removing ".", "..", "./", components. This is
+ /// a VFS request, do not bother about symlinks in the path components
+ /// but canonicalize in order to perform the correct entry search.
+ std::error_code makeCanonical(SmallVectorImpl<char> &Path) const;
+
+ /// Get the File status, or error, from the underlying external file system.
+ /// This returns the status with the originally requested name, while looking
+ /// up the entry using the canonical path.
+ ErrorOr<Status> getExternalStatus(const Twine &CanonicalPath,
+ const Twine &OriginalPath) const;
+
+ /// Make \a Path an absolute path.
+ ///
+ /// Makes \a Path absolute using the \a WorkingDir if it is not already.
+ ///
+ /// /absolute/path => /absolute/path
+ /// relative/../path => <WorkingDir>/relative/../path
+ ///
+ /// \param WorkingDir A path that will be used as the base Dir if \a Path
+ /// is not already absolute.
+ /// \param Path A path that is modified to be an absolute path.
+ /// \returns success if \a path has been made absolute, otherwise a
+ /// platform-specific error_code.
+ std::error_code makeAbsolute(StringRef WorkingDir,
+ SmallVectorImpl<char> &Path) const;
+
+ // In a RedirectingFileSystem, keys can be specified in Posix or Windows
+ // style (or even a mixture of both), so this comparison helper allows
+ // slashes (representing a root) to match backslashes (and vice versa). Note
+ // that, other than the root, path components should not contain slashes or
+ // backslashes.
+ bool pathComponentMatches(llvm::StringRef lhs, llvm::StringRef rhs) const {
+ if ((CaseSensitive ? lhs.equals(rhs) : lhs.equals_insensitive(rhs)))
+ return true;
+ return (lhs == "/" && rhs == "\\") || (lhs == "\\" && rhs == "/");
+ }
+
+ /// The root(s) of the virtual file system.
+ std::vector<std::unique_ptr<Entry>> Roots;
+
+ /// The current working directory of the file system.
+ std::string WorkingDirectory;
+
+ /// The file system to use for external references.
+ IntrusiveRefCntPtr<FileSystem> ExternalFS;
+
+ /// This represents the directory path that the YAML file is located.
+ /// This will be prefixed to each 'external-contents' if IsRelativeOverlay
+ /// is set. This will also be prefixed to each 'roots->name' if RootRelative
+ /// is set to RootRelativeKind::OverlayDir and the path is relative.
+ std::string OverlayFileDir;
+
+ /// @name Configuration
+ /// @{
+
+ /// Whether to perform case-sensitive comparisons.
+ ///
+ /// Currently, case-insensitive matching only works correctly with ASCII.
+ bool CaseSensitive = is_style_posix(sys::path::Style::native);
+
+ /// IsRelativeOverlay marks whether a OverlayFileDir path must
+ /// be prefixed in every 'external-contents' when reading from YAML files.
+ bool IsRelativeOverlay = false;
+
+ /// Whether to use to use the value of 'external-contents' for the
+ /// names of files. This global value is overridable on a per-file basis.
+ bool UseExternalNames = true;
+
+ /// Determines the lookups to perform, as well as their order. See
+ /// \c RedirectKind for details.
+ RedirectKind Redirection = RedirectKind::Fallthrough;
+
+ /// Determine the prefix directory if the roots are relative paths. See
+ /// \c RootRelativeKind for details.
+ RootRelativeKind RootRelative = RootRelativeKind::CWD;
+ /// @}
+
+ RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS);
+
+ /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly recursing
+ /// into the contents of \p From if it is a directory. Returns a LookupResult
+ /// giving the matched entry and, if that entry is a FileEntry or
+ /// DirectoryRemapEntry, the path it redirects to in the external file system.
+ ErrorOr<LookupResult> lookupPathImpl(llvm::sys::path::const_iterator Start,
+ llvm::sys::path::const_iterator End,
+ Entry *From) const;
+
+ /// Get the status for a path with the provided \c LookupResult.
+ ErrorOr<Status> status(const Twine &CanonicalPath, const Twine &OriginalPath,
+ const LookupResult &Result);
+
+public:
+ /// Looks up \p Path in \c Roots and returns a LookupResult giving the
+ /// matched entry and, if the entry was a FileEntry or DirectoryRemapEntry,
+ /// the path it redirects to in the external file system.
+ ErrorOr<LookupResult> lookupPath(StringRef Path) const;
+
+ /// Parses \p Buffer, which is expected to be in YAML format and
+ /// returns a virtual file system representing its contents.
+ static std::unique_ptr<RedirectingFileSystem>
+ create(std::unique_ptr<MemoryBuffer> Buffer,
+ SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
+ void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS);
+
+ /// Redirect each of the remapped files from first to second.
+ static std::unique_ptr<RedirectingFileSystem>
+ create(ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
+ bool UseExternalNames, FileSystem &ExternalFS);
+
+ ErrorOr<Status> status(const Twine &Path) override;
+ ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
+
+ std::error_code getRealPath(const Twine &Path,
+ SmallVectorImpl<char> &Output) const override;
+
+ llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
+
+ std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
+
+ std::error_code isLocal(const Twine &Path, bool &Result) override;
+
+ std::error_code makeAbsolute(SmallVectorImpl<char> &Path) const override;
+
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+
+ void setOverlayFileDir(StringRef PrefixDir);
+
+ StringRef getOverlayFileDir() const;
+
+ /// Sets the redirection kind to \c Fallthrough if true or \c RedirectOnly
+ /// otherwise. Will removed in the future, use \c setRedirection instead.
+ void setFallthrough(bool Fallthrough);
+
+ void setRedirection(RedirectingFileSystem::RedirectKind Kind);
+
+ std::vector<llvm::StringRef> getRoots() const;
+
+ void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel = 0) const;
+
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override;
+};
+
+/// Collect all pairs of <virtual path, real path> entries from the
+/// \p YAMLFilePath. This is used by the module dependency collector to forward
+/// the entries into the reproducer output VFS YAML file.
+void collectVFSFromYAML(
+ std::unique_ptr<llvm::MemoryBuffer> Buffer,
+ llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
+ SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
+ void *DiagContext = nullptr,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
+
+class YAMLVFSWriter {
+ std::vector<YAMLVFSEntry> Mappings;
+ std::optional<bool> IsCaseSensitive;
+ std::optional<bool> IsOverlayRelative;
+ std::optional<bool> UseExternalNames;
+ std::string OverlayDir;
+
+ void addEntry(StringRef VirtualPath, StringRef RealPath, bool IsDirectory);
+
+public:
+ YAMLVFSWriter() = default;
+
+ void addFileMapping(StringRef VirtualPath, StringRef RealPath);
+ void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath);
+
+ void setCaseSensitivity(bool CaseSensitive) {
+ IsCaseSensitive = CaseSensitive;
+ }
+
+ void setUseExternalNames(bool UseExtNames) { UseExternalNames = UseExtNames; }
+
+ void setOverlayDir(StringRef OverlayDirectory) {
+ IsOverlayRelative = true;
+ OverlayDir.assign(OverlayDirectory.str());
+ }
+
+ const std::vector<YAMLVFSEntry> &getMappings() const { return Mappings; }
+
+ void write(llvm::raw_ostream &OS);
+};
+
+} // namespace vfs
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_VIRTUALFILESYSTEM_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Watchdog.h b/contrib/libs/llvm16/include/llvm/Support/Watchdog.h
new file mode 100644
index 00000000000..190f8bc057e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Watchdog.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- Watchdog.h - Watchdog timer ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the llvm::sys::Watchdog class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WATCHDOG_H
+#define LLVM_SUPPORT_WATCHDOG_H
+
+#include "llvm/Support/Compiler.h"
+
+namespace llvm {
+ namespace sys {
+
+ /// This class provides an abstraction for a timeout around an operation
+ /// that must complete in a given amount of time. Failure to complete before
+ /// the timeout is an unrecoverable situation and no mechanisms to attempt
+ /// to handle it are provided.
+ class Watchdog {
+ public:
+ Watchdog(unsigned int seconds);
+ ~Watchdog();
+ private:
+ // Noncopyable.
+ Watchdog(const Watchdog &other) = delete;
+ Watchdog &operator=(const Watchdog &other) = delete;
+ };
+ }
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Win64EH.h b/contrib/libs/llvm16/include/llvm/Support/Win64EH.h
new file mode 100644
index 00000000000..088d0596930
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Win64EH.h
@@ -0,0 +1,230 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/Win64EH.h ---Win64 EH Constants-------------*- 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 constants and structures used for implementing
+// exception handling on Win64 platforms. For more information, see
+// http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WIN64EH_H
+#define LLVM_SUPPORT_WIN64EH_H
+
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Endian.h"
+
+namespace llvm {
+namespace Win64EH {
+
+/// UnwindOpcodes - Enumeration whose values specify a single operation in
+/// the prolog of a function.
+enum UnwindOpcodes {
+ // The following set of unwind opcodes is for x86_64. They are documented at
+ // https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64.
+ // Some generic values from this set are used for other architectures too.
+ UOP_PushNonVol = 0,
+ UOP_AllocLarge,
+ UOP_AllocSmall,
+ UOP_SetFPReg,
+ UOP_SaveNonVol,
+ UOP_SaveNonVolBig,
+ UOP_Epilog,
+ UOP_SpareCode,
+ UOP_SaveXMM128,
+ UOP_SaveXMM128Big,
+ UOP_PushMachFrame,
+ // The following set of unwind opcodes is for ARM64. They are documented at
+ // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
+ UOP_AllocMedium,
+ UOP_SaveR19R20X,
+ UOP_SaveFPLRX,
+ UOP_SaveFPLR,
+ UOP_SaveReg,
+ UOP_SaveRegX,
+ UOP_SaveRegP,
+ UOP_SaveRegPX,
+ UOP_SaveLRPair,
+ UOP_SaveFReg,
+ UOP_SaveFRegX,
+ UOP_SaveFRegP,
+ UOP_SaveFRegPX,
+ UOP_SetFP,
+ UOP_AddFP,
+ UOP_Nop,
+ UOP_End,
+ UOP_SaveNext,
+ UOP_TrapFrame,
+ UOP_Context,
+ UOP_ClearUnwoundToCall,
+ UOP_PACSignLR,
+ UOP_SaveAnyRegI,
+ UOP_SaveAnyRegIP,
+ UOP_SaveAnyRegD,
+ UOP_SaveAnyRegDP,
+ UOP_SaveAnyRegQ,
+ UOP_SaveAnyRegQP,
+ UOP_SaveAnyRegIX,
+ UOP_SaveAnyRegIPX,
+ UOP_SaveAnyRegDX,
+ UOP_SaveAnyRegDPX,
+ UOP_SaveAnyRegQX,
+ UOP_SaveAnyRegQPX,
+
+ // The following set of unwind opcodes is for ARM. They are documented at
+ // https://docs.microsoft.com/en-us/cpp/build/arm-exception-handling
+
+ // Stack allocations use UOP_AllocSmall, UOP_AllocLarge from above, plus
+ // the following. AllocSmall, AllocLarge and AllocHuge represent a 16 bit
+ // instruction, while the WideAlloc* opcodes represent a 32 bit instruction.
+ // Small can represent a stack offset of 0x7f*4 (252) bytes, Medium can
+ // represent up to 0x3ff*4 (4092) bytes, Large up to 0xffff*4 (262140) bytes,
+ // and Huge up to 0xffffff*4 (67108860) bytes.
+ UOP_AllocHuge,
+ UOP_WideAllocMedium,
+ UOP_WideAllocLarge,
+ UOP_WideAllocHuge,
+
+ UOP_WideSaveRegMask,
+ UOP_SaveSP,
+ UOP_SaveRegsR4R7LR,
+ UOP_WideSaveRegsR4R11LR,
+ UOP_SaveFRegD8D15,
+ UOP_SaveRegMask,
+ UOP_SaveLR,
+ UOP_SaveFRegD0D15,
+ UOP_SaveFRegD16D31,
+ // Using UOP_Nop from above
+ UOP_WideNop,
+ // Using UOP_End from above
+ UOP_EndNop,
+ UOP_WideEndNop,
+ // A custom unspecified opcode, consisting of one or more bytes. This
+ // allows producing opcodes in the implementation defined/reserved range.
+ UOP_Custom,
+};
+
+/// UnwindCode - This union describes a single operation in a function prolog,
+/// or part thereof.
+union UnwindCode {
+ struct {
+ uint8_t CodeOffset;
+ uint8_t UnwindOpAndOpInfo;
+ } u;
+ support::ulittle16_t FrameOffset;
+
+ uint8_t getUnwindOp() const {
+ return u.UnwindOpAndOpInfo & 0x0F;
+ }
+ uint8_t getOpInfo() const {
+ return (u.UnwindOpAndOpInfo >> 4) & 0x0F;
+ }
+};
+
+enum {
+ /// UNW_ExceptionHandler - Specifies that this function has an exception
+ /// handler.
+ UNW_ExceptionHandler = 0x01,
+ /// UNW_TerminateHandler - Specifies that this function has a termination
+ /// handler.
+ UNW_TerminateHandler = 0x02,
+ /// UNW_ChainInfo - Specifies that this UnwindInfo structure is chained to
+ /// another one.
+ UNW_ChainInfo = 0x04
+};
+
+/// RuntimeFunction - An entry in the table of functions with unwind info.
+struct RuntimeFunction {
+ support::ulittle32_t StartAddress;
+ support::ulittle32_t EndAddress;
+ support::ulittle32_t UnwindInfoOffset;
+};
+
+/// UnwindInfo - An entry in the exception table.
+struct UnwindInfo {
+ uint8_t VersionAndFlags;
+ uint8_t PrologSize;
+ uint8_t NumCodes;
+ uint8_t FrameRegisterAndOffset;
+ UnwindCode UnwindCodes[1];
+
+ uint8_t getVersion() const {
+ return VersionAndFlags & 0x07;
+ }
+ uint8_t getFlags() const {
+ return (VersionAndFlags >> 3) & 0x1f;
+ }
+ uint8_t getFrameRegister() const {
+ return FrameRegisterAndOffset & 0x0f;
+ }
+ uint8_t getFrameOffset() const {
+ return (FrameRegisterAndOffset >> 4) & 0x0f;
+ }
+
+ // The data after unwindCodes depends on flags.
+ // If UNW_ExceptionHandler or UNW_TerminateHandler is set then follows
+ // the address of the language-specific exception handler.
+ // If UNW_ChainInfo is set then follows a RuntimeFunction which defines
+ // the chained unwind info.
+ // For more information please see MSDN at:
+ // http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx
+
+ /// Return pointer to language specific data part of UnwindInfo.
+ void *getLanguageSpecificData() {
+ return reinterpret_cast<void *>(&UnwindCodes[(NumCodes+1) & ~1]);
+ }
+
+ /// Return pointer to language specific data part of UnwindInfo.
+ const void *getLanguageSpecificData() const {
+ return reinterpret_cast<const void *>(&UnwindCodes[(NumCodes + 1) & ~1]);
+ }
+
+ /// Return image-relative offset of language-specific exception handler.
+ uint32_t getLanguageSpecificHandlerOffset() const {
+ return *reinterpret_cast<const support::ulittle32_t *>(
+ getLanguageSpecificData());
+ }
+
+ /// Set image-relative offset of language-specific exception handler.
+ void setLanguageSpecificHandlerOffset(uint32_t offset) {
+ *reinterpret_cast<support::ulittle32_t *>(getLanguageSpecificData()) =
+ offset;
+ }
+
+ /// Return pointer to exception-specific data.
+ void *getExceptionData() {
+ return reinterpret_cast<void *>(reinterpret_cast<uint32_t *>(
+ getLanguageSpecificData())+1);
+ }
+
+ /// Return pointer to chained unwind info.
+ RuntimeFunction *getChainedFunctionEntry() {
+ return reinterpret_cast<RuntimeFunction *>(getLanguageSpecificData());
+ }
+
+ /// Return pointer to chained unwind info.
+ const RuntimeFunction *getChainedFunctionEntry() const {
+ return reinterpret_cast<const RuntimeFunction *>(getLanguageSpecificData());
+ }
+};
+
+
+} // End of namespace Win64EH
+} // End of namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/Windows/WindowsSupport.h b/contrib/libs/llvm16/include/llvm/Support/Windows/WindowsSupport.h
new file mode 100644
index 00000000000..183b011f564
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/Windows/WindowsSupport.h
@@ -0,0 +1,263 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- WindowsSupport.h - Common Windows Include File -----------*- 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 defines things specific to Windows implementations. In addition to
+// providing some helpers for working with win32 APIs, this header wraps
+// <windows.h> with some portability macros. Always include WindowsSupport.h
+// instead of including <windows.h> directly.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+//=== WARNING: Implementation here must contain only generic Win32 code that
+//=== is guaranteed to work on *all* Win32 variants.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H
+#define LLVM_SUPPORT_WINDOWSSUPPORT_H
+
+// mingw-w64 tends to define it as 0x0502 in its headers.
+#undef _WIN32_WINNT
+#undef _WIN32_IE
+
+// Require at least Windows 7 API.
+#define _WIN32_WINNT 0x0601
+#define _WIN32_IE 0x0800 // MinGW at it again. FIXME: verify if still needed.
+#define WIN32_LEAN_AND_MEAN
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/llvm-config.h" // Get build system configuration settings
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/VersionTuple.h"
+#include <cassert>
+#include <string>
+#include <system_error>
+#include <windows.h>
+
+// Must be included after windows.h
+#include <wincrypt.h>
+
+namespace llvm {
+
+/// Determines if the program is running on Windows 8 or newer. This
+/// reimplements one of the helpers in the Windows 8.1 SDK, which are intended
+/// to supercede raw calls to GetVersionEx. Old SDKs, Cygwin, and MinGW don't
+/// yet have VersionHelpers.h, so we have our own helper.
+bool RunningWindows8OrGreater();
+
+/// Determines if the program is running on Windows 11 or Windows Server 2022.
+bool RunningWindows11OrGreater();
+
+/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
+/// RtlGetVersion or GetVersionEx under the hood depending on what is available.
+/// GetVersionEx is deprecated, but this API exposes the build number which can
+/// be useful for working around certain kernel bugs.
+llvm::VersionTuple GetWindowsOSVersion();
+
+bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix);
+
+// Include GetLastError() in a fatal error message.
+[[noreturn]] inline void ReportLastErrorFatal(const char *Msg) {
+ std::string ErrMsg;
+ MakeErrMsg(&ErrMsg, Msg);
+ llvm::report_fatal_error(Twine(ErrMsg));
+}
+
+template <typename HandleTraits>
+class ScopedHandle {
+ typedef typename HandleTraits::handle_type handle_type;
+ handle_type Handle;
+
+ ScopedHandle(const ScopedHandle &other) = delete;
+ void operator=(const ScopedHandle &other) = delete;
+public:
+ ScopedHandle()
+ : Handle(HandleTraits::GetInvalid()) {}
+
+ explicit ScopedHandle(handle_type h)
+ : Handle(h) {}
+
+ ~ScopedHandle() {
+ if (HandleTraits::IsValid(Handle))
+ HandleTraits::Close(Handle);
+ }
+
+ handle_type take() {
+ handle_type t = Handle;
+ Handle = HandleTraits::GetInvalid();
+ return t;
+ }
+
+ ScopedHandle &operator=(handle_type h) {
+ if (HandleTraits::IsValid(Handle))
+ HandleTraits::Close(Handle);
+ Handle = h;
+ return *this;
+ }
+
+ // True if Handle is valid.
+ explicit operator bool() const {
+ return HandleTraits::IsValid(Handle) ? true : false;
+ }
+
+ operator handle_type() const {
+ return Handle;
+ }
+};
+
+struct CommonHandleTraits {
+ typedef HANDLE handle_type;
+
+ static handle_type GetInvalid() {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ static void Close(handle_type h) {
+ ::CloseHandle(h);
+ }
+
+ static bool IsValid(handle_type h) {
+ return h != GetInvalid();
+ }
+};
+
+struct JobHandleTraits : CommonHandleTraits {
+ static handle_type GetInvalid() {
+ return NULL;
+ }
+};
+
+struct CryptContextTraits : CommonHandleTraits {
+ typedef HCRYPTPROV handle_type;
+
+ static handle_type GetInvalid() {
+ return 0;
+ }
+
+ static void Close(handle_type h) {
+ ::CryptReleaseContext(h, 0);
+ }
+
+ static bool IsValid(handle_type h) {
+ return h != GetInvalid();
+ }
+};
+
+struct RegTraits : CommonHandleTraits {
+ typedef HKEY handle_type;
+
+ static handle_type GetInvalid() {
+ return NULL;
+ }
+
+ static void Close(handle_type h) {
+ ::RegCloseKey(h);
+ }
+
+ static bool IsValid(handle_type h) {
+ return h != GetInvalid();
+ }
+};
+
+struct FindHandleTraits : CommonHandleTraits {
+ static void Close(handle_type h) {
+ ::FindClose(h);
+ }
+};
+
+struct FileHandleTraits : CommonHandleTraits {};
+
+typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle;
+typedef ScopedHandle<FileHandleTraits> ScopedFileHandle;
+typedef ScopedHandle<CryptContextTraits> ScopedCryptContext;
+typedef ScopedHandle<RegTraits> ScopedRegHandle;
+typedef ScopedHandle<FindHandleTraits> ScopedFindHandle;
+typedef ScopedHandle<JobHandleTraits> ScopedJobHandle;
+
+template <class T>
+class SmallVectorImpl;
+
+template <class T>
+typename SmallVectorImpl<T>::const_pointer
+c_str(SmallVectorImpl<T> &str) {
+ str.push_back(0);
+ str.pop_back();
+ return str.data();
+}
+
+namespace sys {
+
+inline std::chrono::nanoseconds toDuration(FILETIME Time) {
+ ULARGE_INTEGER TimeInteger;
+ TimeInteger.LowPart = Time.dwLowDateTime;
+ TimeInteger.HighPart = Time.dwHighDateTime;
+
+ // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
+ return std::chrono::nanoseconds(100 * TimeInteger.QuadPart);
+}
+
+inline TimePoint<> toTimePoint(FILETIME Time) {
+ ULARGE_INTEGER TimeInteger;
+ TimeInteger.LowPart = Time.dwLowDateTime;
+ TimeInteger.HighPart = Time.dwHighDateTime;
+
+ // Adjust for different epoch
+ TimeInteger.QuadPart -= 11644473600ll * 10000000;
+
+ // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond)
+ return TimePoint<>(std::chrono::nanoseconds(100 * TimeInteger.QuadPart));
+}
+
+inline FILETIME toFILETIME(TimePoint<> TP) {
+ ULARGE_INTEGER TimeInteger;
+ TimeInteger.QuadPart = TP.time_since_epoch().count() / 100;
+ TimeInteger.QuadPart += 11644473600ll * 10000000;
+
+ FILETIME Time;
+ Time.dwLowDateTime = TimeInteger.LowPart;
+ Time.dwHighDateTime = TimeInteger.HighPart;
+ return Time;
+}
+
+namespace windows {
+// Returns command line arguments. Unlike arguments given to main(),
+// this function guarantees that the returned arguments are encoded in
+// UTF-8 regardless of the current code page setting.
+std::error_code GetCommandLineArguments(SmallVectorImpl<const char *> &Args,
+ BumpPtrAllocator &Alloc);
+
+/// Convert UTF-8 path to a suitable UTF-16 path for use with the Win32 Unicode
+/// File API.
+std::error_code widenPath(const Twine &Path8, SmallVectorImpl<wchar_t> &Path16,
+ size_t MaxPathLen = MAX_PATH);
+
+} // end namespace windows
+} // end namespace sys
+} // end namespace llvm.
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/WindowsError.h b/contrib/libs/llvm16/include/llvm/Support/WindowsError.h
new file mode 100644
index 00000000000..b128f46261e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/WindowsError.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- WindowsError.h - Support for mapping windows errors to posix-------===//
+//
+// 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 LLVM_SUPPORT_WINDOWSERROR_H
+#define LLVM_SUPPORT_WINDOWSERROR_H
+
+#include <system_error>
+
+namespace llvm {
+std::error_code mapWindowsError(unsigned EV);
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/WithColor.h b/contrib/libs/llvm16/include/llvm/Support/WithColor.h
new file mode 100644
index 00000000000..473303d95c5
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/WithColor.h
@@ -0,0 +1,162 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- WithColor.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_WITHCOLOR_H
+#define LLVM_SUPPORT_WITHCOLOR_H
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+class Error;
+class StringRef;
+
+namespace cl {
+class OptionCategory;
+}
+
+extern cl::OptionCategory &getColorCategory();
+
+// Symbolic names for various syntax elements.
+enum class HighlightColor {
+ Address,
+ String,
+ Tag,
+ Attribute,
+ Enumerator,
+ Macro,
+ Error,
+ Warning,
+ Note,
+ Remark
+};
+
+enum class ColorMode {
+ /// Determine whether to use color based on the command line argument and the
+ /// raw_ostream.
+ Auto,
+ /// Enable colors. Because raw_ostream is the one implementing colors, this
+ /// has no effect if the stream does not support colors or has colors
+ /// disabled.
+ Enable,
+ /// Disable colors.
+ Disable,
+};
+
+/// An RAII object that temporarily switches an output stream to a specific
+/// color.
+class WithColor {
+public:
+ using AutoDetectFunctionType = bool (*)(const raw_ostream &OS);
+
+ /// To be used like this: WithColor(OS, HighlightColor::String) << "text";
+ /// @param OS The output stream
+ /// @param S Symbolic name for syntax element to color
+ /// @param Mode Enable, disable or compute whether to use colors.
+ WithColor(raw_ostream &OS, HighlightColor S,
+ ColorMode Mode = ColorMode::Auto);
+ /// To be used like this: WithColor(OS, raw_ostream::Black) << "text";
+ /// @param OS The output stream
+ /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
+ /// change only the bold attribute, and keep colors untouched
+ /// @param Bold Bold/brighter text, default false
+ /// @param BG If true, change the background, default: change foreground
+ /// @param Mode Enable, disable or compute whether to use colors.
+ WithColor(raw_ostream &OS,
+ raw_ostream::Colors Color = raw_ostream::SAVEDCOLOR,
+ bool Bold = false, bool BG = false,
+ ColorMode Mode = ColorMode::Auto)
+ : OS(OS), Mode(Mode) {
+ changeColor(Color, Bold, BG);
+ }
+ ~WithColor();
+
+ raw_ostream &get() { return OS; }
+ operator raw_ostream &() { return OS; }
+ template <typename T> WithColor &operator<<(T &O) {
+ OS << O;
+ return *this;
+ }
+ template <typename T> WithColor &operator<<(const T &O) {
+ OS << O;
+ return *this;
+ }
+
+ /// Convenience method for printing "error: " to stderr.
+ static raw_ostream &error();
+ /// Convenience method for printing "warning: " to stderr.
+ static raw_ostream &warning();
+ /// Convenience method for printing "note: " to stderr.
+ static raw_ostream &note();
+ /// Convenience method for printing "remark: " to stderr.
+ static raw_ostream &remark();
+
+ /// Convenience method for printing "error: " to the given stream.
+ static raw_ostream &error(raw_ostream &OS, StringRef Prefix = "",
+ bool DisableColors = false);
+ /// Convenience method for printing "warning: " to the given stream.
+ static raw_ostream &warning(raw_ostream &OS, StringRef Prefix = "",
+ bool DisableColors = false);
+ /// Convenience method for printing "note: " to the given stream.
+ static raw_ostream &note(raw_ostream &OS, StringRef Prefix = "",
+ bool DisableColors = false);
+ /// Convenience method for printing "remark: " to the given stream.
+ static raw_ostream &remark(raw_ostream &OS, StringRef Prefix = "",
+ bool DisableColors = false);
+
+ /// Determine whether colors are displayed.
+ bool colorsEnabled();
+
+ /// Change the color of text that will be output from this point forward.
+ /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
+ /// change only the bold attribute, and keep colors untouched
+ /// @param Bold Bold/brighter text, default false
+ /// @param BG If true, change the background, default: change foreground
+ WithColor &changeColor(raw_ostream::Colors Color, bool Bold = false,
+ bool BG = false);
+
+ /// Reset the colors to terminal defaults. Call this when you are done
+ /// outputting colored text, or before program exit.
+ WithColor &resetColor();
+
+ /// Implement default handling for Error.
+ /// Print "error: " to stderr.
+ static void defaultErrorHandler(Error Err);
+
+ /// Implement default handling for Warning.
+ /// Print "warning: " to stderr.
+ static void defaultWarningHandler(Error Warning);
+
+ /// Retrieve the default color auto detection function.
+ static AutoDetectFunctionType defaultAutoDetectFunction();
+
+ /// Change the global auto detection function.
+ static void
+ setAutoDetectFunction(AutoDetectFunctionType NewAutoDetectFunction);
+
+private:
+ raw_ostream &OS;
+ ColorMode Mode;
+
+ static AutoDetectFunctionType AutoDetectFunction;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_WITHCOLOR_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/X86DisassemblerDecoderCommon.h b/contrib/libs/llvm16/include/llvm/Support/X86DisassemblerDecoderCommon.h
new file mode 100644
index 00000000000..61724262f08
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/X86DisassemblerDecoderCommon.h
@@ -0,0 +1,487 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- X86DisassemblerDecoderCommon.h - Disassembler decoder ---*- 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 is part of the X86 Disassembler.
+// It contains common definitions used by both the disassembler and the table
+// generator.
+// Documentation for the disassembler can be found in X86Disassembler.h.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_X86DISASSEMBLERDECODERCOMMON_H
+#define LLVM_SUPPORT_X86DISASSEMBLERDECODERCOMMON_H
+
+#include "llvm/Support/DataTypes.h"
+
+namespace llvm {
+namespace X86Disassembler {
+
+#define INSTRUCTIONS_SYM x86DisassemblerInstrSpecifiers
+#define CONTEXTS_SYM x86DisassemblerContexts
+#define ONEBYTE_SYM x86DisassemblerOneByteOpcodes
+#define TWOBYTE_SYM x86DisassemblerTwoByteOpcodes
+#define THREEBYTE38_SYM x86DisassemblerThreeByte38Opcodes
+#define THREEBYTE3A_SYM x86DisassemblerThreeByte3AOpcodes
+#define XOP8_MAP_SYM x86DisassemblerXOP8Opcodes
+#define XOP9_MAP_SYM x86DisassemblerXOP9Opcodes
+#define XOPA_MAP_SYM x86DisassemblerXOPAOpcodes
+#define THREEDNOW_MAP_SYM x86Disassembler3DNowOpcodes
+#define MAP5_SYM x86DisassemblerMap5Opcodes
+#define MAP6_SYM x86DisassemblerMap6Opcodes
+
+#define INSTRUCTIONS_STR "x86DisassemblerInstrSpecifiers"
+#define CONTEXTS_STR "x86DisassemblerContexts"
+#define ONEBYTE_STR "x86DisassemblerOneByteOpcodes"
+#define TWOBYTE_STR "x86DisassemblerTwoByteOpcodes"
+#define THREEBYTE38_STR "x86DisassemblerThreeByte38Opcodes"
+#define THREEBYTE3A_STR "x86DisassemblerThreeByte3AOpcodes"
+#define XOP8_MAP_STR "x86DisassemblerXOP8Opcodes"
+#define XOP9_MAP_STR "x86DisassemblerXOP9Opcodes"
+#define XOPA_MAP_STR "x86DisassemblerXOPAOpcodes"
+#define THREEDNOW_MAP_STR "x86Disassembler3DNowOpcodes"
+#define MAP5_STR "x86DisassemblerMap5Opcodes"
+#define MAP6_STR "x86DisassemblerMap6Opcodes"
+
+// Attributes of an instruction that must be known before the opcode can be
+// processed correctly. Most of these indicate the presence of particular
+// prefixes, but ATTR_64BIT is simply an attribute of the decoding context.
+enum attributeBits {
+ ATTR_NONE = 0x00,
+ ATTR_64BIT = 0x1 << 0,
+ ATTR_XS = 0x1 << 1,
+ ATTR_XD = 0x1 << 2,
+ ATTR_REXW = 0x1 << 3,
+ ATTR_OPSIZE = 0x1 << 4,
+ ATTR_ADSIZE = 0x1 << 5,
+ ATTR_VEX = 0x1 << 6,
+ ATTR_VEXL = 0x1 << 7,
+ ATTR_EVEX = 0x1 << 8,
+ ATTR_EVEXL2 = 0x1 << 9,
+ ATTR_EVEXK = 0x1 << 10,
+ ATTR_EVEXKZ = 0x1 << 11,
+ ATTR_EVEXB = 0x1 << 12,
+ ATTR_max = 0x1 << 13,
+};
+
+// Combinations of the above attributes that are relevant to instruction
+// decode. Although other combinations are possible, they can be reduced to
+// these without affecting the ultimately decoded instruction.
+
+// Class name Rank Rationale for rank assignment
+#define INSTRUCTION_CONTEXTS \
+ ENUM_ENTRY(IC, 0, "says nothing about the instruction") \
+ ENUM_ENTRY(IC_64BIT, 1, "says the instruction applies in " \
+ "64-bit mode but no more") \
+ ENUM_ENTRY(IC_OPSIZE, 3, "requires an OPSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_ADSIZE, 3, "requires an ADSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_OPSIZE_ADSIZE, 4, "requires ADSIZE and OPSIZE prefixes") \
+ ENUM_ENTRY(IC_XD, 2, "may say something about the opcode " \
+ "but not the operands") \
+ ENUM_ENTRY(IC_XS, 2, "may say something about the opcode " \
+ "but not the operands") \
+ ENUM_ENTRY(IC_XD_OPSIZE, 3, "requires an OPSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_XS_OPSIZE, 3, "requires an OPSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_XD_ADSIZE, 3, "requires an ADSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_XS_ADSIZE, 3, "requires an ADSIZE prefix, so " \
+ "operands change width") \
+ ENUM_ENTRY(IC_64BIT_REXW, 5, "requires a REX.W prefix, so operands "\
+ "change width; overrides IC_OPSIZE") \
+ ENUM_ENTRY(IC_64BIT_REXW_ADSIZE, 6, "requires a REX.W prefix and 0x67 " \
+ "prefix") \
+ ENUM_ENTRY(IC_64BIT_OPSIZE, 3, "Just as meaningful as IC_OPSIZE") \
+ ENUM_ENTRY(IC_64BIT_ADSIZE, 3, "Just as meaningful as IC_ADSIZE") \
+ ENUM_ENTRY(IC_64BIT_OPSIZE_ADSIZE, 4, "Just as meaningful as IC_OPSIZE/" \
+ "IC_ADSIZE") \
+ ENUM_ENTRY(IC_64BIT_XD, 6, "XD instructions are SSE; REX.W is " \
+ "secondary") \
+ ENUM_ENTRY(IC_64BIT_XS, 6, "Just as meaningful as IC_64BIT_XD") \
+ ENUM_ENTRY(IC_64BIT_XD_OPSIZE, 3, "Just as meaningful as IC_XD_OPSIZE") \
+ ENUM_ENTRY(IC_64BIT_XS_OPSIZE, 3, "Just as meaningful as IC_XS_OPSIZE") \
+ ENUM_ENTRY(IC_64BIT_XD_ADSIZE, 3, "Just as meaningful as IC_XD_ADSIZE") \
+ ENUM_ENTRY(IC_64BIT_XS_ADSIZE, 3, "Just as meaningful as IC_XS_ADSIZE") \
+ ENUM_ENTRY(IC_64BIT_REXW_XS, 7, "OPSIZE could mean a different " \
+ "opcode") \
+ ENUM_ENTRY(IC_64BIT_REXW_XD, 7, "Just as meaningful as " \
+ "IC_64BIT_REXW_XS") \
+ ENUM_ENTRY(IC_64BIT_REXW_OPSIZE, 8, "The Dynamic Duo! Prefer over all " \
+ "else because this changes most " \
+ "operands' meaning") \
+ ENUM_ENTRY(IC_VEX, 1, "requires a VEX prefix") \
+ ENUM_ENTRY(IC_VEX_XS, 2, "requires VEX and the XS prefix") \
+ ENUM_ENTRY(IC_VEX_XD, 2, "requires VEX and the XD prefix") \
+ ENUM_ENTRY(IC_VEX_OPSIZE, 2, "requires VEX and the OpSize prefix") \
+ ENUM_ENTRY(IC_VEX_W, 3, "requires VEX and the W prefix") \
+ ENUM_ENTRY(IC_VEX_W_XS, 4, "requires VEX, W, and XS prefix") \
+ ENUM_ENTRY(IC_VEX_W_XD, 4, "requires VEX, W, and XD prefix") \
+ ENUM_ENTRY(IC_VEX_W_OPSIZE, 4, "requires VEX, W, and OpSize") \
+ ENUM_ENTRY(IC_VEX_L, 3, "requires VEX and the L prefix") \
+ ENUM_ENTRY(IC_VEX_L_XS, 4, "requires VEX and the L and XS prefix")\
+ ENUM_ENTRY(IC_VEX_L_XD, 4, "requires VEX and the L and XD prefix")\
+ ENUM_ENTRY(IC_VEX_L_OPSIZE, 4, "requires VEX, L, and OpSize") \
+ ENUM_ENTRY(IC_VEX_L_W, 4, "requires VEX, L and W") \
+ ENUM_ENTRY(IC_VEX_L_W_XS, 5, "requires VEX, L, W and XS prefix") \
+ ENUM_ENTRY(IC_VEX_L_W_XD, 5, "requires VEX, L, W and XD prefix") \
+ ENUM_ENTRY(IC_VEX_L_W_OPSIZE, 5, "requires VEX, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX, 1, "requires an EVEX prefix") \
+ ENUM_ENTRY(IC_EVEX_XS, 2, "requires EVEX and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD, 2, "requires EVEX and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE, 2, "requires EVEX and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W, 3, "requires EVEX and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS, 4, "requires EVEX, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD, 4, "requires EVEX, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE, 4, "requires EVEX, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L, 3, "requires EVEX and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS, 4, "requires EVEX and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD, 4, "requires EVEX and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE, 4, "requires EVEX, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W, 3, "requires EVEX, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS, 4, "requires EVEX, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD, 4, "requires EVEX, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE, 4, "requires EVEX, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2, 3, "requires EVEX and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS, 4, "requires EVEX and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD, 4, "requires EVEX and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE, 4, "requires EVEX, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W, 3, "requires EVEX, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS, 4, "requires EVEX, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD, 4, "requires EVEX, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE, 4, "requires EVEX, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_K, 1, "requires an EVEX_K prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_K, 2, "requires EVEX_K and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_K, 2, "requires EVEX_K and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_K, 2, "requires EVEX_K and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_K, 3, "requires EVEX_K and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_K, 4, "requires EVEX_K, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_K, 4, "requires EVEX_K, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_K, 4, "requires EVEX_K, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_K, 3, "requires EVEX_K and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_K, 4, "requires EVEX_K and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_K, 4, "requires EVEX_K and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_K, 4, "requires EVEX_K, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_K, 3, "requires EVEX_K, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_K, 4, "requires EVEX_K, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_K, 4, "requires EVEX_K, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_K, 4, "requires EVEX_K, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_K, 3, "requires EVEX_K and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_K, 4, "requires EVEX_K and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_K, 4, "requires EVEX_K and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_K, 4, "requires EVEX_K, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_K, 3, "requires EVEX_K, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_K, 4, "requires EVEX_K, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_K, 4, "requires EVEX_K, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_K, 4, "requires EVEX_K, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_B, 1, "requires an EVEX_B prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_B, 2, "requires EVEX_B and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_B, 2, "requires EVEX_B and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_B, 2, "requires EVEX_B and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_B, 3, "requires EVEX_B and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_B, 4, "requires EVEX_B, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_B, 4, "requires EVEX_B, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_B, 4, "requires EVEX_B, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_B, 3, "requires EVEX_B and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_B, 4, "requires EVEX_B and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_B, 4, "requires EVEX_B and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_B, 4, "requires EVEX_B, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_B, 3, "requires EVEX_B, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_B, 4, "requires EVEX_B, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_B, 4, "requires EVEX_B, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_B, 4, "requires EVEX_B, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_B, 3, "requires EVEX_B and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_B, 4, "requires EVEX_B and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_B, 4, "requires EVEX_B and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_B, 4, "requires EVEX_B, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_B, 3, "requires EVEX_B, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_B, 4, "requires EVEX_B, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_B, 4, "requires EVEX_B, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_B, 4, "requires EVEX_B, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_K_B, 1, "requires EVEX_B and EVEX_K prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_K_B, 2, "requires EVEX_B, EVEX_K and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_K_B, 2, "requires EVEX_B, EVEX_K and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_K_B, 2, "requires EVEX_B, EVEX_K and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_K_B, 3, "requires EVEX_B, EVEX_K and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_K_B, 3, "requires EVEX_B, EVEX_K and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_K_B, 4, "requires EVEX_B, EVEX_K and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_K_B, 4, "requires EVEX_B, EVEX_K and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_K_B, 3, "requires EVEX_B, EVEX_K, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_K_B,4, "requires EVEX_B, EVEX_K, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_K_B, 3, "requires EVEX_B, EVEX_K and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_K_B, 4, "requires EVEX_B, EVEX_K and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_K_B, 4, "requires EVEX_B, EVEX_K and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_K_B, 4, "requires EVEX_B, EVEX_K, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_K_B, 3, "requires EVEX_B, EVEX_K, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_K_B, 4, "requires EVEX_B, EVEX_K, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_K_B,4, "requires EVEX_B, EVEX_K, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_KZ_B, 1, "requires EVEX_B and EVEX_KZ prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_KZ_B, 2, "requires EVEX_B, EVEX_KZ and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_KZ_B, 3, "requires EVEX_B, EVEX_KZ, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_KZ_B, 3, "requires EVEX_B, EVEX_KZ and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_KZ_B, 3, "requires EVEX_B, EVEX_KZ, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ_B, 4, "requires EVEX_B, EVEX_KZ, L2, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_KZ, 1, "requires an EVEX_KZ prefix") \
+ ENUM_ENTRY(IC_EVEX_XS_KZ, 2, "requires EVEX_KZ and the XS prefix") \
+ ENUM_ENTRY(IC_EVEX_XD_KZ, 2, "requires EVEX_KZ and the XD prefix") \
+ ENUM_ENTRY(IC_EVEX_OPSIZE_KZ, 2, "requires EVEX_KZ and the OpSize prefix") \
+ ENUM_ENTRY(IC_EVEX_W_KZ, 3, "requires EVEX_KZ and the W prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XS_KZ, 4, "requires EVEX_KZ, W, and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_W_XD_KZ, 4, "requires EVEX_KZ, W, and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_W_OPSIZE_KZ, 4, "requires EVEX_KZ, W, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_KZ, 3, "requires EVEX_KZ and the L prefix") \
+ ENUM_ENTRY(IC_EVEX_L_XS_KZ, 4, "requires EVEX_KZ and the L and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L_XD_KZ, 4, "requires EVEX_KZ and the L and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L_OPSIZE_KZ, 4, "requires EVEX_KZ, L, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L_W_KZ, 3, "requires EVEX_KZ, L and W") \
+ ENUM_ENTRY(IC_EVEX_L_W_XS_KZ, 4, "requires EVEX_KZ, L, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_XD_KZ, 4, "requires EVEX_KZ, L, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L, W and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_KZ, 3, "requires EVEX_KZ and the L2 prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_XS_KZ, 4, "requires EVEX_KZ and the L2 and XS prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_XD_KZ, 4, "requires EVEX_KZ and the L2 and XD prefix")\
+ ENUM_ENTRY(IC_EVEX_L2_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, and OpSize") \
+ ENUM_ENTRY(IC_EVEX_L2_W_KZ, 3, "requires EVEX_KZ, L2 and W") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XS_KZ, 4, "requires EVEX_KZ, L2, W and XS prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_XD_KZ, 4, "requires EVEX_KZ, L2, W and XD prefix") \
+ ENUM_ENTRY(IC_EVEX_L2_W_OPSIZE_KZ, 4, "requires EVEX_KZ, L2, W and OpSize")
+
+#define ENUM_ENTRY(n, r, d) n,
+enum InstructionContext {
+ INSTRUCTION_CONTEXTS
+ IC_max
+};
+#undef ENUM_ENTRY
+
+// Opcode types, which determine which decode table to use, both in the Intel
+// manual and also for the decoder.
+enum OpcodeType {
+ ONEBYTE = 0,
+ TWOBYTE = 1,
+ THREEBYTE_38 = 2,
+ THREEBYTE_3A = 3,
+ XOP8_MAP = 4,
+ XOP9_MAP = 5,
+ XOPA_MAP = 6,
+ THREEDNOW_MAP = 7,
+ MAP5 = 8,
+ MAP6 = 9
+};
+
+// The following structs are used for the hierarchical decode table. After
+// determining the instruction's class (i.e., which IC_* constant applies to
+// it), the decoder reads the opcode. Some instructions require specific
+// values of the ModR/M byte, so the ModR/M byte indexes into the final table.
+//
+// If a ModR/M byte is not required, "required" is left unset, and the values
+// for each instructionID are identical.
+typedef uint16_t InstrUID;
+
+// ModRMDecisionType - describes the type of ModR/M decision, allowing the
+// consumer to determine the number of entries in it.
+//
+// MODRM_ONEENTRY - No matter what the value of the ModR/M byte is, the decoded
+// instruction is the same.
+// MODRM_SPLITRM - If the ModR/M byte is between 0x00 and 0xbf, the opcode
+// corresponds to one instruction; otherwise, it corresponds to
+// a different instruction.
+// MODRM_SPLITMISC- If the ModR/M byte is between 0x00 and 0xbf, ModR/M byte
+// divided by 8 is used to select instruction; otherwise, each
+// value of the ModR/M byte could correspond to a different
+// instruction.
+// MODRM_SPLITREG - ModR/M byte divided by 8 is used to select instruction. This
+// corresponds to instructions that use reg field as opcode
+// MODRM_FULL - Potentially, each value of the ModR/M byte could correspond
+// to a different instruction.
+#define MODRMTYPES \
+ ENUM_ENTRY(MODRM_ONEENTRY) \
+ ENUM_ENTRY(MODRM_SPLITRM) \
+ ENUM_ENTRY(MODRM_SPLITMISC) \
+ ENUM_ENTRY(MODRM_SPLITREG) \
+ ENUM_ENTRY(MODRM_FULL)
+
+#define ENUM_ENTRY(n) n,
+enum ModRMDecisionType {
+ MODRMTYPES
+ MODRM_max
+};
+#undef ENUM_ENTRY
+
+#define CASE_ENCODING_RM \
+ case ENCODING_RM: \
+ case ENCODING_RM_CD2: \
+ case ENCODING_RM_CD4: \
+ case ENCODING_RM_CD8: \
+ case ENCODING_RM_CD16: \
+ case ENCODING_RM_CD32: \
+ case ENCODING_RM_CD64
+
+#define CASE_ENCODING_VSIB \
+ case ENCODING_VSIB: \
+ case ENCODING_VSIB_CD2: \
+ case ENCODING_VSIB_CD4: \
+ case ENCODING_VSIB_CD8: \
+ case ENCODING_VSIB_CD16: \
+ case ENCODING_VSIB_CD32: \
+ case ENCODING_VSIB_CD64
+
+// Physical encodings of instruction operands.
+#define ENCODINGS \
+ ENUM_ENTRY(ENCODING_NONE, "") \
+ ENUM_ENTRY(ENCODING_REG, "Register operand in ModR/M byte.") \
+ ENUM_ENTRY(ENCODING_RM, "R/M operand in ModR/M byte.") \
+ ENUM_ENTRY(ENCODING_RM_CD2, "R/M operand with CDisp scaling of 2") \
+ ENUM_ENTRY(ENCODING_RM_CD4, "R/M operand with CDisp scaling of 4") \
+ ENUM_ENTRY(ENCODING_RM_CD8, "R/M operand with CDisp scaling of 8") \
+ ENUM_ENTRY(ENCODING_RM_CD16,"R/M operand with CDisp scaling of 16") \
+ ENUM_ENTRY(ENCODING_RM_CD32,"R/M operand with CDisp scaling of 32") \
+ ENUM_ENTRY(ENCODING_RM_CD64,"R/M operand with CDisp scaling of 64") \
+ ENUM_ENTRY(ENCODING_SIB, "Force SIB operand in ModR/M byte.") \
+ ENUM_ENTRY(ENCODING_VSIB, "VSIB operand in ModR/M byte.") \
+ ENUM_ENTRY(ENCODING_VSIB_CD2, "VSIB operand with CDisp scaling of 2") \
+ ENUM_ENTRY(ENCODING_VSIB_CD4, "VSIB operand with CDisp scaling of 4") \
+ ENUM_ENTRY(ENCODING_VSIB_CD8, "VSIB operand with CDisp scaling of 8") \
+ ENUM_ENTRY(ENCODING_VSIB_CD16,"VSIB operand with CDisp scaling of 16") \
+ ENUM_ENTRY(ENCODING_VSIB_CD32,"VSIB operand with CDisp scaling of 32") \
+ ENUM_ENTRY(ENCODING_VSIB_CD64,"VSIB operand with CDisp scaling of 64") \
+ ENUM_ENTRY(ENCODING_VVVV, "Register operand in VEX.vvvv byte.") \
+ ENUM_ENTRY(ENCODING_WRITEMASK, "Register operand in EVEX.aaa byte.") \
+ ENUM_ENTRY(ENCODING_IB, "1-byte immediate") \
+ ENUM_ENTRY(ENCODING_IW, "2-byte") \
+ ENUM_ENTRY(ENCODING_ID, "4-byte") \
+ ENUM_ENTRY(ENCODING_IO, "8-byte") \
+ ENUM_ENTRY(ENCODING_RB, "(AL..DIL, R8B..R15B) Register code added to " \
+ "the opcode byte") \
+ ENUM_ENTRY(ENCODING_RW, "(AX..DI, R8W..R15W)") \
+ ENUM_ENTRY(ENCODING_RD, "(EAX..EDI, R8D..R15D)") \
+ ENUM_ENTRY(ENCODING_RO, "(RAX..RDI, R8..R15)") \
+ ENUM_ENTRY(ENCODING_FP, "Position on floating-point stack in ModR/M " \
+ "byte.") \
+ \
+ ENUM_ENTRY(ENCODING_Iv, "Immediate of operand size") \
+ ENUM_ENTRY(ENCODING_Ia, "Immediate of address size") \
+ ENUM_ENTRY(ENCODING_IRC, "Immediate for static rounding control") \
+ ENUM_ENTRY(ENCODING_Rv, "Register code of operand size added to the " \
+ "opcode byte") \
+ ENUM_ENTRY(ENCODING_CC, "Condition code encoded in opcode") \
+ ENUM_ENTRY(ENCODING_DUP, "Duplicate of another operand; ID is encoded " \
+ "in type") \
+ ENUM_ENTRY(ENCODING_SI, "Source index; encoded in OpSize/Adsize prefix") \
+ ENUM_ENTRY(ENCODING_DI, "Destination index; encoded in prefixes")
+
+#define ENUM_ENTRY(n, d) n,
+enum OperandEncoding {
+ ENCODINGS
+ ENCODING_max
+};
+#undef ENUM_ENTRY
+
+// Semantic interpretations of instruction operands.
+#define TYPES \
+ ENUM_ENTRY(TYPE_NONE, "") \
+ ENUM_ENTRY(TYPE_REL, "immediate address") \
+ ENUM_ENTRY(TYPE_R8, "1-byte register operand") \
+ ENUM_ENTRY(TYPE_R16, "2-byte") \
+ ENUM_ENTRY(TYPE_R32, "4-byte") \
+ ENUM_ENTRY(TYPE_R64, "8-byte") \
+ ENUM_ENTRY(TYPE_IMM, "immediate operand") \
+ ENUM_ENTRY(TYPE_UIMM8, "1-byte unsigned immediate operand") \
+ ENUM_ENTRY(TYPE_M, "Memory operand") \
+ ENUM_ENTRY(TYPE_MSIB, "Memory operand force sib encoding") \
+ ENUM_ENTRY(TYPE_MVSIBX, "Memory operand using XMM index") \
+ ENUM_ENTRY(TYPE_MVSIBY, "Memory operand using YMM index") \
+ ENUM_ENTRY(TYPE_MVSIBZ, "Memory operand using ZMM index") \
+ ENUM_ENTRY(TYPE_SRCIDX, "memory at source index") \
+ ENUM_ENTRY(TYPE_DSTIDX, "memory at destination index") \
+ ENUM_ENTRY(TYPE_MOFFS, "memory offset (relative to segment base)") \
+ ENUM_ENTRY(TYPE_ST, "Position on the floating-point stack") \
+ ENUM_ENTRY(TYPE_MM64, "8-byte MMX register") \
+ ENUM_ENTRY(TYPE_XMM, "16-byte") \
+ ENUM_ENTRY(TYPE_YMM, "32-byte") \
+ ENUM_ENTRY(TYPE_ZMM, "64-byte") \
+ ENUM_ENTRY(TYPE_VK, "mask register") \
+ ENUM_ENTRY(TYPE_VK_PAIR, "mask register pair") \
+ ENUM_ENTRY(TYPE_TMM, "tile") \
+ ENUM_ENTRY(TYPE_SEGMENTREG, "Segment register operand") \
+ ENUM_ENTRY(TYPE_DEBUGREG, "Debug register operand") \
+ ENUM_ENTRY(TYPE_CONTROLREG, "Control register operand") \
+ ENUM_ENTRY(TYPE_BNDR, "MPX bounds register") \
+ \
+ ENUM_ENTRY(TYPE_Rv, "Register operand of operand size") \
+ ENUM_ENTRY(TYPE_RELv, "Immediate address of operand size") \
+ ENUM_ENTRY(TYPE_DUP0, "Duplicate of operand 0") \
+ ENUM_ENTRY(TYPE_DUP1, "operand 1") \
+ ENUM_ENTRY(TYPE_DUP2, "operand 2") \
+ ENUM_ENTRY(TYPE_DUP3, "operand 3") \
+ ENUM_ENTRY(TYPE_DUP4, "operand 4") \
+
+#define ENUM_ENTRY(n, d) n,
+enum OperandType {
+ TYPES
+ TYPE_max
+};
+#undef ENUM_ENTRY
+
+/// The specification for how to extract and interpret one operand.
+struct OperandSpecifier {
+ uint8_t encoding;
+ uint8_t type;
+};
+
+static const unsigned X86_MAX_OPERANDS = 6;
+
+/// Decoding mode for the Intel disassembler. 16-bit, 32-bit, and 64-bit mode
+/// are supported, and represent real mode, IA-32e, and IA-32e in 64-bit mode,
+/// respectively.
+enum DisassemblerMode {
+ MODE_16BIT,
+ MODE_32BIT,
+ MODE_64BIT
+};
+
+} // namespace X86Disassembler
+} // namespace llvm
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/X86TargetParser.h b/contrib/libs/llvm16/include/llvm/Support/X86TargetParser.h
new file mode 100644
index 00000000000..9901d0d5c20
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/X86TargetParser.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/X86TargetParser.h --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This header is deprecated in favour of
+/// `llvm/TargetParser/X86TargetParser.h`.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TargetParser/X86TargetParser.h"
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/YAMLParser.h b/contrib/libs/llvm16/include/llvm/Support/YAMLParser.h
new file mode 100644
index 00000000000..5c505fa07de
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/YAMLParser.h
@@ -0,0 +1,639 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- YAMLParser.h - Simple YAML parser ------------------------*- 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 is a YAML 1.2 parser.
+//
+// See http://www.yaml.org/spec/1.2/spec.html for the full standard.
+//
+// This currently does not implement the following:
+// * Tag resolution.
+// * UTF-16.
+// * BOMs anywhere other than the first Unicode scalar value in the file.
+//
+// The most important class here is Stream. This represents a YAML stream with
+// 0, 1, or many documents.
+//
+// SourceMgr sm;
+// StringRef input = getInput();
+// yaml::Stream stream(input, sm);
+//
+// for (yaml::document_iterator di = stream.begin(), de = stream.end();
+// di != de; ++di) {
+// yaml::Node *n = di->getRoot();
+// if (n) {
+// // Do something with n...
+// } else
+// break;
+// }
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_YAMLPARSER_H
+#define LLVM_SUPPORT_YAMLPARSER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
+#include <cassert>
+#include <cstddef>
+#include <iterator>
+#include <map>
+#include <memory>
+#include <optional>
+#include <string>
+#include <system_error>
+
+namespace llvm {
+
+class MemoryBufferRef;
+class raw_ostream;
+class Twine;
+
+namespace yaml {
+
+class Document;
+class document_iterator;
+class Node;
+class Scanner;
+struct Token;
+
+/// Dump all the tokens in this stream to OS.
+/// \returns true if there was an error, false otherwise.
+bool dumpTokens(StringRef Input, raw_ostream &);
+
+/// Scans all tokens in input without outputting anything. This is used
+/// for benchmarking the tokenizer.
+/// \returns true if there was an error, false otherwise.
+bool scanTokens(StringRef Input);
+
+/// Escape \a Input for a double quoted scalar; if \p EscapePrintable
+/// is true, all UTF8 sequences will be escaped, if \p EscapePrintable is
+/// false, those UTF8 sequences encoding printable unicode scalars will not be
+/// escaped, but emitted verbatim.
+std::string escape(StringRef Input, bool EscapePrintable = true);
+
+/// Parse \p S as a bool according to https://yaml.org/type/bool.html.
+std::optional<bool> parseBool(StringRef S);
+
+/// This class represents a YAML stream potentially containing multiple
+/// documents.
+class Stream {
+public:
+ /// This keeps a reference to the string referenced by \p Input.
+ Stream(StringRef Input, SourceMgr &, bool ShowColors = true,
+ std::error_code *EC = nullptr);
+
+ Stream(MemoryBufferRef InputBuffer, SourceMgr &, bool ShowColors = true,
+ std::error_code *EC = nullptr);
+ ~Stream();
+
+ document_iterator begin();
+ document_iterator end();
+ void skip();
+ bool failed();
+
+ bool validate() {
+ skip();
+ return !failed();
+ }
+
+ void printError(Node *N, const Twine &Msg,
+ SourceMgr::DiagKind Kind = SourceMgr::DK_Error);
+ void printError(const SMRange &Range, const Twine &Msg,
+ SourceMgr::DiagKind Kind = SourceMgr::DK_Error);
+
+private:
+ friend class Document;
+
+ std::unique_ptr<Scanner> scanner;
+ std::unique_ptr<Document> CurrentDoc;
+};
+
+/// Abstract base class for all Nodes.
+class Node {
+ virtual void anchor();
+
+public:
+ enum NodeKind {
+ NK_Null,
+ NK_Scalar,
+ NK_BlockScalar,
+ NK_KeyValue,
+ NK_Mapping,
+ NK_Sequence,
+ NK_Alias
+ };
+
+ Node(unsigned int Type, std::unique_ptr<Document> &, StringRef Anchor,
+ StringRef Tag);
+
+ // It's not safe to copy YAML nodes; the document is streamed and the position
+ // is part of the state.
+ Node(const Node &) = delete;
+ void operator=(const Node &) = delete;
+
+ void *operator new(size_t Size, BumpPtrAllocator &Alloc,
+ size_t Alignment = 16) noexcept {
+ return Alloc.Allocate(Size, Alignment);
+ }
+
+ void operator delete(void *Ptr, BumpPtrAllocator &Alloc,
+ size_t Size) noexcept {
+ Alloc.Deallocate(Ptr, Size, 0);
+ }
+
+ void operator delete(void *) noexcept = delete;
+
+ /// Get the value of the anchor attached to this node. If it does not
+ /// have one, getAnchor().size() will be 0.
+ StringRef getAnchor() const { return Anchor; }
+
+ /// Get the tag as it was written in the document. This does not
+ /// perform tag resolution.
+ StringRef getRawTag() const { return Tag; }
+
+ /// Get the verbatium tag for a given Node. This performs tag resoluton
+ /// and substitution.
+ std::string getVerbatimTag() const;
+
+ SMRange getSourceRange() const { return SourceRange; }
+ void setSourceRange(SMRange SR) { SourceRange = SR; }
+
+ // These functions forward to Document and Scanner.
+ Token &peekNext();
+ Token getNext();
+ Node *parseBlockNode();
+ BumpPtrAllocator &getAllocator();
+ void setError(const Twine &Message, Token &Location) const;
+ bool failed() const;
+
+ virtual void skip() {}
+
+ unsigned int getType() const { return TypeID; }
+
+protected:
+ std::unique_ptr<Document> &Doc;
+ SMRange SourceRange;
+
+ ~Node() = default;
+
+private:
+ unsigned int TypeID;
+ StringRef Anchor;
+ /// The tag as typed in the document.
+ StringRef Tag;
+};
+
+/// A null value.
+///
+/// Example:
+/// !!null null
+class NullNode final : public Node {
+ void anchor() override;
+
+public:
+ NullNode(std::unique_ptr<Document> &D)
+ : Node(NK_Null, D, StringRef(), StringRef()) {}
+
+ static bool classof(const Node *N) { return N->getType() == NK_Null; }
+};
+
+/// A scalar node is an opaque datum that can be presented as a
+/// series of zero or more Unicode scalar values.
+///
+/// Example:
+/// Adena
+class ScalarNode final : public Node {
+ void anchor() override;
+
+public:
+ ScalarNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag,
+ StringRef Val)
+ : Node(NK_Scalar, D, Anchor, Tag), Value(Val) {
+ SMLoc Start = SMLoc::getFromPointer(Val.begin());
+ SMLoc End = SMLoc::getFromPointer(Val.end());
+ SourceRange = SMRange(Start, End);
+ }
+
+ // Return Value without any escaping or folding or other fun YAML stuff. This
+ // is the exact bytes that are contained in the file (after conversion to
+ // utf8).
+ StringRef getRawValue() const { return Value; }
+
+ /// Gets the value of this node as a StringRef.
+ ///
+ /// \param Storage is used to store the content of the returned StringRef if
+ /// it requires any modification from how it appeared in the source.
+ /// This happens with escaped characters and multi-line literals.
+ StringRef getValue(SmallVectorImpl<char> &Storage) const;
+
+ static bool classof(const Node *N) {
+ return N->getType() == NK_Scalar;
+ }
+
+private:
+ StringRef Value;
+
+ StringRef unescapeDoubleQuoted(StringRef UnquotedValue,
+ StringRef::size_type Start,
+ SmallVectorImpl<char> &Storage) const;
+};
+
+/// A block scalar node is an opaque datum that can be presented as a
+/// series of zero or more Unicode scalar values.
+///
+/// Example:
+/// |
+/// Hello
+/// World
+class BlockScalarNode final : public Node {
+ void anchor() override;
+
+public:
+ BlockScalarNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag,
+ StringRef Value, StringRef RawVal)
+ : Node(NK_BlockScalar, D, Anchor, Tag), Value(Value) {
+ SMLoc Start = SMLoc::getFromPointer(RawVal.begin());
+ SMLoc End = SMLoc::getFromPointer(RawVal.end());
+ SourceRange = SMRange(Start, End);
+ }
+
+ /// Gets the value of this node as a StringRef.
+ StringRef getValue() const { return Value; }
+
+ static bool classof(const Node *N) {
+ return N->getType() == NK_BlockScalar;
+ }
+
+private:
+ StringRef Value;
+};
+
+/// A key and value pair. While not technically a Node under the YAML
+/// representation graph, it is easier to treat them this way.
+///
+/// TODO: Consider making this not a child of Node.
+///
+/// Example:
+/// Section: .text
+class KeyValueNode final : public Node {
+ void anchor() override;
+
+public:
+ KeyValueNode(std::unique_ptr<Document> &D)
+ : Node(NK_KeyValue, D, StringRef(), StringRef()) {}
+
+ /// Parse and return the key.
+ ///
+ /// This may be called multiple times.
+ ///
+ /// \returns The key, or nullptr if failed() == true.
+ Node *getKey();
+
+ /// Parse and return the value.
+ ///
+ /// This may be called multiple times.
+ ///
+ /// \returns The value, or nullptr if failed() == true.
+ Node *getValue();
+
+ void skip() override {
+ if (Node *Key = getKey()) {
+ Key->skip();
+ if (Node *Val = getValue())
+ Val->skip();
+ }
+ }
+
+ static bool classof(const Node *N) {
+ return N->getType() == NK_KeyValue;
+ }
+
+private:
+ Node *Key = nullptr;
+ Node *Value = nullptr;
+};
+
+/// This is an iterator abstraction over YAML collections shared by both
+/// sequences and maps.
+///
+/// BaseT must have a ValueT* member named CurrentEntry and a member function
+/// increment() which must set CurrentEntry to 0 to create an end iterator.
+template <class BaseT, class ValueT> class basic_collection_iterator {
+public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = ValueT;
+ using difference_type = std::ptrdiff_t;
+ using pointer = value_type *;
+ using reference = value_type &;
+
+ basic_collection_iterator() = default;
+ basic_collection_iterator(BaseT *B) : Base(B) {}
+
+ ValueT *operator->() const {
+ assert(Base && Base->CurrentEntry && "Attempted to access end iterator!");
+ return Base->CurrentEntry;
+ }
+
+ ValueT &operator*() const {
+ assert(Base && Base->CurrentEntry &&
+ "Attempted to dereference end iterator!");
+ return *Base->CurrentEntry;
+ }
+
+ operator ValueT *() const {
+ assert(Base && Base->CurrentEntry && "Attempted to access end iterator!");
+ return Base->CurrentEntry;
+ }
+
+ /// Note on EqualityComparable:
+ ///
+ /// The iterator is not re-entrant,
+ /// it is meant to be used for parsing YAML on-demand
+ /// Once iteration started - it can point only to one entry at a time
+ /// hence Base.CurrentEntry and Other.Base.CurrentEntry are equal
+ /// iff Base and Other.Base are equal.
+ bool operator==(const basic_collection_iterator &Other) const {
+ if (Base && (Base == Other.Base)) {
+ assert((Base->CurrentEntry == Other.Base->CurrentEntry)
+ && "Equal Bases expected to point to equal Entries");
+ }
+
+ return Base == Other.Base;
+ }
+
+ bool operator!=(const basic_collection_iterator &Other) const {
+ return !(Base == Other.Base);
+ }
+
+ basic_collection_iterator &operator++() {
+ assert(Base && "Attempted to advance iterator past end!");
+ Base->increment();
+ // Create an end iterator.
+ if (!Base->CurrentEntry)
+ Base = nullptr;
+ return *this;
+ }
+
+private:
+ BaseT *Base = nullptr;
+};
+
+// The following two templates are used for both MappingNode and Sequence Node.
+template <class CollectionType>
+typename CollectionType::iterator begin(CollectionType &C) {
+ assert(C.IsAtBeginning && "You may only iterate over a collection once!");
+ C.IsAtBeginning = false;
+ typename CollectionType::iterator ret(&C);
+ ++ret;
+ return ret;
+}
+
+template <class CollectionType> void skip(CollectionType &C) {
+ // TODO: support skipping from the middle of a parsed collection ;/
+ assert((C.IsAtBeginning || C.IsAtEnd) && "Cannot skip mid parse!");
+ if (C.IsAtBeginning)
+ for (typename CollectionType::iterator i = begin(C), e = C.end(); i != e;
+ ++i)
+ i->skip();
+}
+
+/// Represents a YAML map created from either a block map for a flow map.
+///
+/// This parses the YAML stream as increment() is called.
+///
+/// Example:
+/// Name: _main
+/// Scope: Global
+class MappingNode final : public Node {
+ void anchor() override;
+
+public:
+ enum MappingType {
+ MT_Block,
+ MT_Flow,
+ MT_Inline ///< An inline mapping node is used for "[key: value]".
+ };
+
+ MappingNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag,
+ MappingType MT)
+ : Node(NK_Mapping, D, Anchor, Tag), Type(MT) {}
+
+ friend class basic_collection_iterator<MappingNode, KeyValueNode>;
+
+ using iterator = basic_collection_iterator<MappingNode, KeyValueNode>;
+
+ template <class T> friend typename T::iterator yaml::begin(T &);
+ template <class T> friend void yaml::skip(T &);
+
+ iterator begin() { return yaml::begin(*this); }
+
+ iterator end() { return iterator(); }
+
+ void skip() override { yaml::skip(*this); }
+
+ static bool classof(const Node *N) {
+ return N->getType() == NK_Mapping;
+ }
+
+private:
+ MappingType Type;
+ bool IsAtBeginning = true;
+ bool IsAtEnd = false;
+ KeyValueNode *CurrentEntry = nullptr;
+
+ void increment();
+};
+
+/// Represents a YAML sequence created from either a block sequence for a
+/// flow sequence.
+///
+/// This parses the YAML stream as increment() is called.
+///
+/// Example:
+/// - Hello
+/// - World
+class SequenceNode final : public Node {
+ void anchor() override;
+
+public:
+ enum SequenceType {
+ ST_Block,
+ ST_Flow,
+ // Use for:
+ //
+ // key:
+ // - val1
+ // - val2
+ //
+ // As a BlockMappingEntry and BlockEnd are not created in this case.
+ ST_Indentless
+ };
+
+ SequenceNode(std::unique_ptr<Document> &D, StringRef Anchor, StringRef Tag,
+ SequenceType ST)
+ : Node(NK_Sequence, D, Anchor, Tag), SeqType(ST) {}
+
+ friend class basic_collection_iterator<SequenceNode, Node>;
+
+ using iterator = basic_collection_iterator<SequenceNode, Node>;
+
+ template <class T> friend typename T::iterator yaml::begin(T &);
+ template <class T> friend void yaml::skip(T &);
+
+ void increment();
+
+ iterator begin() { return yaml::begin(*this); }
+
+ iterator end() { return iterator(); }
+
+ void skip() override { yaml::skip(*this); }
+
+ static bool classof(const Node *N) {
+ return N->getType() == NK_Sequence;
+ }
+
+private:
+ SequenceType SeqType;
+ bool IsAtBeginning = true;
+ bool IsAtEnd = false;
+ bool WasPreviousTokenFlowEntry = true; // Start with an imaginary ','.
+ Node *CurrentEntry = nullptr;
+};
+
+/// Represents an alias to a Node with an anchor.
+///
+/// Example:
+/// *AnchorName
+class AliasNode final : public Node {
+ void anchor() override;
+
+public:
+ AliasNode(std::unique_ptr<Document> &D, StringRef Val)
+ : Node(NK_Alias, D, StringRef(), StringRef()), Name(Val) {}
+
+ StringRef getName() const { return Name; }
+
+ static bool classof(const Node *N) { return N->getType() == NK_Alias; }
+
+private:
+ StringRef Name;
+};
+
+/// A YAML Stream is a sequence of Documents. A document contains a root
+/// node.
+class Document {
+public:
+ Document(Stream &ParentStream);
+
+ /// Root for parsing a node. Returns a single node.
+ Node *parseBlockNode();
+
+ /// Finish parsing the current document and return true if there are
+ /// more. Return false otherwise.
+ bool skip();
+
+ /// Parse and return the root level node.
+ Node *getRoot() {
+ if (Root)
+ return Root;
+ return Root = parseBlockNode();
+ }
+
+ const std::map<StringRef, StringRef> &getTagMap() const { return TagMap; }
+
+private:
+ friend class Node;
+ friend class document_iterator;
+
+ /// Stream to read tokens from.
+ Stream &stream;
+
+ /// Used to allocate nodes to. All are destroyed without calling their
+ /// destructor when the document is destroyed.
+ BumpPtrAllocator NodeAllocator;
+
+ /// The root node. Used to support skipping a partially parsed
+ /// document.
+ Node *Root;
+
+ /// Maps tag prefixes to their expansion.
+ std::map<StringRef, StringRef> TagMap;
+
+ Token &peekNext();
+ Token getNext();
+ void setError(const Twine &Message, Token &Location) const;
+ bool failed() const;
+
+ /// Parse %BLAH directives and return true if any were encountered.
+ bool parseDirectives();
+
+ /// Parse %YAML
+ void parseYAMLDirective();
+
+ /// Parse %TAG
+ void parseTAGDirective();
+
+ /// Consume the next token and error if it is not \a TK.
+ bool expectToken(int TK);
+};
+
+/// Iterator abstraction for Documents over a Stream.
+class document_iterator {
+public:
+ document_iterator() = default;
+ document_iterator(std::unique_ptr<Document> &D) : Doc(&D) {}
+
+ bool operator==(const document_iterator &Other) const {
+ if (isAtEnd() || Other.isAtEnd())
+ return isAtEnd() && Other.isAtEnd();
+
+ return Doc == Other.Doc;
+ }
+ bool operator!=(const document_iterator &Other) const {
+ return !(*this == Other);
+ }
+
+ document_iterator operator++() {
+ assert(Doc && "incrementing iterator past the end.");
+ if (!(*Doc)->skip()) {
+ Doc->reset(nullptr);
+ } else {
+ Stream &S = (*Doc)->stream;
+ Doc->reset(new Document(S));
+ }
+ return *this;
+ }
+
+ Document &operator*() { return **Doc; }
+
+ std::unique_ptr<Document> &operator->() { return *Doc; }
+
+private:
+ bool isAtEnd() const { return !Doc || !*Doc; }
+
+ std::unique_ptr<Document> *Doc = nullptr;
+};
+
+} // end namespace yaml
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_YAMLPARSER_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/YAMLTraits.h b/contrib/libs/llvm16/include/llvm/Support/YAMLTraits.h
new file mode 100644
index 00000000000..80cecb20573
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/YAMLTraits.h
@@ -0,0 +1,2149 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/YAMLTraits.h --------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_YAMLTRAITS_H
+#define LLVM_SUPPORT_YAMLTRAITS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/AlignOf.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <map>
+#include <memory>
+#include <new>
+#include <optional>
+#include <string>
+#include <system_error>
+#include <type_traits>
+#include <vector>
+
+namespace llvm {
+
+class VersionTuple;
+
+namespace yaml {
+
+enum class NodeKind : uint8_t {
+ Scalar,
+ Map,
+ Sequence,
+};
+
+struct EmptyContext {};
+
+/// This class should be specialized by any type that needs to be converted
+/// to/from a YAML mapping. For example:
+///
+/// struct MappingTraits<MyStruct> {
+/// static void mapping(IO &io, MyStruct &s) {
+/// io.mapRequired("name", s.name);
+/// io.mapRequired("size", s.size);
+/// io.mapOptional("age", s.age);
+/// }
+/// };
+template<class T>
+struct MappingTraits {
+ // Must provide:
+ // static void mapping(IO &io, T &fields);
+ // Optionally may provide:
+ // static std::string validate(IO &io, T &fields);
+ // static void enumInput(IO &io, T &value);
+ //
+ // The optional flow flag will cause generated YAML to use a flow mapping
+ // (e.g. { a: 0, b: 1 }):
+ // static const bool flow = true;
+};
+
+/// This class is similar to MappingTraits<T> but allows you to pass in
+/// additional context for each map operation. For example:
+///
+/// struct MappingContextTraits<MyStruct, MyContext> {
+/// static void mapping(IO &io, MyStruct &s, MyContext &c) {
+/// io.mapRequired("name", s.name);
+/// io.mapRequired("size", s.size);
+/// io.mapOptional("age", s.age);
+/// ++c.TimesMapped;
+/// }
+/// };
+template <class T, class Context> struct MappingContextTraits {
+ // Must provide:
+ // static void mapping(IO &io, T &fields, Context &Ctx);
+ // Optionally may provide:
+ // static std::string validate(IO &io, T &fields, Context &Ctx);
+ //
+ // The optional flow flag will cause generated YAML to use a flow mapping
+ // (e.g. { a: 0, b: 1 }):
+ // static const bool flow = true;
+};
+
+/// This class should be specialized by any integral type that converts
+/// to/from a YAML scalar where there is a one-to-one mapping between
+/// in-memory values and a string in YAML. For example:
+///
+/// struct ScalarEnumerationTraits<Colors> {
+/// static void enumeration(IO &io, Colors &value) {
+/// io.enumCase(value, "red", cRed);
+/// io.enumCase(value, "blue", cBlue);
+/// io.enumCase(value, "green", cGreen);
+/// }
+/// };
+template <typename T, typename Enable = void> struct ScalarEnumerationTraits {
+ // Must provide:
+ // static void enumeration(IO &io, T &value);
+};
+
+/// This class should be specialized by any integer type that is a union
+/// of bit values and the YAML representation is a flow sequence of
+/// strings. For example:
+///
+/// struct ScalarBitSetTraits<MyFlags> {
+/// static void bitset(IO &io, MyFlags &value) {
+/// io.bitSetCase(value, "big", flagBig);
+/// io.bitSetCase(value, "flat", flagFlat);
+/// io.bitSetCase(value, "round", flagRound);
+/// }
+/// };
+template <typename T, typename Enable = void> struct ScalarBitSetTraits {
+ // Must provide:
+ // static void bitset(IO &io, T &value);
+};
+
+/// Describe which type of quotes should be used when quoting is necessary.
+/// Some non-printable characters need to be double-quoted, while some others
+/// are fine with simple-quoting, and some don't need any quoting.
+enum class QuotingType { None, Single, Double };
+
+/// This class should be specialized by type that requires custom conversion
+/// to/from a yaml scalar. For example:
+///
+/// template<>
+/// struct ScalarTraits<MyType> {
+/// static void output(const MyType &val, void*, llvm::raw_ostream &out) {
+/// // stream out custom formatting
+/// out << llvm::format("%x", val);
+/// }
+/// static StringRef input(StringRef scalar, void*, MyType &value) {
+/// // parse scalar and set `value`
+/// // return empty string on success, or error string
+/// return StringRef();
+/// }
+/// static QuotingType mustQuote(StringRef) { return QuotingType::Single; }
+/// };
+template <typename T, typename Enable = void> struct ScalarTraits {
+ // Must provide:
+ //
+ // Function to write the value as a string:
+ // static void output(const T &value, void *ctxt, llvm::raw_ostream &out);
+ //
+ // Function to convert a string to a value. Returns the empty
+ // StringRef on success or an error string if string is malformed:
+ // static StringRef input(StringRef scalar, void *ctxt, T &value);
+ //
+ // Function to determine if the value should be quoted.
+ // static QuotingType mustQuote(StringRef);
+};
+
+/// This class should be specialized by type that requires custom conversion
+/// to/from a YAML literal block scalar. For example:
+///
+/// template <>
+/// struct BlockScalarTraits<MyType> {
+/// static void output(const MyType &Value, void*, llvm::raw_ostream &Out)
+/// {
+/// // stream out custom formatting
+/// Out << Value;
+/// }
+/// static StringRef input(StringRef Scalar, void*, MyType &Value) {
+/// // parse scalar and set `value`
+/// // return empty string on success, or error string
+/// return StringRef();
+/// }
+/// };
+template <typename T>
+struct BlockScalarTraits {
+ // Must provide:
+ //
+ // Function to write the value as a string:
+ // static void output(const T &Value, void *ctx, llvm::raw_ostream &Out);
+ //
+ // Function to convert a string to a value. Returns the empty
+ // StringRef on success or an error string if string is malformed:
+ // static StringRef input(StringRef Scalar, void *ctxt, T &Value);
+ //
+ // Optional:
+ // static StringRef inputTag(T &Val, std::string Tag)
+ // static void outputTag(const T &Val, raw_ostream &Out)
+};
+
+/// This class should be specialized by type that requires custom conversion
+/// to/from a YAML scalar with optional tags. For example:
+///
+/// template <>
+/// struct TaggedScalarTraits<MyType> {
+/// static void output(const MyType &Value, void*, llvm::raw_ostream
+/// &ScalarOut, llvm::raw_ostream &TagOut)
+/// {
+/// // stream out custom formatting including optional Tag
+/// Out << Value;
+/// }
+/// static StringRef input(StringRef Scalar, StringRef Tag, void*, MyType
+/// &Value) {
+/// // parse scalar and set `value`
+/// // return empty string on success, or error string
+/// return StringRef();
+/// }
+/// static QuotingType mustQuote(const MyType &Value, StringRef) {
+/// return QuotingType::Single;
+/// }
+/// };
+template <typename T> struct TaggedScalarTraits {
+ // Must provide:
+ //
+ // Function to write the value and tag as strings:
+ // static void output(const T &Value, void *ctx, llvm::raw_ostream &ScalarOut,
+ // llvm::raw_ostream &TagOut);
+ //
+ // Function to convert a string to a value. Returns the empty
+ // StringRef on success or an error string if string is malformed:
+ // static StringRef input(StringRef Scalar, StringRef Tag, void *ctxt, T
+ // &Value);
+ //
+ // Function to determine if the value should be quoted.
+ // static QuotingType mustQuote(const T &Value, StringRef Scalar);
+};
+
+/// This class should be specialized by any type that needs to be converted
+/// to/from a YAML sequence. For example:
+///
+/// template<>
+/// struct SequenceTraits<MyContainer> {
+/// static size_t size(IO &io, MyContainer &seq) {
+/// return seq.size();
+/// }
+/// static MyType& element(IO &, MyContainer &seq, size_t index) {
+/// if ( index >= seq.size() )
+/// seq.resize(index+1);
+/// return seq[index];
+/// }
+/// };
+template<typename T, typename EnableIf = void>
+struct SequenceTraits {
+ // Must provide:
+ // static size_t size(IO &io, T &seq);
+ // static T::value_type& element(IO &io, T &seq, size_t index);
+ //
+ // The following is option and will cause generated YAML to use
+ // a flow sequence (e.g. [a,b,c]).
+ // static const bool flow = true;
+};
+
+/// This class should be specialized by any type for which vectors of that
+/// type need to be converted to/from a YAML sequence.
+template<typename T, typename EnableIf = void>
+struct SequenceElementTraits {
+ // Must provide:
+ // static const bool flow;
+};
+
+/// This class should be specialized by any type that needs to be converted
+/// to/from a list of YAML documents.
+template<typename T>
+struct DocumentListTraits {
+ // Must provide:
+ // static size_t size(IO &io, T &seq);
+ // static T::value_type& element(IO &io, T &seq, size_t index);
+};
+
+/// This class should be specialized by any type that needs to be converted
+/// to/from a YAML mapping in the case where the names of the keys are not known
+/// in advance, e.g. a string map.
+template <typename T>
+struct CustomMappingTraits {
+ // static void inputOne(IO &io, StringRef key, T &elem);
+ // static void output(IO &io, T &elem);
+};
+
+/// This class should be specialized by any type that can be represented as
+/// a scalar, map, or sequence, decided dynamically. For example:
+///
+/// typedef std::unique_ptr<MyBase> MyPoly;
+///
+/// template<>
+/// struct PolymorphicTraits<MyPoly> {
+/// static NodeKind getKind(const MyPoly &poly) {
+/// return poly->getKind();
+/// }
+/// static MyScalar& getAsScalar(MyPoly &poly) {
+/// if (!poly || !isa<MyScalar>(poly))
+/// poly.reset(new MyScalar());
+/// return *cast<MyScalar>(poly.get());
+/// }
+/// // ...
+/// };
+template <typename T> struct PolymorphicTraits {
+ // Must provide:
+ // static NodeKind getKind(const T &poly);
+ // static scalar_type &getAsScalar(T &poly);
+ // static map_type &getAsMap(T &poly);
+ // static sequence_type &getAsSequence(T &poly);
+};
+
+// Only used for better diagnostics of missing traits
+template <typename T>
+struct MissingTrait;
+
+// Test if ScalarEnumerationTraits<T> is defined on type T.
+template <class T>
+struct has_ScalarEnumerationTraits
+{
+ using Signature_enumeration = void (*)(class IO&, T&);
+
+ template <typename U>
+ static char test(SameType<Signature_enumeration, &U::enumeration>*);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value =
+ (sizeof(test<ScalarEnumerationTraits<T>>(nullptr)) == 1);
+};
+
+// Test if ScalarBitSetTraits<T> is defined on type T.
+template <class T>
+struct has_ScalarBitSetTraits
+{
+ using Signature_bitset = void (*)(class IO&, T&);
+
+ template <typename U>
+ static char test(SameType<Signature_bitset, &U::bitset>*);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value = (sizeof(test<ScalarBitSetTraits<T>>(nullptr)) == 1);
+};
+
+// Test if ScalarTraits<T> is defined on type T.
+template <class T>
+struct has_ScalarTraits
+{
+ using Signature_input = StringRef (*)(StringRef, void*, T&);
+ using Signature_output = void (*)(const T&, void*, raw_ostream&);
+ using Signature_mustQuote = QuotingType (*)(StringRef);
+
+ template <typename U>
+ static char test(SameType<Signature_input, &U::input> *,
+ SameType<Signature_output, &U::output> *,
+ SameType<Signature_mustQuote, &U::mustQuote> *);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value =
+ (sizeof(test<ScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1);
+};
+
+// Test if BlockScalarTraits<T> is defined on type T.
+template <class T>
+struct has_BlockScalarTraits
+{
+ using Signature_input = StringRef (*)(StringRef, void *, T &);
+ using Signature_output = void (*)(const T &, void *, raw_ostream &);
+
+ template <typename U>
+ static char test(SameType<Signature_input, &U::input> *,
+ SameType<Signature_output, &U::output> *);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value =
+ (sizeof(test<BlockScalarTraits<T>>(nullptr, nullptr)) == 1);
+};
+
+// Test if TaggedScalarTraits<T> is defined on type T.
+template <class T> struct has_TaggedScalarTraits {
+ using Signature_input = StringRef (*)(StringRef, StringRef, void *, T &);
+ using Signature_output = void (*)(const T &, void *, raw_ostream &,
+ raw_ostream &);
+ using Signature_mustQuote = QuotingType (*)(const T &, StringRef);
+
+ template <typename U>
+ static char test(SameType<Signature_input, &U::input> *,
+ SameType<Signature_output, &U::output> *,
+ SameType<Signature_mustQuote, &U::mustQuote> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value =
+ (sizeof(test<TaggedScalarTraits<T>>(nullptr, nullptr, nullptr)) == 1);
+};
+
+// Test if MappingContextTraits<T> is defined on type T.
+template <class T, class Context> struct has_MappingTraits {
+ using Signature_mapping = void (*)(class IO &, T &, Context &);
+
+ template <typename U>
+ static char test(SameType<Signature_mapping, &U::mapping>*);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value =
+ (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
+};
+
+// Test if MappingTraits<T> is defined on type T.
+template <class T> struct has_MappingTraits<T, EmptyContext> {
+ using Signature_mapping = void (*)(class IO &, T &);
+
+ template <typename U>
+ static char test(SameType<Signature_mapping, &U::mapping> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
+};
+
+// Test if MappingContextTraits<T>::validate() is defined on type T.
+template <class T, class Context> struct has_MappingValidateTraits {
+ using Signature_validate = std::string (*)(class IO &, T &, Context &);
+
+ template <typename U>
+ static char test(SameType<Signature_validate, &U::validate>*);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value =
+ (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
+};
+
+// Test if MappingTraits<T>::validate() is defined on type T.
+template <class T> struct has_MappingValidateTraits<T, EmptyContext> {
+ using Signature_validate = std::string (*)(class IO &, T &);
+
+ template <typename U>
+ static char test(SameType<Signature_validate, &U::validate> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
+};
+
+// Test if MappingContextTraits<T>::enumInput() is defined on type T.
+template <class T, class Context> struct has_MappingEnumInputTraits {
+ using Signature_validate = void (*)(class IO &, T &);
+
+ template <typename U>
+ static char test(SameType<Signature_validate, &U::enumInput> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value =
+ (sizeof(test<MappingContextTraits<T, Context>>(nullptr)) == 1);
+};
+
+// Test if MappingTraits<T>::enumInput() is defined on type T.
+template <class T> struct has_MappingEnumInputTraits<T, EmptyContext> {
+ using Signature_validate = void (*)(class IO &, T &);
+
+ template <typename U>
+ static char test(SameType<Signature_validate, &U::enumInput> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value = (sizeof(test<MappingTraits<T>>(nullptr)) == 1);
+};
+
+// Test if SequenceTraits<T> is defined on type T.
+template <class T>
+struct has_SequenceMethodTraits
+{
+ using Signature_size = size_t (*)(class IO&, T&);
+
+ template <typename U>
+ static char test(SameType<Signature_size, &U::size>*);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value = (sizeof(test<SequenceTraits<T>>(nullptr)) == 1);
+};
+
+// Test if CustomMappingTraits<T> is defined on type T.
+template <class T>
+struct has_CustomMappingTraits
+{
+ using Signature_input = void (*)(IO &io, StringRef key, T &v);
+
+ template <typename U>
+ static char test(SameType<Signature_input, &U::inputOne>*);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value =
+ (sizeof(test<CustomMappingTraits<T>>(nullptr)) == 1);
+};
+
+// has_FlowTraits<int> will cause an error with some compilers because
+// it subclasses int. Using this wrapper only instantiates the
+// real has_FlowTraits only if the template type is a class.
+template <typename T, bool Enabled = std::is_class<T>::value>
+class has_FlowTraits
+{
+public:
+ static const bool value = false;
+};
+
+// Some older gcc compilers don't support straight forward tests
+// for members, so test for ambiguity cause by the base and derived
+// classes both defining the member.
+template <class T>
+struct has_FlowTraits<T, true>
+{
+ struct Fallback { bool flow; };
+ struct Derived : T, Fallback { };
+
+ template<typename C>
+ static char (&f(SameType<bool Fallback::*, &C::flow>*))[1];
+
+ template<typename C>
+ static char (&f(...))[2];
+
+ static bool const value = sizeof(f<Derived>(nullptr)) == 2;
+};
+
+// Test if SequenceTraits<T> is defined on type T
+template<typename T>
+struct has_SequenceTraits : public std::integral_constant<bool,
+ has_SequenceMethodTraits<T>::value > { };
+
+// Test if DocumentListTraits<T> is defined on type T
+template <class T>
+struct has_DocumentListTraits
+{
+ using Signature_size = size_t (*)(class IO &, T &);
+
+ template <typename U>
+ static char test(SameType<Signature_size, &U::size>*);
+
+ template <typename U>
+ static double test(...);
+
+ static bool const value = (sizeof(test<DocumentListTraits<T>>(nullptr))==1);
+};
+
+template <class T> struct has_PolymorphicTraits {
+ using Signature_getKind = NodeKind (*)(const T &);
+
+ template <typename U>
+ static char test(SameType<Signature_getKind, &U::getKind> *);
+
+ template <typename U> static double test(...);
+
+ static bool const value = (sizeof(test<PolymorphicTraits<T>>(nullptr)) == 1);
+};
+
+inline bool isNumeric(StringRef S) {
+ const auto skipDigits = [](StringRef Input) {
+ return Input.ltrim("0123456789");
+ };
+
+ // Make S.front() and S.drop_front().front() (if S.front() is [+-]) calls
+ // safe.
+ if (S.empty() || S.equals("+") || S.equals("-"))
+ return false;
+
+ if (S.equals(".nan") || S.equals(".NaN") || S.equals(".NAN"))
+ return true;
+
+ // Infinity and decimal numbers can be prefixed with sign.
+ StringRef Tail = (S.front() == '-' || S.front() == '+') ? S.drop_front() : S;
+
+ // Check for infinity first, because checking for hex and oct numbers is more
+ // expensive.
+ if (Tail.equals(".inf") || Tail.equals(".Inf") || Tail.equals(".INF"))
+ return true;
+
+ // Section 10.3.2 Tag Resolution
+ // YAML 1.2 Specification prohibits Base 8 and Base 16 numbers prefixed with
+ // [-+], so S should be used instead of Tail.
+ if (S.startswith("0o"))
+ return S.size() > 2 &&
+ S.drop_front(2).find_first_not_of("01234567") == StringRef::npos;
+
+ if (S.startswith("0x"))
+ return S.size() > 2 && S.drop_front(2).find_first_not_of(
+ "0123456789abcdefABCDEF") == StringRef::npos;
+
+ // Parse float: [-+]? (\. [0-9]+ | [0-9]+ (\. [0-9]* )?) ([eE] [-+]? [0-9]+)?
+ S = Tail;
+
+ // Handle cases when the number starts with '.' and hence needs at least one
+ // digit after dot (as opposed by number which has digits before the dot), but
+ // doesn't have one.
+ if (S.startswith(".") &&
+ (S.equals(".") ||
+ (S.size() > 1 && std::strchr("0123456789", S[1]) == nullptr)))
+ return false;
+
+ if (S.startswith("E") || S.startswith("e"))
+ return false;
+
+ enum ParseState {
+ Default,
+ FoundDot,
+ FoundExponent,
+ };
+ ParseState State = Default;
+
+ S = skipDigits(S);
+
+ // Accept decimal integer.
+ if (S.empty())
+ return true;
+
+ if (S.front() == '.') {
+ State = FoundDot;
+ S = S.drop_front();
+ } else if (S.front() == 'e' || S.front() == 'E') {
+ State = FoundExponent;
+ S = S.drop_front();
+ } else {
+ return false;
+ }
+
+ if (State == FoundDot) {
+ S = skipDigits(S);
+ if (S.empty())
+ return true;
+
+ if (S.front() == 'e' || S.front() == 'E') {
+ State = FoundExponent;
+ S = S.drop_front();
+ } else {
+ return false;
+ }
+ }
+
+ assert(State == FoundExponent && "Should have found exponent at this point.");
+ if (S.empty())
+ return false;
+
+ if (S.front() == '+' || S.front() == '-') {
+ S = S.drop_front();
+ if (S.empty())
+ return false;
+ }
+
+ return skipDigits(S).empty();
+}
+
+inline bool isNull(StringRef S) {
+ return S.equals("null") || S.equals("Null") || S.equals("NULL") ||
+ S.equals("~");
+}
+
+inline bool isBool(StringRef S) {
+ // FIXME: using parseBool is causing multiple tests to fail.
+ return S.equals("true") || S.equals("True") || S.equals("TRUE") ||
+ S.equals("false") || S.equals("False") || S.equals("FALSE");
+}
+
+// 5.1. Character Set
+// The allowed character range explicitly excludes the C0 control block #x0-#x1F
+// (except for TAB #x9, LF #xA, and CR #xD which are allowed), DEL #x7F, the C1
+// control block #x80-#x9F (except for NEL #x85 which is allowed), the surrogate
+// block #xD800-#xDFFF, #xFFFE, and #xFFFF.
+inline QuotingType needsQuotes(StringRef S) {
+ if (S.empty())
+ return QuotingType::Single;
+
+ QuotingType MaxQuotingNeeded = QuotingType::None;
+ if (isSpace(static_cast<unsigned char>(S.front())) ||
+ isSpace(static_cast<unsigned char>(S.back())))
+ MaxQuotingNeeded = QuotingType::Single;
+ if (isNull(S))
+ MaxQuotingNeeded = QuotingType::Single;
+ if (isBool(S))
+ MaxQuotingNeeded = QuotingType::Single;
+ if (isNumeric(S))
+ MaxQuotingNeeded = QuotingType::Single;
+
+ // 7.3.3 Plain Style
+ // Plain scalars must not begin with most indicators, as this would cause
+ // ambiguity with other YAML constructs.
+ if (std::strchr(R"(-?:\,[]{}#&*!|>'"%@`)", S[0]) != nullptr)
+ MaxQuotingNeeded = QuotingType::Single;
+
+ for (unsigned char C : S) {
+ // Alphanum is safe.
+ if (isAlnum(C))
+ continue;
+
+ switch (C) {
+ // Safe scalar characters.
+ case '_':
+ case '-':
+ case '^':
+ case '.':
+ case ',':
+ case ' ':
+ // TAB (0x9) is allowed in unquoted strings.
+ case 0x9:
+ continue;
+ // LF(0xA) and CR(0xD) may delimit values and so require at least single
+ // quotes. LLVM YAML parser cannot handle single quoted multiline so use
+ // double quoting to produce valid YAML.
+ case 0xA:
+ case 0xD:
+ return QuotingType::Double;
+ // DEL (0x7F) are excluded from the allowed character range.
+ case 0x7F:
+ return QuotingType::Double;
+ // Forward slash is allowed to be unquoted, but we quote it anyway. We have
+ // many tests that use FileCheck against YAML output, and this output often
+ // contains paths. If we quote backslashes but not forward slashes then
+ // paths will come out either quoted or unquoted depending on which platform
+ // the test is run on, making FileCheck comparisons difficult.
+ case '/':
+ default: {
+ // C0 control block (0x0 - 0x1F) is excluded from the allowed character
+ // range.
+ if (C <= 0x1F)
+ return QuotingType::Double;
+
+ // Always double quote UTF-8.
+ if ((C & 0x80) != 0)
+ return QuotingType::Double;
+
+ // The character is not safe, at least simple quoting needed.
+ MaxQuotingNeeded = QuotingType::Single;
+ }
+ }
+ }
+
+ return MaxQuotingNeeded;
+}
+
+template <typename T, typename Context>
+struct missingTraits
+ : public std::integral_constant<bool,
+ !has_ScalarEnumerationTraits<T>::value &&
+ !has_ScalarBitSetTraits<T>::value &&
+ !has_ScalarTraits<T>::value &&
+ !has_BlockScalarTraits<T>::value &&
+ !has_TaggedScalarTraits<T>::value &&
+ !has_MappingTraits<T, Context>::value &&
+ !has_SequenceTraits<T>::value &&
+ !has_CustomMappingTraits<T>::value &&
+ !has_DocumentListTraits<T>::value &&
+ !has_PolymorphicTraits<T>::value> {};
+
+template <typename T, typename Context>
+struct validatedMappingTraits
+ : public std::integral_constant<
+ bool, has_MappingTraits<T, Context>::value &&
+ has_MappingValidateTraits<T, Context>::value> {};
+
+template <typename T, typename Context>
+struct unvalidatedMappingTraits
+ : public std::integral_constant<
+ bool, has_MappingTraits<T, Context>::value &&
+ !has_MappingValidateTraits<T, Context>::value> {};
+
+// Base class for Input and Output.
+class IO {
+public:
+ IO(void *Ctxt = nullptr);
+ virtual ~IO();
+
+ virtual bool outputting() const = 0;
+
+ virtual unsigned beginSequence() = 0;
+ virtual bool preflightElement(unsigned, void *&) = 0;
+ virtual void postflightElement(void*) = 0;
+ virtual void endSequence() = 0;
+ virtual bool canElideEmptySequence() = 0;
+
+ virtual unsigned beginFlowSequence() = 0;
+ virtual bool preflightFlowElement(unsigned, void *&) = 0;
+ virtual void postflightFlowElement(void*) = 0;
+ virtual void endFlowSequence() = 0;
+
+ virtual bool mapTag(StringRef Tag, bool Default=false) = 0;
+ virtual void beginMapping() = 0;
+ virtual void endMapping() = 0;
+ virtual bool preflightKey(const char*, bool, bool, bool &, void *&) = 0;
+ virtual void postflightKey(void*) = 0;
+ virtual std::vector<StringRef> keys() = 0;
+
+ virtual void beginFlowMapping() = 0;
+ virtual void endFlowMapping() = 0;
+
+ virtual void beginEnumScalar() = 0;
+ virtual bool matchEnumScalar(const char*, bool) = 0;
+ virtual bool matchEnumFallback() = 0;
+ virtual void endEnumScalar() = 0;
+
+ virtual bool beginBitSetScalar(bool &) = 0;
+ virtual bool bitSetMatch(const char*, bool) = 0;
+ virtual void endBitSetScalar() = 0;
+
+ virtual void scalarString(StringRef &, QuotingType) = 0;
+ virtual void blockScalarString(StringRef &) = 0;
+ virtual void scalarTag(std::string &) = 0;
+
+ virtual NodeKind getNodeKind() = 0;
+
+ virtual void setError(const Twine &) = 0;
+ virtual void setAllowUnknownKeys(bool Allow);
+
+ template <typename T>
+ void enumCase(T &Val, const char* Str, const T ConstVal) {
+ if ( matchEnumScalar(Str, outputting() && Val == ConstVal) ) {
+ Val = ConstVal;
+ }
+ }
+
+ // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
+ template <typename T>
+ void enumCase(T &Val, const char* Str, const uint32_t ConstVal) {
+ if ( matchEnumScalar(Str, outputting() && Val == static_cast<T>(ConstVal)) ) {
+ Val = ConstVal;
+ }
+ }
+
+ template <typename FBT, typename T>
+ void enumFallback(T &Val) {
+ if (matchEnumFallback()) {
+ EmptyContext Context;
+ // FIXME: Force integral conversion to allow strong typedefs to convert.
+ FBT Res = static_cast<typename FBT::BaseType>(Val);
+ yamlize(*this, Res, true, Context);
+ Val = static_cast<T>(static_cast<typename FBT::BaseType>(Res));
+ }
+ }
+
+ template <typename T>
+ void bitSetCase(T &Val, const char* Str, const T ConstVal) {
+ if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
+ Val = static_cast<T>(Val | ConstVal);
+ }
+ }
+
+ // allow anonymous enum values to be used with LLVM_YAML_STRONG_TYPEDEF
+ template <typename T>
+ void bitSetCase(T &Val, const char* Str, const uint32_t ConstVal) {
+ if ( bitSetMatch(Str, outputting() && (Val & ConstVal) == ConstVal) ) {
+ Val = static_cast<T>(Val | ConstVal);
+ }
+ }
+
+ template <typename T>
+ void maskedBitSetCase(T &Val, const char *Str, T ConstVal, T Mask) {
+ if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal))
+ Val = Val | ConstVal;
+ }
+
+ template <typename T>
+ void maskedBitSetCase(T &Val, const char *Str, uint32_t ConstVal,
+ uint32_t Mask) {
+ if (bitSetMatch(Str, outputting() && (Val & Mask) == ConstVal))
+ Val = Val | ConstVal;
+ }
+
+ void *getContext() const;
+ void setContext(void *);
+
+ template <typename T> void mapRequired(const char *Key, T &Val) {
+ EmptyContext Ctx;
+ this->processKey(Key, Val, true, Ctx);
+ }
+
+ template <typename T, typename Context>
+ void mapRequired(const char *Key, T &Val, Context &Ctx) {
+ this->processKey(Key, Val, true, Ctx);
+ }
+
+ template <typename T> void mapOptional(const char *Key, T &Val) {
+ EmptyContext Ctx;
+ mapOptionalWithContext(Key, Val, Ctx);
+ }
+
+ template <typename T, typename DefaultT>
+ void mapOptional(const char *Key, T &Val, const DefaultT &Default) {
+ EmptyContext Ctx;
+ mapOptionalWithContext(Key, Val, Default, Ctx);
+ }
+
+ template <typename T, typename Context>
+ std::enable_if_t<has_SequenceTraits<T>::value, void>
+ mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
+ // omit key/value instead of outputting empty sequence
+ if (this->canElideEmptySequence() && !(Val.begin() != Val.end()))
+ return;
+ this->processKey(Key, Val, false, Ctx);
+ }
+
+ template <typename T, typename Context>
+ void mapOptionalWithContext(const char *Key, std::optional<T> &Val,
+ Context &Ctx) {
+ this->processKeyWithDefault(Key, Val, std::optional<T>(),
+ /*Required=*/false, Ctx);
+ }
+
+ template <typename T, typename Context>
+ std::enable_if_t<!has_SequenceTraits<T>::value, void>
+ mapOptionalWithContext(const char *Key, T &Val, Context &Ctx) {
+ this->processKey(Key, Val, false, Ctx);
+ }
+
+ template <typename T, typename Context, typename DefaultT>
+ void mapOptionalWithContext(const char *Key, T &Val, const DefaultT &Default,
+ Context &Ctx) {
+ static_assert(std::is_convertible<DefaultT, T>::value,
+ "Default type must be implicitly convertible to value type!");
+ this->processKeyWithDefault(Key, Val, static_cast<const T &>(Default),
+ false, Ctx);
+ }
+
+private:
+ template <typename T, typename Context>
+ void processKeyWithDefault(const char *Key, std::optional<T> &Val,
+ const std::optional<T> &DefaultValue,
+ bool Required, Context &Ctx);
+
+ template <typename T, typename Context>
+ void processKeyWithDefault(const char *Key, T &Val, const T &DefaultValue,
+ bool Required, Context &Ctx) {
+ void *SaveInfo;
+ bool UseDefault;
+ const bool sameAsDefault = outputting() && Val == DefaultValue;
+ if ( this->preflightKey(Key, Required, sameAsDefault, UseDefault,
+ SaveInfo) ) {
+ yamlize(*this, Val, Required, Ctx);
+ this->postflightKey(SaveInfo);
+ }
+ else {
+ if ( UseDefault )
+ Val = DefaultValue;
+ }
+ }
+
+ template <typename T, typename Context>
+ void processKey(const char *Key, T &Val, bool Required, Context &Ctx) {
+ void *SaveInfo;
+ bool UseDefault;
+ if ( this->preflightKey(Key, Required, false, UseDefault, SaveInfo) ) {
+ yamlize(*this, Val, Required, Ctx);
+ this->postflightKey(SaveInfo);
+ }
+ }
+
+private:
+ void *Ctxt;
+};
+
+namespace detail {
+
+template <typename T, typename Context>
+void doMapping(IO &io, T &Val, Context &Ctx) {
+ MappingContextTraits<T, Context>::mapping(io, Val, Ctx);
+}
+
+template <typename T> void doMapping(IO &io, T &Val, EmptyContext &Ctx) {
+ MappingTraits<T>::mapping(io, Val);
+}
+
+} // end namespace detail
+
+template <typename T>
+std::enable_if_t<has_ScalarEnumerationTraits<T>::value, void>
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+ io.beginEnumScalar();
+ ScalarEnumerationTraits<T>::enumeration(io, Val);
+ io.endEnumScalar();
+}
+
+template <typename T>
+std::enable_if_t<has_ScalarBitSetTraits<T>::value, void>
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+ bool DoClear;
+ if ( io.beginBitSetScalar(DoClear) ) {
+ if ( DoClear )
+ Val = T();
+ ScalarBitSetTraits<T>::bitset(io, Val);
+ io.endBitSetScalar();
+ }
+}
+
+template <typename T>
+std::enable_if_t<has_ScalarTraits<T>::value, void> yamlize(IO &io, T &Val, bool,
+ EmptyContext &Ctx) {
+ if ( io.outputting() ) {
+ SmallString<128> Storage;
+ raw_svector_ostream Buffer(Storage);
+ ScalarTraits<T>::output(Val, io.getContext(), Buffer);
+ StringRef Str = Buffer.str();
+ io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
+ }
+ else {
+ StringRef Str;
+ io.scalarString(Str, ScalarTraits<T>::mustQuote(Str));
+ StringRef Result = ScalarTraits<T>::input(Str, io.getContext(), Val);
+ if ( !Result.empty() ) {
+ io.setError(Twine(Result));
+ }
+ }
+}
+
+template <typename T>
+std::enable_if_t<has_BlockScalarTraits<T>::value, void>
+yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) {
+ if (YamlIO.outputting()) {
+ std::string Storage;
+ raw_string_ostream Buffer(Storage);
+ BlockScalarTraits<T>::output(Val, YamlIO.getContext(), Buffer);
+ StringRef Str = Buffer.str();
+ YamlIO.blockScalarString(Str);
+ } else {
+ StringRef Str;
+ YamlIO.blockScalarString(Str);
+ StringRef Result =
+ BlockScalarTraits<T>::input(Str, YamlIO.getContext(), Val);
+ if (!Result.empty())
+ YamlIO.setError(Twine(Result));
+ }
+}
+
+template <typename T>
+std::enable_if_t<has_TaggedScalarTraits<T>::value, void>
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+ if (io.outputting()) {
+ std::string ScalarStorage, TagStorage;
+ raw_string_ostream ScalarBuffer(ScalarStorage), TagBuffer(TagStorage);
+ TaggedScalarTraits<T>::output(Val, io.getContext(), ScalarBuffer,
+ TagBuffer);
+ io.scalarTag(TagBuffer.str());
+ StringRef ScalarStr = ScalarBuffer.str();
+ io.scalarString(ScalarStr,
+ TaggedScalarTraits<T>::mustQuote(Val, ScalarStr));
+ } else {
+ std::string Tag;
+ io.scalarTag(Tag);
+ StringRef Str;
+ io.scalarString(Str, QuotingType::None);
+ StringRef Result =
+ TaggedScalarTraits<T>::input(Str, Tag, io.getContext(), Val);
+ if (!Result.empty()) {
+ io.setError(Twine(Result));
+ }
+ }
+}
+
+template <typename T, typename Context>
+std::enable_if_t<validatedMappingTraits<T, Context>::value, void>
+yamlize(IO &io, T &Val, bool, Context &Ctx) {
+ if (has_FlowTraits<MappingTraits<T>>::value)
+ io.beginFlowMapping();
+ else
+ io.beginMapping();
+ if (io.outputting()) {
+ std::string Err = MappingTraits<T>::validate(io, Val);
+ if (!Err.empty()) {
+ errs() << Err << "\n";
+ assert(Err.empty() && "invalid struct trying to be written as yaml");
+ }
+ }
+ detail::doMapping(io, Val, Ctx);
+ if (!io.outputting()) {
+ std::string Err = MappingTraits<T>::validate(io, Val);
+ if (!Err.empty())
+ io.setError(Err);
+ }
+ if (has_FlowTraits<MappingTraits<T>>::value)
+ io.endFlowMapping();
+ else
+ io.endMapping();
+}
+
+template <typename T, typename Context>
+std::enable_if_t<!has_MappingEnumInputTraits<T, Context>::value, bool>
+yamlizeMappingEnumInput(IO &io, T &Val) {
+ return false;
+}
+
+template <typename T, typename Context>
+std::enable_if_t<has_MappingEnumInputTraits<T, Context>::value, bool>
+yamlizeMappingEnumInput(IO &io, T &Val) {
+ if (io.outputting())
+ return false;
+
+ io.beginEnumScalar();
+ MappingTraits<T>::enumInput(io, Val);
+ bool Matched = !io.matchEnumFallback();
+ io.endEnumScalar();
+ return Matched;
+}
+
+template <typename T, typename Context>
+std::enable_if_t<unvalidatedMappingTraits<T, Context>::value, void>
+yamlize(IO &io, T &Val, bool, Context &Ctx) {
+ if (yamlizeMappingEnumInput<T, Context>(io, Val))
+ return;
+ if (has_FlowTraits<MappingTraits<T>>::value) {
+ io.beginFlowMapping();
+ detail::doMapping(io, Val, Ctx);
+ io.endFlowMapping();
+ } else {
+ io.beginMapping();
+ detail::doMapping(io, Val, Ctx);
+ io.endMapping();
+ }
+}
+
+template <typename T>
+std::enable_if_t<has_CustomMappingTraits<T>::value, void>
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+ if ( io.outputting() ) {
+ io.beginMapping();
+ CustomMappingTraits<T>::output(io, Val);
+ io.endMapping();
+ } else {
+ io.beginMapping();
+ for (StringRef key : io.keys())
+ CustomMappingTraits<T>::inputOne(io, key, Val);
+ io.endMapping();
+ }
+}
+
+template <typename T>
+std::enable_if_t<has_PolymorphicTraits<T>::value, void>
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+ switch (io.outputting() ? PolymorphicTraits<T>::getKind(Val)
+ : io.getNodeKind()) {
+ case NodeKind::Scalar:
+ return yamlize(io, PolymorphicTraits<T>::getAsScalar(Val), true, Ctx);
+ case NodeKind::Map:
+ return yamlize(io, PolymorphicTraits<T>::getAsMap(Val), true, Ctx);
+ case NodeKind::Sequence:
+ return yamlize(io, PolymorphicTraits<T>::getAsSequence(Val), true, Ctx);
+ }
+}
+
+template <typename T>
+std::enable_if_t<missingTraits<T, EmptyContext>::value, void>
+yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) {
+ char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
+}
+
+template <typename T, typename Context>
+std::enable_if_t<has_SequenceTraits<T>::value, void>
+yamlize(IO &io, T &Seq, bool, Context &Ctx) {
+ if ( has_FlowTraits< SequenceTraits<T>>::value ) {
+ unsigned incnt = io.beginFlowSequence();
+ unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
+ for(unsigned i=0; i < count; ++i) {
+ void *SaveInfo;
+ if ( io.preflightFlowElement(i, SaveInfo) ) {
+ yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx);
+ io.postflightFlowElement(SaveInfo);
+ }
+ }
+ io.endFlowSequence();
+ }
+ else {
+ unsigned incnt = io.beginSequence();
+ unsigned count = io.outputting() ? SequenceTraits<T>::size(io, Seq) : incnt;
+ for(unsigned i=0; i < count; ++i) {
+ void *SaveInfo;
+ if ( io.preflightElement(i, SaveInfo) ) {
+ yamlize(io, SequenceTraits<T>::element(io, Seq, i), true, Ctx);
+ io.postflightElement(SaveInfo);
+ }
+ }
+ io.endSequence();
+ }
+}
+
+template<>
+struct ScalarTraits<bool> {
+ static void output(const bool &, void* , raw_ostream &);
+ static StringRef input(StringRef, void *, bool &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<StringRef> {
+ static void output(const StringRef &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, StringRef &);
+ static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
+};
+
+template<>
+struct ScalarTraits<std::string> {
+ static void output(const std::string &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, std::string &);
+ static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
+};
+
+template<>
+struct ScalarTraits<uint8_t> {
+ static void output(const uint8_t &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, uint8_t &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<uint16_t> {
+ static void output(const uint16_t &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, uint16_t &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<uint32_t> {
+ static void output(const uint32_t &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, uint32_t &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<uint64_t> {
+ static void output(const uint64_t &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, uint64_t &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<int8_t> {
+ static void output(const int8_t &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, int8_t &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<int16_t> {
+ static void output(const int16_t &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, int16_t &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<int32_t> {
+ static void output(const int32_t &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, int32_t &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<int64_t> {
+ static void output(const int64_t &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, int64_t &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<float> {
+ static void output(const float &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, float &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<double> {
+ static void output(const double &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, double &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+// For endian types, we use existing scalar Traits class for the underlying
+// type. This way endian aware types are supported whenever the traits are
+// defined for the underlying type.
+template <typename value_type, support::endianness endian, size_t alignment>
+struct ScalarTraits<support::detail::packed_endian_specific_integral<
+ value_type, endian, alignment>,
+ std::enable_if_t<has_ScalarTraits<value_type>::value>> {
+ using endian_type =
+ support::detail::packed_endian_specific_integral<value_type, endian,
+ alignment>;
+
+ static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) {
+ ScalarTraits<value_type>::output(static_cast<value_type>(E), Ctx, Stream);
+ }
+
+ static StringRef input(StringRef Str, void *Ctx, endian_type &E) {
+ value_type V;
+ auto R = ScalarTraits<value_type>::input(Str, Ctx, V);
+ E = static_cast<endian_type>(V);
+ return R;
+ }
+
+ static QuotingType mustQuote(StringRef Str) {
+ return ScalarTraits<value_type>::mustQuote(Str);
+ }
+};
+
+template <typename value_type, support::endianness endian, size_t alignment>
+struct ScalarEnumerationTraits<
+ support::detail::packed_endian_specific_integral<value_type, endian,
+ alignment>,
+ std::enable_if_t<has_ScalarEnumerationTraits<value_type>::value>> {
+ using endian_type =
+ support::detail::packed_endian_specific_integral<value_type, endian,
+ alignment>;
+
+ static void enumeration(IO &io, endian_type &E) {
+ value_type V = E;
+ ScalarEnumerationTraits<value_type>::enumeration(io, V);
+ E = V;
+ }
+};
+
+template <typename value_type, support::endianness endian, size_t alignment>
+struct ScalarBitSetTraits<
+ support::detail::packed_endian_specific_integral<value_type, endian,
+ alignment>,
+ std::enable_if_t<has_ScalarBitSetTraits<value_type>::value>> {
+ using endian_type =
+ support::detail::packed_endian_specific_integral<value_type, endian,
+ alignment>;
+ static void bitset(IO &io, endian_type &E) {
+ value_type V = E;
+ ScalarBitSetTraits<value_type>::bitset(io, V);
+ E = V;
+ }
+};
+
+// Utility for use within MappingTraits<>::mapping() method
+// to [de]normalize an object for use with YAML conversion.
+template <typename TNorm, typename TFinal>
+struct MappingNormalization {
+ MappingNormalization(IO &i_o, TFinal &Obj)
+ : io(i_o), BufPtr(nullptr), Result(Obj) {
+ if ( io.outputting() ) {
+ BufPtr = new (&Buffer) TNorm(io, Obj);
+ }
+ else {
+ BufPtr = new (&Buffer) TNorm(io);
+ }
+ }
+
+ ~MappingNormalization() {
+ if ( ! io.outputting() ) {
+ Result = BufPtr->denormalize(io);
+ }
+ BufPtr->~TNorm();
+ }
+
+ TNorm* operator->() { return BufPtr; }
+
+private:
+ using Storage = AlignedCharArrayUnion<TNorm>;
+
+ Storage Buffer;
+ IO &io;
+ TNorm *BufPtr;
+ TFinal &Result;
+};
+
+// Utility for use within MappingTraits<>::mapping() method
+// to [de]normalize an object for use with YAML conversion.
+template <typename TNorm, typename TFinal>
+struct MappingNormalizationHeap {
+ MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator)
+ : io(i_o), Result(Obj) {
+ if ( io.outputting() ) {
+ BufPtr = new (&Buffer) TNorm(io, Obj);
+ }
+ else if (allocator) {
+ BufPtr = allocator->Allocate<TNorm>();
+ new (BufPtr) TNorm(io);
+ } else {
+ BufPtr = new TNorm(io);
+ }
+ }
+
+ ~MappingNormalizationHeap() {
+ if ( io.outputting() ) {
+ BufPtr->~TNorm();
+ }
+ else {
+ Result = BufPtr->denormalize(io);
+ }
+ }
+
+ TNorm* operator->() { return BufPtr; }
+
+private:
+ using Storage = AlignedCharArrayUnion<TNorm>;
+
+ Storage Buffer;
+ IO &io;
+ TNorm *BufPtr = nullptr;
+ TFinal &Result;
+};
+
+///
+/// The Input class is used to parse a yaml document into in-memory structs
+/// and vectors.
+///
+/// It works by using YAMLParser to do a syntax parse of the entire yaml
+/// document, then the Input class builds a graph of HNodes which wraps
+/// each yaml Node. The extra layer is buffering. The low level yaml
+/// parser only lets you look at each node once. The buffering layer lets
+/// you search and interate multiple times. This is necessary because
+/// the mapRequired() method calls may not be in the same order
+/// as the keys in the document.
+///
+class Input : public IO {
+public:
+ // Construct a yaml Input object from a StringRef and optional
+ // user-data. The DiagHandler can be specified to provide
+ // alternative error reporting.
+ Input(StringRef InputContent,
+ void *Ctxt = nullptr,
+ SourceMgr::DiagHandlerTy DiagHandler = nullptr,
+ void *DiagHandlerCtxt = nullptr);
+ Input(MemoryBufferRef Input,
+ void *Ctxt = nullptr,
+ SourceMgr::DiagHandlerTy DiagHandler = nullptr,
+ void *DiagHandlerCtxt = nullptr);
+ ~Input() override;
+
+ // Check if there was an syntax or semantic error during parsing.
+ std::error_code error();
+
+private:
+ bool outputting() const override;
+ bool mapTag(StringRef, bool) override;
+ void beginMapping() override;
+ void endMapping() override;
+ bool preflightKey(const char *, bool, bool, bool &, void *&) override;
+ void postflightKey(void *) override;
+ std::vector<StringRef> keys() override;
+ void beginFlowMapping() override;
+ void endFlowMapping() override;
+ unsigned beginSequence() override;
+ void endSequence() override;
+ bool preflightElement(unsigned index, void *&) override;
+ void postflightElement(void *) override;
+ unsigned beginFlowSequence() override;
+ bool preflightFlowElement(unsigned , void *&) override;
+ void postflightFlowElement(void *) override;
+ void endFlowSequence() override;
+ void beginEnumScalar() override;
+ bool matchEnumScalar(const char*, bool) override;
+ bool matchEnumFallback() override;
+ void endEnumScalar() override;
+ bool beginBitSetScalar(bool &) override;
+ bool bitSetMatch(const char *, bool ) override;
+ void endBitSetScalar() override;
+ void scalarString(StringRef &, QuotingType) override;
+ void blockScalarString(StringRef &) override;
+ void scalarTag(std::string &) override;
+ NodeKind getNodeKind() override;
+ void setError(const Twine &message) override;
+ bool canElideEmptySequence() override;
+
+ class HNode {
+ virtual void anchor();
+
+ public:
+ HNode(Node *n) : _node(n) { }
+ virtual ~HNode() = default;
+
+ static bool classof(const HNode *) { return true; }
+
+ Node *_node;
+ };
+
+ class EmptyHNode : public HNode {
+ void anchor() override;
+
+ public:
+ EmptyHNode(Node *n) : HNode(n) { }
+
+ static bool classof(const HNode *n) { return NullNode::classof(n->_node); }
+
+ static bool classof(const EmptyHNode *) { return true; }
+ };
+
+ class ScalarHNode : public HNode {
+ void anchor() override;
+
+ public:
+ ScalarHNode(Node *n, StringRef s) : HNode(n), _value(s) { }
+
+ StringRef value() const { return _value; }
+
+ static bool classof(const HNode *n) {
+ return ScalarNode::classof(n->_node) ||
+ BlockScalarNode::classof(n->_node);
+ }
+
+ static bool classof(const ScalarHNode *) { return true; }
+
+ protected:
+ StringRef _value;
+ };
+
+ class MapHNode : public HNode {
+ void anchor() override;
+
+ public:
+ MapHNode(Node *n) : HNode(n) { }
+
+ static bool classof(const HNode *n) {
+ return MappingNode::classof(n->_node);
+ }
+
+ static bool classof(const MapHNode *) { return true; }
+
+ using NameToNodeAndLoc =
+ StringMap<std::pair<std::unique_ptr<HNode>, SMRange>>;
+
+ NameToNodeAndLoc Mapping;
+ SmallVector<std::string, 6> ValidKeys;
+ };
+
+ class SequenceHNode : public HNode {
+ void anchor() override;
+
+ public:
+ SequenceHNode(Node *n) : HNode(n) { }
+
+ static bool classof(const HNode *n) {
+ return SequenceNode::classof(n->_node);
+ }
+
+ static bool classof(const SequenceHNode *) { return true; }
+
+ std::vector<std::unique_ptr<HNode>> Entries;
+ };
+
+ std::unique_ptr<Input::HNode> createHNodes(Node *node);
+ void setError(HNode *hnode, const Twine &message);
+ void setError(Node *node, const Twine &message);
+ void setError(const SMRange &Range, const Twine &message);
+
+ void reportWarning(HNode *hnode, const Twine &message);
+ void reportWarning(Node *hnode, const Twine &message);
+ void reportWarning(const SMRange &Range, const Twine &message);
+
+public:
+ // These are only used by operator>>. They could be private
+ // if those templated things could be made friends.
+ bool setCurrentDocument();
+ bool nextDocument();
+
+ /// Returns the current node that's being parsed by the YAML Parser.
+ const Node *getCurrentNode() const;
+
+ void setAllowUnknownKeys(bool Allow) override;
+
+private:
+ SourceMgr SrcMgr; // must be before Strm
+ std::unique_ptr<llvm::yaml::Stream> Strm;
+ std::unique_ptr<HNode> TopNode;
+ std::error_code EC;
+ BumpPtrAllocator StringAllocator;
+ document_iterator DocIterator;
+ llvm::BitVector BitValuesUsed;
+ HNode *CurrentNode = nullptr;
+ bool ScalarMatchFound = false;
+ bool AllowUnknownKeys = false;
+};
+
+///
+/// The Output class is used to generate a yaml document from in-memory structs
+/// and vectors.
+///
+class Output : public IO {
+public:
+ Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70);
+ ~Output() override;
+
+ /// Set whether or not to output optional values which are equal
+ /// to the default value. By default, when outputting if you attempt
+ /// to write a value that is equal to the default, the value gets ignored.
+ /// Sometimes, it is useful to be able to see these in the resulting YAML
+ /// anyway.
+ void setWriteDefaultValues(bool Write) { WriteDefaultValues = Write; }
+
+ bool outputting() const override;
+ bool mapTag(StringRef, bool) override;
+ void beginMapping() override;
+ void endMapping() override;
+ bool preflightKey(const char *key, bool, bool, bool &, void *&) override;
+ void postflightKey(void *) override;
+ std::vector<StringRef> keys() override;
+ void beginFlowMapping() override;
+ void endFlowMapping() override;
+ unsigned beginSequence() override;
+ void endSequence() override;
+ bool preflightElement(unsigned, void *&) override;
+ void postflightElement(void *) override;
+ unsigned beginFlowSequence() override;
+ bool preflightFlowElement(unsigned, void *&) override;
+ void postflightFlowElement(void *) override;
+ void endFlowSequence() override;
+ void beginEnumScalar() override;
+ bool matchEnumScalar(const char*, bool) override;
+ bool matchEnumFallback() override;
+ void endEnumScalar() override;
+ bool beginBitSetScalar(bool &) override;
+ bool bitSetMatch(const char *, bool ) override;
+ void endBitSetScalar() override;
+ void scalarString(StringRef &, QuotingType) override;
+ void blockScalarString(StringRef &) override;
+ void scalarTag(std::string &) override;
+ NodeKind getNodeKind() override;
+ void setError(const Twine &message) override;
+ bool canElideEmptySequence() override;
+
+ // These are only used by operator<<. They could be private
+ // if that templated operator could be made a friend.
+ void beginDocuments();
+ bool preflightDocument(unsigned);
+ void postflightDocument();
+ void endDocuments();
+
+private:
+ void output(StringRef s);
+ void outputUpToEndOfLine(StringRef s);
+ void newLineCheck(bool EmptySequence = false);
+ void outputNewLine();
+ void paddedKey(StringRef key);
+ void flowKey(StringRef Key);
+
+ enum InState {
+ inSeqFirstElement,
+ inSeqOtherElement,
+ inFlowSeqFirstElement,
+ inFlowSeqOtherElement,
+ inMapFirstKey,
+ inMapOtherKey,
+ inFlowMapFirstKey,
+ inFlowMapOtherKey
+ };
+
+ static bool inSeqAnyElement(InState State);
+ static bool inFlowSeqAnyElement(InState State);
+ static bool inMapAnyKey(InState State);
+ static bool inFlowMapAnyKey(InState State);
+
+ raw_ostream &Out;
+ int WrapColumn;
+ SmallVector<InState, 8> StateStack;
+ int Column = 0;
+ int ColumnAtFlowStart = 0;
+ int ColumnAtMapFlowStart = 0;
+ bool NeedBitValueComma = false;
+ bool NeedFlowSequenceComma = false;
+ bool EnumerationMatchFound = false;
+ bool WriteDefaultValues = false;
+ StringRef Padding;
+ StringRef PaddingBeforeContainer;
+};
+
+template <typename T, typename Context>
+void IO::processKeyWithDefault(const char *Key, std::optional<T> &Val,
+ const std::optional<T> &DefaultValue,
+ bool Required, Context &Ctx) {
+ assert(!DefaultValue && "std::optional<T> shouldn't have a value!");
+ void *SaveInfo;
+ bool UseDefault = true;
+ const bool sameAsDefault = outputting() && !Val;
+ if (!outputting() && !Val)
+ Val = T();
+ if (Val &&
+ this->preflightKey(Key, Required, sameAsDefault, UseDefault, SaveInfo)) {
+
+ // When reading an std::optional<X> key from a YAML description, we allow
+ // the special "<none>" value, which can be used to specify that no value
+ // was requested, i.e. the DefaultValue will be assigned. The DefaultValue
+ // is usually None.
+ bool IsNone = false;
+ if (!outputting())
+ if (const auto *Node =
+ dyn_cast<ScalarNode>(((Input *)this)->getCurrentNode()))
+ // We use rtrim to ignore possible white spaces that might exist when a
+ // comment is present on the same line.
+ IsNone = Node->getRawValue().rtrim(' ') == "<none>";
+
+ if (IsNone)
+ Val = DefaultValue;
+ else
+ yamlize(*this, *Val, Required, Ctx);
+ this->postflightKey(SaveInfo);
+ } else {
+ if (UseDefault)
+ Val = DefaultValue;
+ }
+}
+
+/// YAML I/O does conversion based on types. But often native data types
+/// are just a typedef of built in intergral types (e.g. int). But the C++
+/// type matching system sees through the typedef and all the typedefed types
+/// look like a built in type. This will cause the generic YAML I/O conversion
+/// to be used. To provide better control over the YAML conversion, you can
+/// use this macro instead of typedef. It will create a class with one field
+/// and automatic conversion operators to and from the base type.
+/// Based on BOOST_STRONG_TYPEDEF
+#define LLVM_YAML_STRONG_TYPEDEF(_base, _type) \
+ struct _type { \
+ _type() = default; \
+ _type(const _base v) : value(v) {} \
+ _type(const _type &v) = default; \
+ _type &operator=(const _type &rhs) = default; \
+ _type &operator=(const _base &rhs) { value = rhs; return *this; } \
+ operator const _base & () const { return value; } \
+ bool operator==(const _type &rhs) const { return value == rhs.value; } \
+ bool operator==(const _base &rhs) const { return value == rhs; } \
+ bool operator<(const _type &rhs) const { return value < rhs.value; } \
+ _base value; \
+ using BaseType = _base; \
+ };
+
+///
+/// Use these types instead of uintXX_t in any mapping to have
+/// its yaml output formatted as hexadecimal.
+///
+LLVM_YAML_STRONG_TYPEDEF(uint8_t, Hex8)
+LLVM_YAML_STRONG_TYPEDEF(uint16_t, Hex16)
+LLVM_YAML_STRONG_TYPEDEF(uint32_t, Hex32)
+LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64)
+
+template<>
+struct ScalarTraits<Hex8> {
+ static void output(const Hex8 &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, Hex8 &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<Hex16> {
+ static void output(const Hex16 &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, Hex16 &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<Hex32> {
+ static void output(const Hex32 &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, Hex32 &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template<>
+struct ScalarTraits<Hex64> {
+ static void output(const Hex64 &, void *, raw_ostream &);
+ static StringRef input(StringRef, void *, Hex64 &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+template <> struct ScalarTraits<VersionTuple> {
+ static void output(const VersionTuple &Value, void *, llvm::raw_ostream &Out);
+ static StringRef input(StringRef, void *, VersionTuple &);
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+
+// Define non-member operator>> so that Input can stream in a document list.
+template <typename T>
+inline std::enable_if_t<has_DocumentListTraits<T>::value, Input &>
+operator>>(Input &yin, T &docList) {
+ int i = 0;
+ EmptyContext Ctx;
+ while ( yin.setCurrentDocument() ) {
+ yamlize(yin, DocumentListTraits<T>::element(yin, docList, i), true, Ctx);
+ if ( yin.error() )
+ return yin;
+ yin.nextDocument();
+ ++i;
+ }
+ return yin;
+}
+
+// Define non-member operator>> so that Input can stream in a map as a document.
+template <typename T>
+inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Input &>
+operator>>(Input &yin, T &docMap) {
+ EmptyContext Ctx;
+ yin.setCurrentDocument();
+ yamlize(yin, docMap, true, Ctx);
+ return yin;
+}
+
+// Define non-member operator>> so that Input can stream in a sequence as
+// a document.
+template <typename T>
+inline std::enable_if_t<has_SequenceTraits<T>::value, Input &>
+operator>>(Input &yin, T &docSeq) {
+ EmptyContext Ctx;
+ if (yin.setCurrentDocument())
+ yamlize(yin, docSeq, true, Ctx);
+ return yin;
+}
+
+// Define non-member operator>> so that Input can stream in a block scalar.
+template <typename T>
+inline std::enable_if_t<has_BlockScalarTraits<T>::value, Input &>
+operator>>(Input &In, T &Val) {
+ EmptyContext Ctx;
+ if (In.setCurrentDocument())
+ yamlize(In, Val, true, Ctx);
+ return In;
+}
+
+// Define non-member operator>> so that Input can stream in a string map.
+template <typename T>
+inline std::enable_if_t<has_CustomMappingTraits<T>::value, Input &>
+operator>>(Input &In, T &Val) {
+ EmptyContext Ctx;
+ if (In.setCurrentDocument())
+ yamlize(In, Val, true, Ctx);
+ return In;
+}
+
+// Define non-member operator>> so that Input can stream in a polymorphic type.
+template <typename T>
+inline std::enable_if_t<has_PolymorphicTraits<T>::value, Input &>
+operator>>(Input &In, T &Val) {
+ EmptyContext Ctx;
+ if (In.setCurrentDocument())
+ yamlize(In, Val, true, Ctx);
+ return In;
+}
+
+// Provide better error message about types missing a trait specialization
+template <typename T>
+inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Input &>
+operator>>(Input &yin, T &docSeq) {
+ char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
+ return yin;
+}
+
+// Define non-member operator<< so that Output can stream out document list.
+template <typename T>
+inline std::enable_if_t<has_DocumentListTraits<T>::value, Output &>
+operator<<(Output &yout, T &docList) {
+ EmptyContext Ctx;
+ yout.beginDocuments();
+ const size_t count = DocumentListTraits<T>::size(yout, docList);
+ for(size_t i=0; i < count; ++i) {
+ if ( yout.preflightDocument(i) ) {
+ yamlize(yout, DocumentListTraits<T>::element(yout, docList, i), true,
+ Ctx);
+ yout.postflightDocument();
+ }
+ }
+ yout.endDocuments();
+ return yout;
+}
+
+// Define non-member operator<< so that Output can stream out a map.
+template <typename T>
+inline std::enable_if_t<has_MappingTraits<T, EmptyContext>::value, Output &>
+operator<<(Output &yout, T &map) {
+ EmptyContext Ctx;
+ yout.beginDocuments();
+ if ( yout.preflightDocument(0) ) {
+ yamlize(yout, map, true, Ctx);
+ yout.postflightDocument();
+ }
+ yout.endDocuments();
+ return yout;
+}
+
+// Define non-member operator<< so that Output can stream out a sequence.
+template <typename T>
+inline std::enable_if_t<has_SequenceTraits<T>::value, Output &>
+operator<<(Output &yout, T &seq) {
+ EmptyContext Ctx;
+ yout.beginDocuments();
+ if ( yout.preflightDocument(0) ) {
+ yamlize(yout, seq, true, Ctx);
+ yout.postflightDocument();
+ }
+ yout.endDocuments();
+ return yout;
+}
+
+// Define non-member operator<< so that Output can stream out a block scalar.
+template <typename T>
+inline std::enable_if_t<has_BlockScalarTraits<T>::value, Output &>
+operator<<(Output &Out, T &Val) {
+ EmptyContext Ctx;
+ Out.beginDocuments();
+ if (Out.preflightDocument(0)) {
+ yamlize(Out, Val, true, Ctx);
+ Out.postflightDocument();
+ }
+ Out.endDocuments();
+ return Out;
+}
+
+// Define non-member operator<< so that Output can stream out a string map.
+template <typename T>
+inline std::enable_if_t<has_CustomMappingTraits<T>::value, Output &>
+operator<<(Output &Out, T &Val) {
+ EmptyContext Ctx;
+ Out.beginDocuments();
+ if (Out.preflightDocument(0)) {
+ yamlize(Out, Val, true, Ctx);
+ Out.postflightDocument();
+ }
+ Out.endDocuments();
+ return Out;
+}
+
+// Define non-member operator<< so that Output can stream out a polymorphic
+// type.
+template <typename T>
+inline std::enable_if_t<has_PolymorphicTraits<T>::value, Output &>
+operator<<(Output &Out, T &Val) {
+ EmptyContext Ctx;
+ Out.beginDocuments();
+ if (Out.preflightDocument(0)) {
+ // FIXME: The parser does not support explicit documents terminated with a
+ // plain scalar; the end-marker is included as part of the scalar token.
+ assert(PolymorphicTraits<T>::getKind(Val) != NodeKind::Scalar && "plain scalar documents are not supported");
+ yamlize(Out, Val, true, Ctx);
+ Out.postflightDocument();
+ }
+ Out.endDocuments();
+ return Out;
+}
+
+// Provide better error message about types missing a trait specialization
+template <typename T>
+inline std::enable_if_t<missingTraits<T, EmptyContext>::value, Output &>
+operator<<(Output &yout, T &seq) {
+ char missing_yaml_trait_for_type[sizeof(MissingTrait<T>)];
+ return yout;
+}
+
+template <bool B> struct IsFlowSequenceBase {};
+template <> struct IsFlowSequenceBase<true> { static const bool flow = true; };
+
+template <typename T, typename U = void>
+struct IsResizable : std::false_type {};
+
+template <typename T>
+struct IsResizable<T, std::void_t<decltype(std::declval<T>().resize(0))>>
+ : public std::true_type {};
+
+template <typename T, bool B> struct IsResizableBase {
+ using type = typename T::value_type;
+
+ static type &element(IO &io, T &seq, size_t index) {
+ if (index >= seq.size())
+ seq.resize(index + 1);
+ return seq[index];
+ }
+};
+
+template <typename T> struct IsResizableBase<T, false> {
+ using type = typename T::value_type;
+
+ static type &element(IO &io, T &seq, size_t index) {
+ if (index >= seq.size()) {
+ io.setError(Twine("value sequence extends beyond static size (") +
+ Twine(seq.size()) + ")");
+ return seq[0];
+ }
+ return seq[index];
+ }
+};
+
+template <typename T, bool Flow>
+struct SequenceTraitsImpl
+ : IsFlowSequenceBase<Flow>, IsResizableBase<T, IsResizable<T>::value> {
+ static size_t size(IO &io, T &seq) { return seq.size(); }
+};
+
+// Simple helper to check an expression can be used as a bool-valued template
+// argument.
+template <bool> struct CheckIsBool { static const bool value = true; };
+
+// If T has SequenceElementTraits, then vector<T> and SmallVector<T, N> have
+// SequenceTraits that do the obvious thing.
+template <typename T>
+struct SequenceTraits<
+ std::vector<T>,
+ std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
+ : SequenceTraitsImpl<std::vector<T>, SequenceElementTraits<T>::flow> {};
+template <typename T, unsigned N>
+struct SequenceTraits<
+ SmallVector<T, N>,
+ std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
+ : SequenceTraitsImpl<SmallVector<T, N>, SequenceElementTraits<T>::flow> {};
+template <typename T>
+struct SequenceTraits<
+ SmallVectorImpl<T>,
+ std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
+ : SequenceTraitsImpl<SmallVectorImpl<T>, SequenceElementTraits<T>::flow> {};
+template <typename T>
+struct SequenceTraits<
+ MutableArrayRef<T>,
+ std::enable_if_t<CheckIsBool<SequenceElementTraits<T>::flow>::value>>
+ : SequenceTraitsImpl<MutableArrayRef<T>, SequenceElementTraits<T>::flow> {};
+
+// Sequences of fundamental types use flow formatting.
+template <typename T>
+struct SequenceElementTraits<T,
+ std::enable_if_t<std::is_fundamental<T>::value>> {
+ static const bool flow = true;
+};
+
+// Sequences of strings use block formatting.
+template<> struct SequenceElementTraits<std::string> {
+ static const bool flow = false;
+};
+template<> struct SequenceElementTraits<StringRef> {
+ static const bool flow = false;
+};
+template<> struct SequenceElementTraits<std::pair<std::string, std::string>> {
+ static const bool flow = false;
+};
+
+/// Implementation of CustomMappingTraits for std::map<std::string, T>.
+template <typename T> struct StdMapStringCustomMappingTraitsImpl {
+ using map_type = std::map<std::string, T>;
+
+ static void inputOne(IO &io, StringRef key, map_type &v) {
+ io.mapRequired(key.str().c_str(), v[std::string(key)]);
+ }
+
+ static void output(IO &io, map_type &v) {
+ for (auto &p : v)
+ io.mapRequired(p.first.c_str(), p.second);
+ }
+};
+
+} // end namespace yaml
+} // end namespace llvm
+
+#define LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(TYPE, FLOW) \
+ namespace llvm { \
+ namespace yaml { \
+ static_assert( \
+ !std::is_fundamental_v<TYPE> && !std::is_same_v<TYPE, std::string> && \
+ !std::is_same_v<TYPE, llvm::StringRef>, \
+ "only use LLVM_YAML_IS_SEQUENCE_VECTOR for types you control"); \
+ template <> struct SequenceElementTraits<TYPE> { \
+ static const bool flow = FLOW; \
+ }; \
+ } \
+ }
+
+/// Utility for declaring that a std::vector of a particular type
+/// should be considered a YAML sequence.
+#define LLVM_YAML_IS_SEQUENCE_VECTOR(type) \
+ LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, false)
+
+/// Utility for declaring that a std::vector of a particular type
+/// should be considered a YAML flow sequence.
+#define LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(type) \
+ LLVM_YAML_IS_SEQUENCE_VECTOR_IMPL(type, true)
+
+#define LLVM_YAML_DECLARE_MAPPING_TRAITS(Type) \
+ namespace llvm { \
+ namespace yaml { \
+ template <> struct MappingTraits<Type> { \
+ static void mapping(IO &IO, Type &Obj); \
+ }; \
+ } \
+ }
+
+#define LLVM_YAML_DECLARE_ENUM_TRAITS(Type) \
+ namespace llvm { \
+ namespace yaml { \
+ template <> struct ScalarEnumerationTraits<Type> { \
+ static void enumeration(IO &io, Type &Value); \
+ }; \
+ } \
+ }
+
+#define LLVM_YAML_DECLARE_BITSET_TRAITS(Type) \
+ namespace llvm { \
+ namespace yaml { \
+ template <> struct ScalarBitSetTraits<Type> { \
+ static void bitset(IO &IO, Type &Options); \
+ }; \
+ } \
+ }
+
+#define LLVM_YAML_DECLARE_SCALAR_TRAITS(Type, MustQuote) \
+ namespace llvm { \
+ namespace yaml { \
+ template <> struct ScalarTraits<Type> { \
+ static void output(const Type &Value, void *ctx, raw_ostream &Out); \
+ static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \
+ static QuotingType mustQuote(StringRef) { return MustQuote; } \
+ }; \
+ } \
+ }
+
+/// Utility for declaring that a std::vector of a particular type
+/// should be considered a YAML document list.
+#define LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(_type) \
+ namespace llvm { \
+ namespace yaml { \
+ template <unsigned N> \
+ struct DocumentListTraits<SmallVector<_type, N>> \
+ : public SequenceTraitsImpl<SmallVector<_type, N>, false> {}; \
+ template <> \
+ struct DocumentListTraits<std::vector<_type>> \
+ : public SequenceTraitsImpl<std::vector<_type>, false> {}; \
+ } \
+ }
+
+/// Utility for declaring that std::map<std::string, _type> should be considered
+/// a YAML map.
+#define LLVM_YAML_IS_STRING_MAP(_type) \
+ namespace llvm { \
+ namespace yaml { \
+ template <> \
+ struct CustomMappingTraits<std::map<std::string, _type>> \
+ : public StdMapStringCustomMappingTraitsImpl<_type> {}; \
+ } \
+ }
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex32)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex16)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex8)
+
+#endif // LLVM_SUPPORT_YAMLTRAITS_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/circular_raw_ostream.h b/contrib/libs/llvm16/include/llvm/Support/circular_raw_ostream.h
new file mode 100644
index 00000000000..533e4196265
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/circular_raw_ostream.h
@@ -0,0 +1,169 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/circular_raw_ostream.h - Buffered streams --*- 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 raw_ostream implementations for streams to do circular
+// buffering of their output.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H
+#define LLVM_SUPPORT_CIRCULAR_RAW_OSTREAM_H
+
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+ /// circular_raw_ostream - A raw_ostream which *can* save its data
+ /// to a circular buffer, or can pass it through directly to an
+ /// underlying stream if specified with a buffer of zero.
+ ///
+ class circular_raw_ostream : public raw_ostream {
+ public:
+ /// TAKE_OWNERSHIP - Tell this stream that it owns the underlying
+ /// stream and is responsible for cleanup, memory management
+ /// issues, etc.
+ ///
+ static constexpr bool TAKE_OWNERSHIP = true;
+
+ /// REFERENCE_ONLY - Tell this stream it should not manage the
+ /// held stream.
+ ///
+ static constexpr bool REFERENCE_ONLY = false;
+
+ private:
+ /// TheStream - The real stream we output to. We set it to be
+ /// unbuffered, since we're already doing our own buffering.
+ ///
+ raw_ostream *TheStream = nullptr;
+
+ /// OwnsStream - Are we responsible for managing the underlying
+ /// stream?
+ ///
+ bool OwnsStream;
+
+ /// BufferSize - The size of the buffer in bytes.
+ ///
+ size_t BufferSize;
+
+ /// BufferArray - The actual buffer storage.
+ ///
+ char *BufferArray = nullptr;
+
+ /// Cur - Pointer to the current output point in BufferArray.
+ ///
+ char *Cur;
+
+ /// Filled - Indicate whether the buffer has been completely
+ /// filled. This helps avoid garbage output.
+ ///
+ bool Filled = false;
+
+ /// Banner - A pointer to a banner to print before dumping the
+ /// log.
+ ///
+ const char *Banner;
+
+ /// flushBuffer - Dump the contents of the buffer to Stream.
+ ///
+ void flushBuffer() {
+ if (Filled)
+ // Write the older portion of the buffer.
+ TheStream->write(Cur, BufferArray + BufferSize - Cur);
+ // Write the newer portion of the buffer.
+ TheStream->write(BufferArray, Cur - BufferArray);
+ Cur = BufferArray;
+ Filled = false;
+ }
+
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ /// current_pos - Return the current position within the stream,
+ /// not counting the bytes currently in the buffer.
+ ///
+ uint64_t current_pos() const override {
+ // This has the same effect as calling TheStream.current_pos(),
+ // but that interface is private.
+ return TheStream->tell() - TheStream->GetNumBytesInBuffer();
+ }
+
+ public:
+ /// circular_raw_ostream - Construct an optionally
+ /// circular-buffered stream, handing it an underlying stream to
+ /// do the "real" output.
+ ///
+ /// As a side effect, if BuffSize is nonzero, the given Stream is
+ /// set to be Unbuffered. This is because circular_raw_ostream
+ /// does its own buffering, so it doesn't want another layer of
+ /// buffering to be happening underneath it.
+ ///
+ /// "Owns" tells the circular_raw_ostream whether it is
+ /// responsible for managing the held stream, doing memory
+ /// management of it, etc.
+ ///
+ circular_raw_ostream(raw_ostream &Stream, const char *Header,
+ size_t BuffSize = 0, bool Owns = REFERENCE_ONLY)
+ : raw_ostream(/*unbuffered*/ true), OwnsStream(Owns),
+ BufferSize(BuffSize), Banner(Header) {
+ if (BufferSize != 0)
+ BufferArray = new char[BufferSize];
+ Cur = BufferArray;
+ setStream(Stream, Owns);
+ }
+
+ ~circular_raw_ostream() override {
+ flush();
+ flushBufferWithBanner();
+ releaseStream();
+ delete[] BufferArray;
+ }
+
+ bool is_displayed() const override {
+ return TheStream->is_displayed();
+ }
+
+ /// setStream - Tell the circular_raw_ostream to output a
+ /// different stream. "Owns" tells circular_raw_ostream whether
+ /// it should take responsibility for managing the underlying
+ /// stream.
+ ///
+ void setStream(raw_ostream &Stream, bool Owns = REFERENCE_ONLY) {
+ releaseStream();
+ TheStream = &Stream;
+ OwnsStream = Owns;
+ }
+
+ /// flushBufferWithBanner - Force output of the buffer along with
+ /// a small header.
+ ///
+ void flushBufferWithBanner();
+
+ private:
+ /// releaseStream - Delete the held stream if needed. Otherwise,
+ /// transfer the buffer settings from this circular_raw_ostream
+ /// back to the underlying stream.
+ ///
+ void releaseStream() {
+ if (!TheStream)
+ return;
+ if (OwnsStream)
+ delete TheStream;
+ }
+ };
+} // end llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/raw_os_ostream.h b/contrib/libs/llvm16/include/llvm/Support/raw_os_ostream.h
new file mode 100644
index 00000000000..f1ecb4949b5
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/raw_os_ostream.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- raw_os_ostream.h - std::ostream adaptor for raw_ostream --*- 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 defines the raw_os_ostream class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RAW_OS_OSTREAM_H
+#define LLVM_SUPPORT_RAW_OS_OSTREAM_H
+
+#include "llvm/Support/raw_ostream.h"
+#include <iosfwd>
+
+namespace llvm {
+
+/// raw_os_ostream - A raw_ostream that writes to an std::ostream. This is a
+/// simple adaptor class. It does not check for output errors; clients should
+/// use the underlying stream to detect errors.
+class raw_os_ostream : public raw_ostream {
+ std::ostream &OS;
+
+ /// write_impl - See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ /// current_pos - Return the current position within the stream, not
+ /// counting the bytes currently in the buffer.
+ uint64_t current_pos() const override;
+
+public:
+ raw_os_ostream(std::ostream &O) : OS(O) {}
+ ~raw_os_ostream() override;
+};
+
+} // end llvm namespace
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/raw_ostream.h b/contrib/libs/llvm16/include/llvm/Support/raw_ostream.h
new file mode 100644
index 00000000000..22a8cc140c7
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/raw_ostream.h
@@ -0,0 +1,782 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===--- raw_ostream.h - Raw output stream ----------------------*- 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 defines the raw_ostream class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_RAW_OSTREAM_H
+#define LLVM_SUPPORT_RAW_OSTREAM_H
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/DataTypes.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <system_error>
+#include <type_traits>
+
+namespace llvm {
+
+class Duration;
+class formatv_object_base;
+class format_object_base;
+class FormattedString;
+class FormattedNumber;
+class FormattedBytes;
+template <class T> class [[nodiscard]] Expected;
+
+namespace sys {
+namespace fs {
+enum FileAccess : unsigned;
+enum OpenFlags : unsigned;
+enum CreationDisposition : unsigned;
+class FileLocker;
+} // end namespace fs
+} // end namespace sys
+
+/// This class implements an extremely fast bulk output stream that can *only*
+/// output to a stream. It does not support seeking, reopening, rewinding, line
+/// buffered disciplines etc. It is a simple buffer that outputs
+/// a chunk at a time.
+class raw_ostream {
+public:
+ // Class kinds to support LLVM-style RTTI.
+ enum class OStreamKind {
+ OK_OStream,
+ OK_FDStream,
+ };
+
+private:
+ OStreamKind Kind;
+
+ /// The buffer is handled in such a way that the buffer is
+ /// uninitialized, unbuffered, or out of space when OutBufCur >=
+ /// OutBufEnd. Thus a single comparison suffices to determine if we
+ /// need to take the slow path to write a single character.
+ ///
+ /// The buffer is in one of three states:
+ /// 1. Unbuffered (BufferMode == Unbuffered)
+ /// 1. Uninitialized (BufferMode != Unbuffered && OutBufStart == 0).
+ /// 2. Buffered (BufferMode != Unbuffered && OutBufStart != 0 &&
+ /// OutBufEnd - OutBufStart >= 1).
+ ///
+ /// If buffered, then the raw_ostream owns the buffer if (BufferMode ==
+ /// InternalBuffer); otherwise the buffer has been set via SetBuffer and is
+ /// managed by the subclass.
+ ///
+ /// If a subclass installs an external buffer using SetBuffer then it can wait
+ /// for a \see write_impl() call to handle the data which has been put into
+ /// this buffer.
+ char *OutBufStart, *OutBufEnd, *OutBufCur;
+ bool ColorEnabled = false;
+
+ /// Optional stream this stream is tied to. If this stream is written to, the
+ /// tied-to stream will be flushed first.
+ raw_ostream *TiedStream = nullptr;
+
+ enum class BufferKind {
+ Unbuffered = 0,
+ InternalBuffer,
+ ExternalBuffer
+ } BufferMode;
+
+public:
+ // color order matches ANSI escape sequence, don't change
+ enum class Colors {
+ BLACK = 0,
+ RED,
+ GREEN,
+ YELLOW,
+ BLUE,
+ MAGENTA,
+ CYAN,
+ WHITE,
+ SAVEDCOLOR,
+ RESET,
+ };
+
+ static constexpr Colors BLACK = Colors::BLACK;
+ static constexpr Colors RED = Colors::RED;
+ static constexpr Colors GREEN = Colors::GREEN;
+ static constexpr Colors YELLOW = Colors::YELLOW;
+ static constexpr Colors BLUE = Colors::BLUE;
+ static constexpr Colors MAGENTA = Colors::MAGENTA;
+ static constexpr Colors CYAN = Colors::CYAN;
+ static constexpr Colors WHITE = Colors::WHITE;
+ static constexpr Colors SAVEDCOLOR = Colors::SAVEDCOLOR;
+ static constexpr Colors RESET = Colors::RESET;
+
+ explicit raw_ostream(bool unbuffered = false,
+ OStreamKind K = OStreamKind::OK_OStream)
+ : Kind(K), BufferMode(unbuffered ? BufferKind::Unbuffered
+ : BufferKind::InternalBuffer) {
+ // Start out ready to flush.
+ OutBufStart = OutBufEnd = OutBufCur = nullptr;
+ }
+
+ raw_ostream(const raw_ostream &) = delete;
+ void operator=(const raw_ostream &) = delete;
+
+ virtual ~raw_ostream();
+
+ /// tell - Return the current offset with the file.
+ uint64_t tell() const { return current_pos() + GetNumBytesInBuffer(); }
+
+ OStreamKind get_kind() const { return Kind; }
+
+ //===--------------------------------------------------------------------===//
+ // Configuration Interface
+ //===--------------------------------------------------------------------===//
+
+ /// If possible, pre-allocate \p ExtraSize bytes for stream data.
+ /// i.e. it extends internal buffers to keep additional ExtraSize bytes.
+ /// So that the stream could keep at least tell() + ExtraSize bytes
+ /// without re-allocations. reserveExtraSpace() does not change
+ /// the size/data of the stream.
+ virtual void reserveExtraSpace(uint64_t ExtraSize) {}
+
+ /// Set the stream to be buffered, with an automatically determined buffer
+ /// size.
+ void SetBuffered();
+
+ /// Set the stream to be buffered, using the specified buffer size.
+ void SetBufferSize(size_t Size) {
+ flush();
+ SetBufferAndMode(new char[Size], Size, BufferKind::InternalBuffer);
+ }
+
+ size_t GetBufferSize() const {
+ // If we're supposed to be buffered but haven't actually gotten around
+ // to allocating the buffer yet, return the value that would be used.
+ if (BufferMode != BufferKind::Unbuffered && OutBufStart == nullptr)
+ return preferred_buffer_size();
+
+ // Otherwise just return the size of the allocated buffer.
+ return OutBufEnd - OutBufStart;
+ }
+
+ /// Set the stream to be unbuffered. When unbuffered, the stream will flush
+ /// after every write. This routine will also flush the buffer immediately
+ /// when the stream is being set to unbuffered.
+ void SetUnbuffered() {
+ flush();
+ SetBufferAndMode(nullptr, 0, BufferKind::Unbuffered);
+ }
+
+ size_t GetNumBytesInBuffer() const {
+ return OutBufCur - OutBufStart;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Data Output Interface
+ //===--------------------------------------------------------------------===//
+
+ void flush() {
+ if (OutBufCur != OutBufStart)
+ flush_nonempty();
+ }
+
+ raw_ostream &operator<<(char C) {
+ if (OutBufCur >= OutBufEnd)
+ return write(C);
+ *OutBufCur++ = C;
+ return *this;
+ }
+
+ raw_ostream &operator<<(unsigned char C) {
+ if (OutBufCur >= OutBufEnd)
+ return write(C);
+ *OutBufCur++ = C;
+ return *this;
+ }
+
+ raw_ostream &operator<<(signed char C) {
+ if (OutBufCur >= OutBufEnd)
+ return write(C);
+ *OutBufCur++ = C;
+ return *this;
+ }
+
+ raw_ostream &operator<<(StringRef Str) {
+ // Inline fast path, particularly for strings with a known length.
+ size_t Size = Str.size();
+
+ // Make sure we can use the fast path.
+ if (Size > (size_t)(OutBufEnd - OutBufCur))
+ return write(Str.data(), Size);
+
+ if (Size) {
+ memcpy(OutBufCur, Str.data(), Size);
+ OutBufCur += Size;
+ }
+ return *this;
+ }
+
+#if defined(__cpp_char8_t)
+ // When using `char8_t *` integers or pointers are written to the ostream
+ // instead of UTF-8 code as one might expect. This might lead to unexpected
+ // behavior, especially as `u8""` literals are of type `char8_t*` instead of
+ // type `char_t*` from C++20 onwards. Thus we disallow using them with
+ // raw_ostreams.
+ // If you have u8"" literals to stream, you can rewrite them as ordinary
+ // literals with escape sequences
+ // e.g. replace `u8"\u00a0"` by `"\xc2\xa0"`
+ // or use `reinterpret_cast`:
+ // e.g. replace `u8"\u00a0"` by `reinterpret_cast<const char *>(u8"\u00a0")`
+ raw_ostream &operator<<(const char8_t *Str) = delete;
+#endif
+
+ raw_ostream &operator<<(const char *Str) {
+ // Inline fast path, particularly for constant strings where a sufficiently
+ // smart compiler will simplify strlen.
+
+ return this->operator<<(StringRef(Str));
+ }
+
+ raw_ostream &operator<<(const std::string &Str) {
+ // Avoid the fast path, it would only increase code size for a marginal win.
+ return write(Str.data(), Str.length());
+ }
+
+ raw_ostream &operator<<(const std::string_view &Str) {
+ return write(Str.data(), Str.length());
+ }
+
+ raw_ostream &operator<<(const SmallVectorImpl<char> &Str) {
+ return write(Str.data(), Str.size());
+ }
+
+ raw_ostream &operator<<(unsigned long N);
+ raw_ostream &operator<<(long N);
+ raw_ostream &operator<<(unsigned long long N);
+ raw_ostream &operator<<(long long N);
+ raw_ostream &operator<<(const void *P);
+
+ raw_ostream &operator<<(unsigned int N) {
+ return this->operator<<(static_cast<unsigned long>(N));
+ }
+
+ raw_ostream &operator<<(int N) {
+ return this->operator<<(static_cast<long>(N));
+ }
+
+ raw_ostream &operator<<(double N);
+
+ /// Output \p N in hexadecimal, without any prefix or padding.
+ raw_ostream &write_hex(unsigned long long N);
+
+ // Change the foreground color of text.
+ raw_ostream &operator<<(Colors C);
+
+ /// Output a formatted UUID with dash separators.
+ using uuid_t = uint8_t[16];
+ raw_ostream &write_uuid(const uuid_t UUID);
+
+ /// Output \p Str, turning '\\', '\t', '\n', '"', and anything that doesn't
+ /// satisfy llvm::isPrint into an escape sequence.
+ raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false);
+
+ raw_ostream &write(unsigned char C);
+ raw_ostream &write(const char *Ptr, size_t Size);
+
+ // Formatted output, see the format() function in Support/Format.h.
+ raw_ostream &operator<<(const format_object_base &Fmt);
+
+ // Formatted output, see the leftJustify() function in Support/Format.h.
+ raw_ostream &operator<<(const FormattedString &);
+
+ // Formatted output, see the formatHex() function in Support/Format.h.
+ raw_ostream &operator<<(const FormattedNumber &);
+
+ // Formatted output, see the formatv() function in Support/FormatVariadic.h.
+ raw_ostream &operator<<(const formatv_object_base &);
+
+ // Formatted output, see the format_bytes() function in Support/Format.h.
+ raw_ostream &operator<<(const FormattedBytes &);
+
+ /// indent - Insert 'NumSpaces' spaces.
+ raw_ostream &indent(unsigned NumSpaces);
+
+ /// write_zeros - Insert 'NumZeros' nulls.
+ raw_ostream &write_zeros(unsigned NumZeros);
+
+ /// Changes the foreground color of text that will be output from this point
+ /// forward.
+ /// @param Color ANSI color to use, the special SAVEDCOLOR can be used to
+ /// change only the bold attribute, and keep colors untouched
+ /// @param Bold bold/brighter text, default false
+ /// @param BG if true change the background, default: change foreground
+ /// @returns itself so it can be used within << invocations
+ virtual raw_ostream &changeColor(enum Colors Color, bool Bold = false,
+ bool BG = false);
+
+ /// Resets the colors to terminal defaults. Call this when you are done
+ /// outputting colored text, or before program exit.
+ virtual raw_ostream &resetColor();
+
+ /// Reverses the foreground and background colors.
+ virtual raw_ostream &reverseColor();
+
+ /// This function determines if this stream is connected to a "tty" or
+ /// "console" window. That is, the output would be displayed to the user
+ /// rather than being put on a pipe or stored in a file.
+ virtual bool is_displayed() const { return false; }
+
+ /// This function determines if this stream is displayed and supports colors.
+ /// The result is unaffected by calls to enable_color().
+ virtual bool has_colors() const { return is_displayed(); }
+
+ // Enable or disable colors. Once enable_colors(false) is called,
+ // changeColor() has no effect until enable_colors(true) is called.
+ virtual void enable_colors(bool enable) { ColorEnabled = enable; }
+
+ bool colors_enabled() const { return ColorEnabled; }
+
+ /// Tie this stream to the specified stream. Replaces any existing tied-to
+ /// stream. Specifying a nullptr unties the stream.
+ void tie(raw_ostream *TieTo) { TiedStream = TieTo; }
+
+ //===--------------------------------------------------------------------===//
+ // Subclass Interface
+ //===--------------------------------------------------------------------===//
+
+private:
+ /// The is the piece of the class that is implemented by subclasses. This
+ /// writes the \p Size bytes starting at
+ /// \p Ptr to the underlying stream.
+ ///
+ /// This function is guaranteed to only be called at a point at which it is
+ /// safe for the subclass to install a new buffer via SetBuffer.
+ ///
+ /// \param Ptr The start of the data to be written. For buffered streams this
+ /// is guaranteed to be the start of the buffer.
+ ///
+ /// \param Size The number of bytes to be written.
+ ///
+ /// \invariant { Size > 0 }
+ virtual void write_impl(const char *Ptr, size_t Size) = 0;
+
+ /// Return the current position within the stream, not counting the bytes
+ /// currently in the buffer.
+ virtual uint64_t current_pos() const = 0;
+
+protected:
+ /// Use the provided buffer as the raw_ostream buffer. This is intended for
+ /// use only by subclasses which can arrange for the output to go directly
+ /// into the desired output buffer, instead of being copied on each flush.
+ void SetBuffer(char *BufferStart, size_t Size) {
+ SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
+ }
+
+ /// Return an efficient buffer size for the underlying output mechanism.
+ virtual size_t preferred_buffer_size() const;
+
+ /// Return the beginning of the current stream buffer, or 0 if the stream is
+ /// unbuffered.
+ const char *getBufferStart() const { return OutBufStart; }
+
+ //===--------------------------------------------------------------------===//
+ // Private Interface
+ //===--------------------------------------------------------------------===//
+private:
+ /// Install the given buffer and mode.
+ void SetBufferAndMode(char *BufferStart, size_t Size, BufferKind Mode);
+
+ /// Flush the current buffer, which is known to be non-empty. This outputs the
+ /// currently buffered data and resets the buffer to empty.
+ void flush_nonempty();
+
+ /// Copy data into the buffer. Size must not be greater than the number of
+ /// unused bytes in the buffer.
+ void copy_to_buffer(const char *Ptr, size_t Size);
+
+ /// Compute whether colors should be used and do the necessary work such as
+ /// flushing. The result is affected by calls to enable_color().
+ bool prepare_colors();
+
+ /// Flush the tied-to stream (if present) and then write the required data.
+ void flush_tied_then_write(const char *Ptr, size_t Size);
+
+ virtual void anchor();
+};
+
+/// Call the appropriate insertion operator, given an rvalue reference to a
+/// raw_ostream object and return a stream of the same type as the argument.
+template <typename OStream, typename T>
+std::enable_if_t<!std::is_reference<OStream>::value &&
+ std::is_base_of<raw_ostream, OStream>::value,
+ OStream &&>
+operator<<(OStream &&OS, const T &Value) {
+ OS << Value;
+ return std::move(OS);
+}
+
+/// An abstract base class for streams implementations that also support a
+/// pwrite operation. This is useful for code that can mostly stream out data,
+/// but needs to patch in a header that needs to know the output size.
+class raw_pwrite_stream : public raw_ostream {
+ virtual void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) = 0;
+ void anchor() override;
+
+public:
+ explicit raw_pwrite_stream(bool Unbuffered = false,
+ OStreamKind K = OStreamKind::OK_OStream)
+ : raw_ostream(Unbuffered, K) {}
+ void pwrite(const char *Ptr, size_t Size, uint64_t Offset) {
+#ifndef NDEBUG
+ uint64_t Pos = tell();
+ // /dev/null always reports a pos of 0, so we cannot perform this check
+ // in that case.
+ if (Pos)
+ assert(Size + Offset <= Pos && "We don't support extending the stream");
+#endif
+ pwrite_impl(Ptr, Size, Offset);
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// File Output Streams
+//===----------------------------------------------------------------------===//
+
+/// A raw_ostream that writes to a file descriptor.
+///
+class raw_fd_ostream : public raw_pwrite_stream {
+ int FD;
+ bool ShouldClose;
+ bool SupportsSeeking = false;
+ bool IsRegularFile = false;
+ mutable std::optional<bool> HasColors;
+
+#ifdef _WIN32
+ /// True if this fd refers to a Windows console device. Mintty and other
+ /// terminal emulators are TTYs, but they are not consoles.
+ bool IsWindowsConsole = false;
+#endif
+
+ std::error_code EC;
+
+ uint64_t pos = 0;
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
+
+ /// Return the current position within the stream, not counting the bytes
+ /// currently in the buffer.
+ uint64_t current_pos() const override { return pos; }
+
+ /// Determine an efficient buffer size.
+ size_t preferred_buffer_size() const override;
+
+ void anchor() override;
+
+protected:
+ /// Set the flag indicating that an output error has been encountered.
+ void error_detected(std::error_code EC) { this->EC = EC; }
+
+ /// Return the file descriptor.
+ int get_fd() const { return FD; }
+
+ // Update the file position by increasing \p Delta.
+ void inc_pos(uint64_t Delta) { pos += Delta; }
+
+public:
+ /// Open the specified file for writing. If an error occurs, information
+ /// about the error is put into EC, and the stream should be immediately
+ /// destroyed;
+ /// \p Flags allows optional flags to control how the file will be opened.
+ ///
+ /// As a special case, if Filename is "-", then the stream will use
+ /// STDOUT_FILENO instead of opening a file. This will not close the stdout
+ /// descriptor.
+ raw_fd_ostream(StringRef Filename, std::error_code &EC);
+ raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp);
+ raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::FileAccess Access);
+ raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::OpenFlags Flags);
+ raw_fd_ostream(StringRef Filename, std::error_code &EC,
+ sys::fs::CreationDisposition Disp, sys::fs::FileAccess Access,
+ sys::fs::OpenFlags Flags);
+
+ /// FD is the file descriptor that this writes to. If ShouldClose is true,
+ /// this closes the file when the stream is destroyed. If FD is for stdout or
+ /// stderr, it will not be closed.
+ raw_fd_ostream(int fd, bool shouldClose, bool unbuffered = false,
+ OStreamKind K = OStreamKind::OK_OStream);
+
+ ~raw_fd_ostream() override;
+
+ /// Manually flush the stream and close the file. Note that this does not call
+ /// fsync.
+ void close();
+
+ bool supportsSeeking() const { return SupportsSeeking; }
+
+ bool isRegularFile() const { return IsRegularFile; }
+
+ /// Flushes the stream and repositions the underlying file descriptor position
+ /// to the offset specified from the beginning of the file.
+ uint64_t seek(uint64_t off);
+
+ bool is_displayed() const override;
+
+ bool has_colors() const override;
+
+ std::error_code error() const { return EC; }
+
+ /// Return the value of the flag in this raw_fd_ostream indicating whether an
+ /// output error has been encountered.
+ /// This doesn't implicitly flush any pending output. Also, it doesn't
+ /// guarantee to detect all errors unless the stream has been closed.
+ bool has_error() const { return bool(EC); }
+
+ /// Set the flag read by has_error() to false. If the error flag is set at the
+ /// time when this raw_ostream's destructor is called, report_fatal_error is
+ /// called to report the error. Use clear_error() after handling the error to
+ /// avoid this behavior.
+ ///
+ /// "Errors should never pass silently.
+ /// Unless explicitly silenced."
+ /// - from The Zen of Python, by Tim Peters
+ ///
+ void clear_error() { EC = std::error_code(); }
+
+ /// Locks the underlying file.
+ ///
+ /// @returns RAII object that releases the lock upon leaving the scope, if the
+ /// locking was successful. Otherwise returns corresponding
+ /// error code.
+ ///
+ /// The function blocks the current thread until the lock become available or
+ /// error occurs.
+ ///
+ /// Possible use of this function may be as follows:
+ ///
+ /// @code{.cpp}
+ /// if (auto L = stream.lock()) {
+ /// // ... do action that require file to be locked.
+ /// } else {
+ /// handleAllErrors(std::move(L.takeError()), [&](ErrorInfoBase &EIB) {
+ /// // ... handle lock error.
+ /// });
+ /// }
+ /// @endcode
+ [[nodiscard]] Expected<sys::fs::FileLocker> lock();
+
+ /// Tries to lock the underlying file within the specified period.
+ ///
+ /// @returns RAII object that releases the lock upon leaving the scope, if the
+ /// locking was successful. Otherwise returns corresponding
+ /// error code.
+ ///
+ /// It is used as @ref lock.
+ [[nodiscard]] Expected<sys::fs::FileLocker>
+ tryLockFor(Duration const &Timeout);
+};
+
+/// This returns a reference to a raw_fd_ostream for standard output. Use it
+/// like: outs() << "foo" << "bar";
+raw_fd_ostream &outs();
+
+/// This returns a reference to a raw_ostream for standard error.
+/// Use it like: errs() << "foo" << "bar";
+/// By default, the stream is tied to stdout to ensure stdout is flushed before
+/// stderr is written, to ensure the error messages are written in their
+/// expected place.
+raw_fd_ostream &errs();
+
+/// This returns a reference to a raw_ostream which simply discards output.
+raw_ostream &nulls();
+
+//===----------------------------------------------------------------------===//
+// File Streams
+//===----------------------------------------------------------------------===//
+
+/// A raw_ostream of a file for reading/writing/seeking.
+///
+class raw_fd_stream : public raw_fd_ostream {
+public:
+ /// Open the specified file for reading/writing/seeking. If an error occurs,
+ /// information about the error is put into EC, and the stream should be
+ /// immediately destroyed.
+ raw_fd_stream(StringRef Filename, std::error_code &EC);
+
+ /// This reads the \p Size bytes into a buffer pointed by \p Ptr.
+ ///
+ /// \param Ptr The start of the buffer to hold data to be read.
+ ///
+ /// \param Size The number of bytes to be read.
+ ///
+ /// On success, the number of bytes read is returned, and the file position is
+ /// advanced by this number. On error, -1 is returned, use error() to get the
+ /// error code.
+ ssize_t read(char *Ptr, size_t Size);
+
+ /// Check if \p OS is a pointer of type raw_fd_stream*.
+ static bool classof(const raw_ostream *OS);
+};
+
+//===----------------------------------------------------------------------===//
+// Output Stream Adaptors
+//===----------------------------------------------------------------------===//
+
+/// A raw_ostream that writes to an std::string. This is a simple adaptor
+/// class. This class does not encounter output errors.
+/// raw_string_ostream operates without a buffer, delegating all memory
+/// management to the std::string. Thus the std::string is always up-to-date,
+/// may be used directly and there is no need to call flush().
+class raw_string_ostream : public raw_ostream {
+ std::string &OS;
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ /// Return the current position within the stream, not counting the bytes
+ /// currently in the buffer.
+ uint64_t current_pos() const override { return OS.size(); }
+
+public:
+ explicit raw_string_ostream(std::string &O) : OS(O) {
+ SetUnbuffered();
+ }
+
+ /// Returns the string's reference. In most cases it is better to simply use
+ /// the underlying std::string directly.
+ /// TODO: Consider removing this API.
+ std::string &str() { return OS; }
+
+ void reserveExtraSpace(uint64_t ExtraSize) override {
+ OS.reserve(tell() + ExtraSize);
+ }
+};
+
+/// A raw_ostream that writes to an SmallVector or SmallString. This is a
+/// simple adaptor class. This class does not encounter output errors.
+/// raw_svector_ostream operates without a buffer, delegating all memory
+/// management to the SmallString. Thus the SmallString is always up-to-date,
+/// may be used directly and there is no need to call flush().
+class raw_svector_ostream : public raw_pwrite_stream {
+ SmallVectorImpl<char> &OS;
+
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t Size) override;
+
+ void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
+
+ /// Return the current position within the stream.
+ uint64_t current_pos() const override;
+
+public:
+ /// Construct a new raw_svector_ostream.
+ ///
+ /// \param O The vector to write to; this should generally have at least 128
+ /// bytes free to avoid any extraneous memory overhead.
+ explicit raw_svector_ostream(SmallVectorImpl<char> &O) : OS(O) {
+ SetUnbuffered();
+ }
+
+ ~raw_svector_ostream() override = default;
+
+ void flush() = delete;
+
+ /// Return a StringRef for the vector contents.
+ StringRef str() const { return StringRef(OS.data(), OS.size()); }
+
+ void reserveExtraSpace(uint64_t ExtraSize) override {
+ OS.reserve(tell() + ExtraSize);
+ }
+};
+
+/// A raw_ostream that discards all output.
+class raw_null_ostream : public raw_pwrite_stream {
+ /// See raw_ostream::write_impl.
+ void write_impl(const char *Ptr, size_t size) override;
+ void pwrite_impl(const char *Ptr, size_t Size, uint64_t Offset) override;
+
+ /// Return the current position within the stream, not counting the bytes
+ /// currently in the buffer.
+ uint64_t current_pos() const override;
+
+public:
+ explicit raw_null_ostream() = default;
+ ~raw_null_ostream() override;
+};
+
+class buffer_ostream : public raw_svector_ostream {
+ raw_ostream &OS;
+ SmallVector<char, 0> Buffer;
+
+ void anchor() override;
+
+public:
+ buffer_ostream(raw_ostream &OS) : raw_svector_ostream(Buffer), OS(OS) {}
+ ~buffer_ostream() override { OS << str(); }
+};
+
+class buffer_unique_ostream : public raw_svector_ostream {
+ std::unique_ptr<raw_ostream> OS;
+ SmallVector<char, 0> Buffer;
+
+ void anchor() override;
+
+public:
+ buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
+ : raw_svector_ostream(Buffer), OS(std::move(OS)) {
+ // Turn off buffering on OS, which we now own, to avoid allocating a buffer
+ // when the destructor writes only to be immediately flushed again.
+ this->OS->SetUnbuffered();
+ }
+ ~buffer_unique_ostream() override { *OS << str(); }
+};
+
+class Error;
+
+/// This helper creates an output stream and then passes it to \p Write.
+/// The stream created is based on the specified \p OutputFileName:
+/// llvm::outs for "-", raw_null_ostream for "/dev/null", and raw_fd_ostream
+/// for other names. For raw_fd_ostream instances, the stream writes to
+/// a temporary file. The final output file is atomically replaced with the
+/// temporary file after the \p Write function is finished.
+Error writeToOutput(StringRef OutputFileName,
+ std::function<Error(raw_ostream &)> Write);
+
+raw_ostream &operator<<(raw_ostream &OS, std::nullopt_t);
+
+template <typename T, typename = decltype(std::declval<raw_ostream &>()
+ << std::declval<const T &>())>
+raw_ostream &operator<<(raw_ostream &OS, const std::optional<T> &O) {
+ if (O)
+ OS << *O;
+ else
+ OS << std::nullopt;
+ return OS;
+}
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_RAW_OSTREAM_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/thread.h b/contrib/libs/llvm16/include/llvm/Support/thread.h
new file mode 100644
index 00000000000..8302a69512d
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/thread.h
@@ -0,0 +1,255 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===-- llvm/Support/thread.h - Wrapper for <thread> ------------*- 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 header is a wrapper for <thread> that works around problems with the
+// MSVC headers when exceptions are disabled. It also provides llvm::thread,
+// which is either a typedef of std::thread or a replacement that calls the
+// function synchronously depending on the value of LLVM_ENABLE_THREADS.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_THREAD_H
+#define LLVM_SUPPORT_THREAD_H
+
+#include "llvm/Config/llvm-config.h"
+#include <optional>
+
+#ifdef _WIN32
+typedef unsigned long DWORD;
+typedef void *PVOID;
+typedef PVOID HANDLE;
+#endif
+
+#if LLVM_ENABLE_THREADS
+
+#include <thread>
+
+namespace llvm {
+
+#if LLVM_ON_UNIX || _WIN32
+
+/// LLVM thread following std::thread interface with added constructor to
+/// specify stack size.
+class thread {
+ template <typename CalleeTuple> static void GenericThreadProxy(void *Ptr) {
+ std::unique_ptr<CalleeTuple> Callee(static_cast<CalleeTuple *>(Ptr));
+ std::apply(
+ [](auto &&F, auto &&...Args) {
+ std::forward<decltype(F)>(F)(std::forward<decltype(Args)>(Args)...);
+ },
+ *Callee);
+ }
+
+public:
+#if LLVM_ON_UNIX
+ using native_handle_type = pthread_t;
+ using id = pthread_t;
+ using start_routine_type = void *(*)(void *);
+
+ template <typename CalleeTuple> static void *ThreadProxy(void *Ptr) {
+ GenericThreadProxy<CalleeTuple>(Ptr);
+ return nullptr;
+ }
+#elif _WIN32
+ using native_handle_type = HANDLE;
+ using id = DWORD;
+ using start_routine_type = unsigned(__stdcall *)(void *);
+
+ template <typename CalleeTuple>
+ static unsigned __stdcall ThreadProxy(void *Ptr) {
+ GenericThreadProxy<CalleeTuple>(Ptr);
+ return 0;
+ }
+#endif
+
+ static const std::optional<unsigned> DefaultStackSize;
+
+ thread() : Thread(native_handle_type()) {}
+ thread(thread &&Other) noexcept
+ : Thread(std::exchange(Other.Thread, native_handle_type())) {}
+
+ template <class Function, class... Args>
+ explicit thread(Function &&f, Args &&...args)
+ : thread(DefaultStackSize, f, args...) {}
+
+ template <class Function, class... Args>
+ explicit thread(std::optional<unsigned> StackSizeInBytes, Function &&f,
+ Args &&...args);
+ thread(const thread &) = delete;
+
+ ~thread() {
+ if (joinable())
+ std::terminate();
+ }
+
+ thread &operator=(thread &&Other) noexcept {
+ if (joinable())
+ std::terminate();
+ Thread = std::exchange(Other.Thread, native_handle_type());
+ return *this;
+ }
+
+ bool joinable() const noexcept { return Thread != native_handle_type(); }
+
+ inline id get_id() const noexcept;
+
+ native_handle_type native_handle() const noexcept { return Thread; }
+
+ static unsigned hardware_concurrency() {
+ return std::thread::hardware_concurrency();
+ };
+
+ inline void join();
+ inline void detach();
+
+ void swap(llvm::thread &Other) noexcept { std::swap(Thread, Other.Thread); }
+
+private:
+ native_handle_type Thread;
+};
+
+thread::native_handle_type
+llvm_execute_on_thread_impl(thread::start_routine_type ThreadFunc, void *Arg,
+ std::optional<unsigned> StackSizeInBytes);
+void llvm_thread_join_impl(thread::native_handle_type Thread);
+void llvm_thread_detach_impl(thread::native_handle_type Thread);
+thread::id llvm_thread_get_id_impl(thread::native_handle_type Thread);
+thread::id llvm_thread_get_current_id_impl();
+
+template <class Function, class... Args>
+thread::thread(std::optional<unsigned> StackSizeInBytes, Function &&f,
+ Args &&...args) {
+ typedef std::tuple<std::decay_t<Function>, std::decay_t<Args>...> CalleeTuple;
+ std::unique_ptr<CalleeTuple> Callee(
+ new CalleeTuple(std::forward<Function>(f), std::forward<Args>(args)...));
+
+ Thread = llvm_execute_on_thread_impl(ThreadProxy<CalleeTuple>, Callee.get(),
+ StackSizeInBytes);
+ if (Thread != native_handle_type())
+ Callee.release();
+}
+
+thread::id thread::get_id() const noexcept {
+ return llvm_thread_get_id_impl(Thread);
+}
+
+void thread::join() {
+ llvm_thread_join_impl(Thread);
+ Thread = native_handle_type();
+}
+
+void thread::detach() {
+ llvm_thread_detach_impl(Thread);
+ Thread = native_handle_type();
+}
+
+namespace this_thread {
+inline thread::id get_id() { return llvm_thread_get_current_id_impl(); }
+} // namespace this_thread
+
+#else // !LLVM_ON_UNIX && !_WIN32
+
+/// std::thread backed implementation of llvm::thread interface that ignores the
+/// stack size request.
+class thread {
+public:
+ using native_handle_type = std::thread::native_handle_type;
+ using id = std::thread::id;
+
+ thread() : Thread(std::thread()) {}
+ thread(thread &&Other) noexcept
+ : Thread(std::exchange(Other.Thread, std::thread())) {}
+
+ template <class Function, class... Args>
+ explicit thread(std::optional<unsigned> StackSizeInBytes, Function &&f,
+ Args &&...args)
+ : Thread(std::forward<Function>(f), std::forward<Args>(args)...) {}
+
+ template <class Function, class... Args>
+ explicit thread(Function &&f, Args &&...args) : Thread(f, args...) {}
+
+ thread(const thread &) = delete;
+
+ ~thread() {}
+
+ thread &operator=(thread &&Other) noexcept {
+ Thread = std::exchange(Other.Thread, std::thread());
+ return *this;
+ }
+
+ bool joinable() const noexcept { return Thread.joinable(); }
+
+ id get_id() const noexcept { return Thread.get_id(); }
+
+ native_handle_type native_handle() noexcept { return Thread.native_handle(); }
+
+ static unsigned hardware_concurrency() {
+ return std::thread::hardware_concurrency();
+ };
+
+ inline void join() { Thread.join(); }
+ inline void detach() { Thread.detach(); }
+
+ void swap(llvm::thread &Other) noexcept { std::swap(Thread, Other.Thread); }
+
+private:
+ std::thread Thread;
+};
+
+namespace this_thread {
+ inline thread::id get_id() { return std::this_thread::get_id(); }
+}
+
+#endif // LLVM_ON_UNIX || _WIN32
+
+} // namespace llvm
+
+#else // !LLVM_ENABLE_THREADS
+
+#include <utility>
+
+namespace llvm {
+
+struct thread {
+ thread() {}
+ thread(thread &&other) {}
+ template <class Function, class... Args>
+ explicit thread(std::optional<unsigned> StackSizeInBytes, Function &&f,
+ Args &&...args) {
+ f(std::forward<Args>(args)...);
+ }
+ template <class Function, class... Args>
+ explicit thread(Function &&f, Args &&...args) {
+ f(std::forward<Args>(args)...);
+ }
+ thread(const thread &) = delete;
+
+ void detach() {
+ report_fatal_error("Detaching from a thread does not make sense with no "
+ "threading support");
+ }
+ void join() {}
+ static unsigned hardware_concurrency() { return 1; };
+};
+
+} // namespace llvm
+
+#endif // LLVM_ENABLE_THREADS
+
+#endif // LLVM_SUPPORT_THREAD_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/type_traits.h b/contrib/libs/llvm16/include/llvm/Support/type_traits.h
new file mode 100644
index 00000000000..5c80f0b158e
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/type_traits.h
@@ -0,0 +1,147 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+//===- llvm/Support/type_traits.h - Simplfied type traits -------*- 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 provides useful additions to the standard type_traits library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_TYPE_TRAITS_H
+#define LLVM_SUPPORT_TYPE_TRAITS_H
+
+#include "llvm/Support/Compiler.h"
+#include <type_traits>
+#include <utility>
+
+namespace llvm {
+
+
+/// Metafunction that determines whether the given type is either an
+/// integral type or an enumeration type, including enum classes.
+///
+/// Note that this accepts potentially more integral types than is_integral
+/// because it is based on being implicitly convertible to an integral type.
+/// Also note that enum classes aren't implicitly convertible to integral types,
+/// the value may therefore need to be explicitly converted before being used.
+template <typename T> class is_integral_or_enum {
+ using UnderlyingT = std::remove_reference_t<T>;
+
+public:
+ static const bool value =
+ !std::is_class<UnderlyingT>::value && // Filter conversion operators.
+ !std::is_pointer<UnderlyingT>::value &&
+ !std::is_floating_point<UnderlyingT>::value &&
+ (std::is_enum<UnderlyingT>::value ||
+ std::is_convertible<UnderlyingT, unsigned long long>::value);
+};
+
+/// If T is a pointer, just return it. If it is not, return T&.
+template<typename T, typename Enable = void>
+struct add_lvalue_reference_if_not_pointer { using type = T &; };
+
+template <typename T>
+struct add_lvalue_reference_if_not_pointer<
+ T, std::enable_if_t<std::is_pointer<T>::value>> {
+ using type = T;
+};
+
+/// If T is a pointer to X, return a pointer to const X. If it is not,
+/// return const T.
+template<typename T, typename Enable = void>
+struct add_const_past_pointer { using type = const T; };
+
+template <typename T>
+struct add_const_past_pointer<T, std::enable_if_t<std::is_pointer<T>::value>> {
+ using type = const std::remove_pointer_t<T> *;
+};
+
+template <typename T, typename Enable = void>
+struct const_pointer_or_const_ref {
+ using type = const T &;
+};
+template <typename T>
+struct const_pointer_or_const_ref<T,
+ std::enable_if_t<std::is_pointer<T>::value>> {
+ using type = typename add_const_past_pointer<T>::type;
+};
+
+namespace detail {
+/// Internal utility to detect trivial copy construction.
+template<typename T> union copy_construction_triviality_helper {
+ T t;
+ copy_construction_triviality_helper() = default;
+ copy_construction_triviality_helper(const copy_construction_triviality_helper&) = default;
+ ~copy_construction_triviality_helper() = default;
+};
+/// Internal utility to detect trivial move construction.
+template<typename T> union move_construction_triviality_helper {
+ T t;
+ move_construction_triviality_helper() = default;
+ move_construction_triviality_helper(move_construction_triviality_helper&&) = default;
+ ~move_construction_triviality_helper() = default;
+};
+
+template<class T>
+union trivial_helper {
+ T t;
+};
+
+} // end namespace detail
+
+/// An implementation of `std::is_trivially_copy_constructible` since we have
+/// users with STLs that don't yet include it.
+template <typename T>
+struct is_trivially_copy_constructible
+ : std::is_copy_constructible<
+ ::llvm::detail::copy_construction_triviality_helper<T>> {};
+template <typename T>
+struct is_trivially_copy_constructible<T &> : std::true_type {};
+template <typename T>
+struct is_trivially_copy_constructible<T &&> : std::false_type {};
+
+/// An implementation of `std::is_trivially_move_constructible` since we have
+/// users with STLs that don't yet include it.
+template <typename T>
+struct is_trivially_move_constructible
+ : std::is_move_constructible<
+ ::llvm::detail::move_construction_triviality_helper<T>> {};
+template <typename T>
+struct is_trivially_move_constructible<T &> : std::true_type {};
+template <typename T>
+struct is_trivially_move_constructible<T &&> : std::true_type {};
+
+
+template <typename T>
+struct is_copy_assignable {
+ template<class F>
+ static auto get(F*) -> decltype(std::declval<F &>() = std::declval<const F &>(), std::true_type{});
+ static std::false_type get(...);
+ static constexpr bool value = decltype(get((T*)nullptr))::value;
+};
+
+template <typename T>
+struct is_move_assignable {
+ template<class F>
+ static auto get(F*) -> decltype(std::declval<F &>() = std::declval<F &&>(), std::true_type{});
+ static std::false_type get(...);
+ static constexpr bool value = decltype(get((T*)nullptr))::value;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_SUPPORT_TYPE_TRAITS_H
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
diff --git a/contrib/libs/llvm16/include/llvm/Support/xxhash.h b/contrib/libs/llvm16/include/llvm/Support/xxhash.h
new file mode 100644
index 00000000000..94811149284
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Support/xxhash.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#endif
+
+/*
+ xxHash - Extremely Fast Hash algorithm
+ Header File
+ Copyright (C) 2012-2016, Yann Collet.
+
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - xxHash source repository : https://github.com/Cyan4973/xxHash
+*/
+
+/* based on revision d2df04efcbef7d7f6886d345861e5dfda4edacc1 Removed
+ * everything but a simple interface for computing XXh64. */
+
+#ifndef LLVM_SUPPORT_XXHASH_H
+#define LLVM_SUPPORT_XXHASH_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+uint64_t xxHash64(llvm::StringRef Data);
+uint64_t xxHash64(llvm::ArrayRef<uint8_t> Data);
+}
+
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif