diff options
Diffstat (limited to 'lib/Support/Windows')
| -rw-r--r-- | lib/Support/Windows/COM.inc | 7 | ||||
| -rw-r--r-- | lib/Support/Windows/DynamicLibrary.inc | 7 | ||||
| -rw-r--r-- | lib/Support/Windows/Host.inc | 7 | ||||
| -rw-r--r-- | lib/Support/Windows/Memory.inc | 96 | ||||
| -rw-r--r-- | lib/Support/Windows/Mutex.inc | 7 | ||||
| -rw-r--r-- | lib/Support/Windows/Path.inc | 98 | ||||
| -rw-r--r-- | lib/Support/Windows/Process.inc | 9 | ||||
| -rw-r--r-- | lib/Support/Windows/Program.inc | 7 | ||||
| -rw-r--r-- | lib/Support/Windows/RWMutex.inc | 7 | ||||
| -rw-r--r-- | lib/Support/Windows/Signals.inc | 11 | ||||
| -rw-r--r-- | lib/Support/Windows/ThreadLocal.inc | 7 | ||||
| -rw-r--r-- | lib/Support/Windows/Threading.inc | 23 | ||||
| -rw-r--r-- | lib/Support/Windows/Watchdog.inc | 7 | ||||
| -rw-r--r-- | lib/Support/Windows/WindowsSupport.h | 7 |
14 files changed, 210 insertions, 90 deletions
diff --git a/lib/Support/Windows/COM.inc b/lib/Support/Windows/COM.inc index 54f3ecf28ec25..002182bc39394 100644 --- a/lib/Support/Windows/COM.inc +++ b/lib/Support/Windows/COM.inc @@ -1,9 +1,8 @@ //==- llvm/Support/Windows/COM.inc - Windows COM Implementation -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc index 1d47f0848a6df..71b206c4cf9ee 100644 --- a/lib/Support/Windows/DynamicLibrary.inc +++ b/lib/Support/Windows/DynamicLibrary.inc @@ -1,9 +1,8 @@ //===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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/lib/Support/Windows/Host.inc b/lib/Support/Windows/Host.inc index 58c4dc5d678ff..21b947f26df3e 100644 --- a/lib/Support/Windows/Host.inc +++ b/lib/Support/Windows/Host.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Win32/Host.inc ------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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/lib/Support/Windows/Memory.inc b/lib/Support/Windows/Memory.inc index 318e65aaa9ee7..a67f9c7d0f35b 100644 --- a/lib/Support/Windows/Memory.inc +++ b/lib/Support/Windows/Memory.inc @@ -1,9 +1,8 @@ //===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -23,7 +22,7 @@ namespace { DWORD getWindowsProtectionFlags(unsigned Flags) { - switch (Flags) { + switch (Flags & llvm::sys::Memory::MF_RWE_MASK) { // Contrary to what you might expect, the Windows page protection flags // are not a bitwise combination of RWX values case llvm::sys::Memory::MF_READ: @@ -48,6 +47,9 @@ DWORD getWindowsProtectionFlags(unsigned Flags) { return PAGE_NOACCESS; } +// While we'd be happy to allocate single pages, the Windows allocation +// granularity may be larger than a single page (in practice, it is 64K) +// so mapping less than that will create an unreachable fragment of memory. size_t getAllocationGranularity() { SYSTEM_INFO Info; ::GetSystemInfo(&Info); @@ -57,6 +59,38 @@ size_t getAllocationGranularity() { return Info.dwAllocationGranularity; } +// Large/huge memory pages need explicit process permissions in order to be +// used. See https://blogs.msdn.microsoft.com/oldnewthing/20110128-00/?p=11643 +// Also large pages need to be manually enabled on your OS. If all this is +// sucessfull, we return the minimal large memory page size. +static size_t enableProcessLargePages() { + HANDLE Token = 0; + size_t LargePageMin = GetLargePageMinimum(); + if (LargePageMin) + OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &Token); + if (!Token) + return 0; + LUID Luid; + if (!LookupPrivilegeValue(0, SE_LOCK_MEMORY_NAME, &Luid)) { + CloseHandle(Token); + return 0; + } + TOKEN_PRIVILEGES TP{}; + TP.PrivilegeCount = 1; + TP.Privileges[0].Luid = Luid; + TP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (!AdjustTokenPrivileges(Token, FALSE, &TP, 0, 0, 0)) { + CloseHandle(Token); + return 0; + } + DWORD E = GetLastError(); + CloseHandle(Token); + if (E == ERROR_SUCCESS) + return LargePageMin; + return 0; +} + } // namespace namespace llvm { @@ -75,22 +109,23 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, if (NumBytes == 0) return MemoryBlock(); - // While we'd be happy to allocate single pages, the Windows allocation - // granularity may be larger than a single page (in practice, it is 64K) - // so mapping less than that will create an unreachable fragment of memory. - // Avoid using one-time initialization of static locals here, since they - // aren't thread safe with MSVC. - static volatile size_t GranularityCached; - size_t Granularity = GranularityCached; - if (Granularity == 0) { - Granularity = getAllocationGranularity(); - GranularityCached = Granularity; + static size_t DefaultGranularity = getAllocationGranularity(); + static size_t LargePageGranularity = enableProcessLargePages(); + + DWORD AllocType = MEM_RESERVE | MEM_COMMIT; + bool HugePages = false; + size_t Granularity = DefaultGranularity; + + if ((Flags & MF_HUGE_HINT) && LargePageGranularity > 0) { + AllocType |= MEM_LARGE_PAGES; + HugePages = true; + Granularity = LargePageGranularity; } - const size_t NumBlocks = (NumBytes+Granularity-1)/Granularity; + size_t NumBlocks = (NumBytes + Granularity - 1) / Granularity; uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + - NearBlock->size() + NearBlock->allocatedSize() : 0; // If the requested address is not aligned to the allocation granularity, @@ -100,13 +135,13 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, DWORD Protect = getWindowsProtectionFlags(Flags); - void *PA = ::VirtualAlloc(reinterpret_cast<void*>(Start), - NumBlocks*Granularity, - MEM_RESERVE | MEM_COMMIT, Protect); + size_t AllocSize = NumBlocks * Granularity; + void *PA = ::VirtualAlloc(reinterpret_cast<void *>(Start), + AllocSize, AllocType, Protect); if (PA == NULL) { - if (NearBlock) { - // Try again without the NearBlock hint - return allocateMappedMemory(NumBytes, NULL, Flags, EC); + if (NearBlock || HugePages) { + // Try again without the NearBlock hint and without large memory pages + return allocateMappedMemory(NumBytes, NULL, Flags & ~MF_HUGE_HINT, EC); } EC = mapWindowsError(::GetLastError()); return MemoryBlock(); @@ -114,40 +149,41 @@ MemoryBlock Memory::allocateMappedMemory(size_t NumBytes, MemoryBlock Result; Result.Address = PA; - Result.Size = NumBlocks*Granularity; + Result.AllocatedSize = AllocSize; + Result.Flags = (Flags & ~MF_HUGE_HINT) | (HugePages ? MF_HUGE_HINT : 0); if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(Result.Address, Result.Size); + Memory::InvalidateInstructionCache(Result.Address, AllocSize); return Result; } std::error_code Memory::releaseMappedMemory(MemoryBlock &M) { - if (M.Address == 0 || M.Size == 0) + if (M.Address == 0 || M.AllocatedSize == 0) return std::error_code(); if (!VirtualFree(M.Address, 0, MEM_RELEASE)) return mapWindowsError(::GetLastError()); M.Address = 0; - M.Size = 0; + M.AllocatedSize = 0; return std::error_code(); } std::error_code Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { - if (M.Address == 0 || M.Size == 0) + if (M.Address == 0 || M.AllocatedSize == 0) return std::error_code(); DWORD Protect = getWindowsProtectionFlags(Flags); DWORD OldFlags; - if (!VirtualProtect(M.Address, M.Size, Protect, &OldFlags)) + if (!VirtualProtect(M.Address, M.AllocatedSize, Protect, &OldFlags)) return mapWindowsError(::GetLastError()); if (Flags & MF_EXEC) - Memory::InvalidateInstructionCache(M.Address, M.Size); + Memory::InvalidateInstructionCache(M.Address, M.AllocatedSize); return std::error_code(); } diff --git a/lib/Support/Windows/Mutex.inc b/lib/Support/Windows/Mutex.inc index 0af145ec9a4e6..b55b14febf2cd 100644 --- a/lib/Support/Windows/Mutex.inc +++ b/lib/Support/Windows/Mutex.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Win32/Mutex.inc - Win32 Mutex Implementation -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc index d34aa763124c9..5704930aeeccb 100644 --- a/lib/Support/Windows/Path.inc +++ b/lib/Support/Windows/Path.inc @@ -1,9 +1,8 @@ //===- llvm/Support/Windows/Path.inc - Windows Path Impl --------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -735,6 +734,14 @@ std::error_code status(int FD, file_status &Result) { return getStatus(FileHandle, Result); } +std::error_code status(file_t FileHandle, file_status &Result) { + return getStatus(FileHandle, Result); +} + +unsigned getUmask() { + return 0; +} + std::error_code setPermissions(const Twine &Path, perms Permissions) { SmallVector<wchar_t, 128> PathUTF16; if (std::error_code EC = widenPath(Path, PathUTF16)) @@ -766,6 +773,11 @@ std::error_code setPermissions(const Twine &Path, perms Permissions) { return std::error_code(); } +std::error_code setPermissions(int FD, perms Permissions) { + // FIXME Not implemented. + return std::make_error_code(std::errc::not_supported); +} + std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, TimePoint<> ModificationTime) { FILETIME AccessFT = toFILETIME(AccessTime); @@ -776,10 +788,9 @@ std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, return std::error_code(); } -std::error_code mapped_file_region::init(int FD, uint64_t Offset, - mapmode Mode) { +std::error_code mapped_file_region::init(sys::fs::file_t OrigFileHandle, + uint64_t Offset, mapmode Mode) { this->Mode = Mode; - HANDLE OrigFileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); if (OrigFileHandle == INVALID_HANDLE_VALUE) return make_error_code(errc::bad_file_descriptor); @@ -846,8 +857,9 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset, return std::error_code(); } -mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, - uint64_t offset, std::error_code &ec) +mapped_file_region::mapped_file_region(sys::fs::file_t fd, mapmode mode, + size_t length, uint64_t offset, + std::error_code &ec) : Size(length), Mapping() { ec = init(fd, offset, mode); if (ec) @@ -1197,9 +1209,73 @@ Expected<file_t> openNativeFileForRead(const Twine &Name, OpenFlags Flags, return Result; } -void closeFile(file_t &F) { - ::CloseHandle(F); +file_t convertFDToNativeFile(int FD) { + return reinterpret_cast<HANDLE>(::_get_osfhandle(FD)); +} + +file_t getStdinHandle() { return ::GetStdHandle(STD_INPUT_HANDLE); } +file_t getStdoutHandle() { return ::GetStdHandle(STD_OUTPUT_HANDLE); } +file_t getStderrHandle() { return ::GetStdHandle(STD_ERROR_HANDLE); } + +std::error_code readNativeFileImpl(file_t FileHandle, char *BufPtr, size_t BytesToRead, + size_t *BytesRead, OVERLAPPED *Overlap) { + // ReadFile can only read 2GB at a time. The caller should check the number of + // bytes and read in a loop until termination. + DWORD BytesToRead32 = + std::min(size_t(std::numeric_limits<DWORD>::max()), BytesToRead); + DWORD BytesRead32 = 0; + bool Success = + ::ReadFile(FileHandle, BufPtr, BytesToRead32, &BytesRead32, Overlap); + *BytesRead = BytesRead32; + if (!Success) { + DWORD Err = ::GetLastError(); + // Pipe EOF is not an error. + if (Err == ERROR_BROKEN_PIPE) + return std::error_code(); + return mapWindowsError(Err); + } + return std::error_code(); +} + +std::error_code readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf, + size_t *BytesRead) { + return readNativeFileImpl(FileHandle, Buf.data(), Buf.size(), BytesRead, + /*Overlap=*/nullptr); +} + +std::error_code readNativeFileSlice(file_t FileHandle, + MutableArrayRef<char> Buf, size_t Offset) { + char *BufPtr = Buf.data(); + size_t BytesLeft = Buf.size(); + + while (BytesLeft) { + uint64_t CurOff = Buf.size() - BytesLeft + Offset; + OVERLAPPED Overlapped = {}; + Overlapped.Offset = uint32_t(CurOff); + Overlapped.OffsetHigh = uint32_t(uint64_t(CurOff) >> 32); + + size_t BytesRead = 0; + if (auto EC = readNativeFileImpl(FileHandle, BufPtr, BytesLeft, &BytesRead, + &Overlapped)) + return EC; + + // Once we reach EOF, zero the remaining bytes in the buffer. + if (BytesRead == 0) { + memset(BufPtr, 0, BytesLeft); + break; + } + BytesLeft -= BytesRead; + BufPtr += BytesRead; + } + return std::error_code(); +} + +std::error_code closeFile(file_t &F) { + file_t TmpF = F; F = kInvalidFile; + if (!::CloseHandle(TmpF)) + return mapWindowsError(::GetLastError()); + return std::error_code(); } std::error_code remove_directories(const Twine &path, bool IgnoreErrors) { diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc index 2b2d792314343..4b91f9f7fc667 100644 --- a/lib/Support/Windows/Process.inc +++ b/lib/Support/Windows/Process.inc @@ -1,9 +1,8 @@ //===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -57,7 +56,7 @@ static unsigned computePageSize() { return static_cast<unsigned>(info.dwPageSize); } -unsigned Process::getPageSize() { +Expected<unsigned> Process::getPageSize() { static unsigned Ret = computePageSize(); return Ret; } diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc index c037956603f26..0f54e59ee55b6 100644 --- a/lib/Support/Windows/Program.inc +++ b/lib/Support/Windows/Program.inc @@ -1,9 +1,8 @@ //===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc index 5eb9351eee526..8df9bc3941603 100644 --- a/lib/Support/Windows/RWMutex.inc +++ b/lib/Support/Windows/RWMutex.inc @@ -1,9 +1,8 @@ //= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc index 41eb5e593aa5c..6a820ef22b1e9 100644 --- a/lib/Support/Windows/Signals.inc +++ b/lib/Support/Windows/Signals.inc @@ -1,9 +1,8 @@ //===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -557,6 +556,10 @@ void llvm::sys::SetInterruptFunction(void (*IF)()) { LeaveCriticalSection(&CriticalSection); } +void llvm::sys::SetInfoSignalFunction(void (*Handler)()) { + // Unimplemented. +} + /// Add a function to be called when a signal is delivered to the process. The /// handler can have a cookie passed to it to identify what instance of the diff --git a/lib/Support/Windows/ThreadLocal.inc b/lib/Support/Windows/ThreadLocal.inc index 8be1c3ecfbb90..1e0ed955e9abe 100644 --- a/lib/Support/Windows/ThreadLocal.inc +++ b/lib/Support/Windows/ThreadLocal.inc @@ -1,9 +1,8 @@ //= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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/lib/Support/Windows/Threading.inc b/lib/Support/Windows/Threading.inc index 0bd92f66c6b89..96649472cc90b 100644 --- a/lib/Support/Windows/Threading.inc +++ b/lib/Support/Windows/Threading.inc @@ -1,9 +1,8 @@ //===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -107,3 +106,19 @@ void llvm::get_thread_name(SmallVectorImpl<char> &Name) { // value. Name.clear(); } + +SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { + // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority + // Begin background processing mode. The system lowers the resource scheduling + // priorities of the thread so that it can perform background work without + // significantly affecting activity in the foreground. + // End background processing mode. The system restores the resource scheduling + // priorities of the thread as they were before the thread entered background + // processing mode. + return SetThreadPriority(GetCurrentThread(), + Priority == ThreadPriority::Background + ? THREAD_MODE_BACKGROUND_BEGIN + : THREAD_MODE_BACKGROUND_END) + ? SetThreadPriorityResult::SUCCESS + : SetThreadPriorityResult::FAILURE; +} diff --git a/lib/Support/Windows/Watchdog.inc b/lib/Support/Windows/Watchdog.inc index fab2bdf2a9411..a362c999de769 100644 --- a/lib/Support/Windows/Watchdog.inc +++ b/lib/Support/Windows/Watchdog.inc @@ -1,9 +1,8 @@ //===--- Windows/Watchdog.inc - Windows Watchdog Implementation -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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/lib/Support/Windows/WindowsSupport.h b/lib/Support/Windows/WindowsSupport.h index 979cc5d013904..fed9b2f462ef7 100644 --- a/lib/Support/Windows/WindowsSupport.h +++ b/lib/Support/Windows/WindowsSupport.h @@ -1,9 +1,8 @@ //===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // |
