[llvm] r334630 - LTO: Keep file handles open for memory mapped files.
Michael Kruse via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 26 15:55:30 PDT 2018
Hi,
this patch broke bugpoint on Windows:
$ (cd 'C:\Users\MEINER~1\AppData\Local\Temp\reproduce-bruxta1h' &&
'C:\Users\meinersbur\build\llvm\release\bin\bugpoint.exe'
'-opt-command=C:\Users\meinersbur\build\llvm\release\bin\opt.exe'
'C:\Users\MEINER~1\AppData\Local\Temp\reproduce-bruxta1h\pr3821817-precompute.ll'
-scoped-noalias -polly-codegen)
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-b43aded.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-6517e54.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-6575634.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-7dad9ae.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-81165ee.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-018d544.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-e88e95a.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-d37f5e8.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-29843f5.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-26d3c62.bc: error: Could not open input file:
permission denied
C:\Users\meinersbur\build\llvm\release\bin\opt.exe:
bugpoint-input-dc3b1bc.bc: error: Could not open input file:
permission denied
verify failed!
bugpoint-input-b43aded.bc is a strange file. I can see it in explorer,
but when trying to open it, Notepad claims it doesn't exist and offers
to create it (which will then fail).
Michael
2018-06-13 13:03 GMT-05:00 Peter Collingbourne via llvm-commits
<llvm-commits at lists.llvm.org>:
> Author: pcc
> Date: Wed Jun 13 11:03:14 2018
> New Revision: 334630
>
> URL: http://llvm.org/viewvc/llvm-project?rev=334630&view=rev
> Log:
> LTO: Keep file handles open for memory mapped files.
>
> On Windows we've observed that if you open a file, write to it, map it into
> memory and close the file handle, the contents of the memory mapping can
> sometimes be incorrect. That was what we did when adding an entry to the
> ThinLTO cache using the TempFile and MemoryBuffer classes, and it was causing
> intermittent build failures on Chromium's ThinLTO bots on Windows. More
> details are in the associated Chromium bug (crbug.com/786127).
>
> We can prevent this from happening by keeping a handle to the file open while
> the mapping is active. So this patch changes the mapped_file_region class to
> duplicate the file handle when mapping the file and close it upon unmapping it.
>
> One gotcha is that the file handle that we keep open must not have been
> created with FILE_FLAG_DELETE_ON_CLOSE, as otherwise the operating system
> will prevent other processes from opening the file. We can achieve this
> by avoiding the use of FILE_FLAG_DELETE_ON_CLOSE altogether. Instead,
> we use SetFileInformationByHandle with FileDispositionInfo to manage the
> delete-on-close bit. This lets us remove the hack that we used to use to
> clear the delete-on-close bit on a file opened with FILE_FLAG_DELETE_ON_CLOSE.
>
> A downside of using SetFileInformationByHandle/FileDispositionInfo as
> opposed to FILE_FLAG_DELETE_ON_CLOSE is that it prevents us from using
> CreateFile to open the file while the flag is set, even within the same
> process. This doesn't seem to matter for almost every client of TempFile,
> except for LockFileManager, which calls sys::fs::create_link to create a
> hard link from the lock file, and in the process of doing so tries to open
> the file. To prevent this change from breaking LockFileManager I changed it
> to stop using TempFile by effectively reverting r318550.
>
> Differential Revision: https://reviews.llvm.org/D48051
>
> Modified:
> llvm/trunk/include/llvm/Support/FileSystem.h
> llvm/trunk/include/llvm/Support/LockFileManager.h
> llvm/trunk/lib/LTO/Caching.cpp
> llvm/trunk/lib/Support/LockFileManager.cpp
> llvm/trunk/lib/Support/Path.cpp
> llvm/trunk/lib/Support/Unix/Path.inc
> llvm/trunk/lib/Support/Windows/Path.inc
>
> Modified: llvm/trunk/include/llvm/Support/FileSystem.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileSystem.h?rev=334630&r1=334629&r2=334630&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/FileSystem.h (original)
> +++ llvm/trunk/include/llvm/Support/FileSystem.h Wed Jun 13 11:03:14 2018
> @@ -1043,7 +1043,9 @@ private:
> /// Platform-specific mapping state.
> size_t Size;
> void *Mapping;
> - int FD;
> +#ifdef _WIN32
> + void *FileHandle;
> +#endif
> mapmode Mode;
>
> std::error_code init(int FD, uint64_t Offset, mapmode Mode);
>
> Modified: llvm/trunk/include/llvm/Support/LockFileManager.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/LockFileManager.h?rev=334630&r1=334629&r2=334630&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/LockFileManager.h (original)
> +++ llvm/trunk/include/llvm/Support/LockFileManager.h Wed Jun 13 11:03:14 2018
> @@ -11,7 +11,6 @@
>
> #include "llvm/ADT/Optional.h"
> #include "llvm/ADT/SmallString.h"
> -#include "llvm/Support/FileSystem.h"
> #include <system_error>
> #include <utility> // for std::pair
>
> @@ -54,7 +53,7 @@ public:
> private:
> SmallString<128> FileName;
> SmallString<128> LockFileName;
> - Optional<sys::fs::TempFile> UniqueLockFile;
> + SmallString<128> UniqueLockFileName;
>
> Optional<std::pair<std::string, int> > Owner;
> std::error_code ErrorCode;
>
> Modified: llvm/trunk/lib/LTO/Caching.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/Caching.cpp?rev=334630&r1=334629&r2=334630&view=diff
> ==============================================================================
> --- llvm/trunk/lib/LTO/Caching.cpp (original)
> +++ llvm/trunk/lib/LTO/Caching.cpp Wed Jun 13 11:03:14 2018
> @@ -40,7 +40,14 @@ Expected<NativeObjectCache> lto::localCa
> return AddStreamFn();
> }
>
> - if (MBOrErr.getError() != errc::no_such_file_or_directory)
> + // On Windows we can fail to open a cache file with a permission denied
> + // error. This generally means that another process has requested to delete
> + // the file while it is still open, but it could also mean that another
> + // process has opened the file without the sharing permissions we need.
> + // Since the file is probably being deleted we handle it in the same way as
> + // if the file did not exist at all.
> + if (MBOrErr.getError() != errc::no_such_file_or_directory &&
> + MBOrErr.getError() != errc::permission_denied)
> report_fatal_error(Twine("Failed to open cache file ") + EntryPath +
> ": " + MBOrErr.getError().message() + "\n");
>
>
> Modified: llvm/trunk/lib/Support/LockFileManager.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/LockFileManager.cpp?rev=334630&r1=334629&r2=334630&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Support/LockFileManager.cpp (original)
> +++ llvm/trunk/lib/Support/LockFileManager.cpp Wed Jun 13 11:03:14 2018
> @@ -9,10 +9,8 @@
>
> #include "llvm/Support/LockFileManager.h"
> #include "llvm/ADT/None.h"
> -#include "llvm/ADT/ScopeExit.h"
> #include "llvm/ADT/SmallVector.h"
> #include "llvm/ADT/StringExtras.h"
> -#include "llvm/Config/llvm-config.h"
> #include "llvm/Support/Errc.h"
> #include "llvm/Support/ErrorOr.h"
> #include "llvm/Support/FileSystem.h"
> @@ -123,6 +121,39 @@ bool LockFileManager::processStillExecut
> return true;
> }
>
> +namespace {
> +
> +/// An RAII helper object ensure that the unique lock file is removed.
> +///
> +/// Ensures that if there is an error or a signal before we finish acquiring the
> +/// lock, the unique file will be removed. And if we successfully take the lock,
> +/// the signal handler is left in place so that signals while the lock is held
> +/// will remove the unique lock file. The caller should ensure there is a
> +/// matching call to sys::DontRemoveFileOnSignal when the lock is released.
> +class RemoveUniqueLockFileOnSignal {
> + StringRef Filename;
> + bool RemoveImmediately;
> +public:
> + RemoveUniqueLockFileOnSignal(StringRef Name)
> + : Filename(Name), RemoveImmediately(true) {
> + sys::RemoveFileOnSignal(Filename, nullptr);
> + }
> +
> + ~RemoveUniqueLockFileOnSignal() {
> + if (!RemoveImmediately) {
> + // Leave the signal handler enabled. It will be removed when the lock is
> + // released.
> + return;
> + }
> + sys::fs::remove(Filename);
> + sys::DontRemoveFileOnSignal(Filename);
> + }
> +
> + void lockAcquired() { RemoveImmediately = false; }
> +};
> +
> +} // end anonymous namespace
> +
> LockFileManager::LockFileManager(StringRef FileName)
> {
> this->FileName = FileName;
> @@ -141,22 +172,16 @@ LockFileManager::LockFileManager(StringR
> return;
>
> // Create a lock file that is unique to this instance.
> - Expected<sys::fs::TempFile> Temp =
> - sys::fs::TempFile::create(LockFileName + "-%%%%%%%%");
> - if (!Temp) {
> - std::error_code EC = errorToErrorCode(Temp.takeError());
> - std::string S("failed to create unique file with prefix ");
> - S.append(LockFileName.str());
> + UniqueLockFileName = LockFileName;
> + UniqueLockFileName += "-%%%%%%%%";
> + int UniqueLockFileID;
> + if (std::error_code EC = sys::fs::createUniqueFile(
> + UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) {
> + std::string S("failed to create unique file ");
> + S.append(UniqueLockFileName.str());
> setError(EC, S);
> return;
> }
> - UniqueLockFile = std::move(*Temp);
> -
> - // Make sure we discard the temporary file on exit.
> - auto RemoveTempFile = llvm::make_scope_exit([&]() {
> - if (Error E = UniqueLockFile->discard())
> - setError(errorToErrorCode(std::move(E)));
> - });
>
> // Write our process ID to our unique lock file.
> {
> @@ -166,46 +191,54 @@ LockFileManager::LockFileManager(StringR
> return;
> }
>
> - raw_fd_ostream Out(UniqueLockFile->FD, /*shouldClose=*/false);
> + raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
> Out << HostID << ' ';
> #if LLVM_ON_UNIX
> Out << getpid();
> #else
> Out << "1";
> #endif
> - Out.flush();
> + Out.close();
>
> if (Out.has_error()) {
> // We failed to write out PID, so report the error, remove the
> // unique lock file, and fail.
> std::string S("failed to write to ");
> - S.append(UniqueLockFile->TmpName);
> + S.append(UniqueLockFileName.str());
> setError(Out.error(), S);
> + sys::fs::remove(UniqueLockFileName);
> return;
> }
> }
>
> + // Clean up the unique file on signal, which also releases the lock if it is
> + // held since the .lock symlink will point to a nonexistent file.
> + RemoveUniqueLockFileOnSignal RemoveUniqueFile(UniqueLockFileName);
> +
> while (true) {
> // Create a link from the lock file name. If this succeeds, we're done.
> std::error_code EC =
> - sys::fs::create_link(UniqueLockFile->TmpName, LockFileName);
> + sys::fs::create_link(UniqueLockFileName, LockFileName);
> if (!EC) {
> - RemoveTempFile.release();
> + RemoveUniqueFile.lockAcquired();
> return;
> }
>
> if (EC != errc::file_exists) {
> std::string S("failed to create link ");
> raw_string_ostream OSS(S);
> - OSS << LockFileName.str() << " to " << UniqueLockFile->TmpName;
> + OSS << LockFileName.str() << " to " << UniqueLockFileName.str();
> setError(EC, OSS.str());
> return;
> }
>
> // Someone else managed to create the lock file first. Read the process ID
> // from the lock file.
> - if ((Owner = readLockFile(LockFileName)))
> - return; // RemoveTempFile will delete out our unique lock file.
> + if ((Owner = readLockFile(LockFileName))) {
> + // Wipe out our unique lock file (it's useless now)
> + sys::fs::remove(UniqueLockFileName);
> + return;
> + }
>
> if (!sys::fs::exists(LockFileName)) {
> // The previous owner released the lock file before we could read it.
> @@ -217,7 +250,7 @@ LockFileManager::LockFileManager(StringR
> // ownership.
> if ((EC = sys::fs::remove(LockFileName))) {
> std::string S("failed to remove lockfile ");
> - S.append(LockFileName.str());
> + S.append(UniqueLockFileName.str());
> setError(EC, S);
> return;
> }
> @@ -252,7 +285,10 @@ LockFileManager::~LockFileManager() {
>
> // Since we own the lock, remove the lock file and our own unique lock file.
> sys::fs::remove(LockFileName);
> - consumeError(UniqueLockFile->discard());
> + sys::fs::remove(UniqueLockFileName);
> + // The unique file is now gone, so remove it from the signal handler. This
> + // matches a sys::RemoveFileOnSignal() in LockFileManager().
> + sys::DontRemoveFileOnSignal(UniqueLockFileName);
> }
>
> LockFileManager::WaitForUnlockResult LockFileManager::waitForUnlock() {
>
> Modified: llvm/trunk/lib/Support/Path.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Path.cpp?rev=334630&r1=334629&r2=334630&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Support/Path.cpp (original)
> +++ llvm/trunk/lib/Support/Path.cpp Wed Jun 13 11:03:14 2018
> @@ -1129,12 +1129,13 @@ Error TempFile::keep(const Twine &Name)
> // Always try to close and rename.
> #ifdef _WIN32
> // If we cant't cancel the delete don't rename.
> - std::error_code RenameEC = cancelDeleteOnClose(FD);
> + auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
> + std::error_code RenameEC = setDeleteDisposition(H, false);
> if (!RenameEC)
> RenameEC = rename_fd(FD, Name);
> // If we can't rename, discard the temporary file.
> if (RenameEC)
> - removeFD(FD);
> + setDeleteDisposition(H, true);
> #else
> std::error_code RenameEC = fs::rename(TmpName, Name);
> // If we can't rename, discard the temporary file.
> @@ -1160,7 +1161,8 @@ Error TempFile::keep() {
> Done = true;
>
> #ifdef _WIN32
> - if (std::error_code EC = cancelDeleteOnClose(FD))
> + auto H = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
> + if (std::error_code EC = setDeleteDisposition(H, false))
> return errorCodeToError(EC);
> #else
> sys::DontRemoveFileOnSignal(TmpName);
>
> Modified: llvm/trunk/lib/Support/Unix/Path.inc
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Path.inc?rev=334630&r1=334629&r2=334630&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Support/Unix/Path.inc (original)
> +++ llvm/trunk/lib/Support/Unix/Path.inc Wed Jun 13 11:03:14 2018
> @@ -634,8 +634,7 @@ std::error_code mapped_file_region::init
>
> mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
> uint64_t offset, std::error_code &ec)
> - : Size(length), Mapping(), FD(fd), Mode(mode) {
> - (void)FD;
> + : Size(length), Mapping(), Mode(mode) {
> (void)Mode;
> ec = init(fd, offset, mode);
> if (ec)
>
> Modified: llvm/trunk/lib/Support/Windows/Path.inc
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Path.inc?rev=334630&r1=334629&r2=334630&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Support/Windows/Path.inc (original)
> +++ llvm/trunk/lib/Support/Windows/Path.inc Wed Jun 13 11:03:14 2018
> @@ -404,56 +404,6 @@ static std::error_code setDeleteDisposit
> return std::error_code();
> }
>
> -static std::error_code removeFD(int FD) {
> - HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
> - return setDeleteDisposition(Handle, true);
> -}
> -
> -/// In order to handle temporary files we want the following properties
> -///
> -/// * The temporary file is deleted on crashes
> -/// * We can use (read, rename, etc) the temporary file.
> -/// * We can cancel the delete to keep the file.
> -///
> -/// Using FILE_DISPOSITION_INFO with DeleteFile=true will create a file that is
> -/// deleted on close, but it has a few problems:
> -///
> -/// * The file cannot be used. An attempt to open or rename the file will fail.
> -/// This makes the temporary file almost useless, as it cannot be part of
> -/// any other CreateFileW call in the current or in another process.
> -/// * It is not atomic. A crash just after CreateFileW or just after canceling
> -/// the delete will leave the file on disk.
> -///
> -/// Using FILE_FLAG_DELETE_ON_CLOSE solves the first issues and the first part
> -/// of the second one, but there is no way to cancel it in place. What works is
> -/// to create a second handle to prevent the deletion, close the first one and
> -/// then clear DeleteFile with SetFileInformationByHandle. This requires
> -/// changing the handle and file descriptor the caller uses.
> -static std::error_code cancelDeleteOnClose(int &FD) {
> - HANDLE Handle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
> - SmallVector<wchar_t, MAX_PATH> Name;
> - if (std::error_code EC = realPathFromHandle(Handle, Name))
> - return EC;
> - HANDLE NewHandle =
> - ::CreateFileW(Name.data(), GENERIC_READ | GENERIC_WRITE | DELETE,
> - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
> - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
> - if (NewHandle == INVALID_HANDLE_VALUE)
> - return mapWindowsError(::GetLastError());
> - if (close(FD))
> - return mapWindowsError(::GetLastError());
> -
> - if (std::error_code EC = setDeleteDisposition(NewHandle, false))
> - return EC;
> -
> - FD = ::_open_osfhandle(intptr_t(NewHandle), 0);
> - if (FD == -1) {
> - ::CloseHandle(NewHandle);
> - return mapWindowsError(ERROR_INVALID_HANDLE);
> - }
> - return std::error_code();
> -}
> -
> static std::error_code rename_internal(HANDLE FromHandle, const Twine &To,
> bool ReplaceIfExists) {
> SmallVector<wchar_t, 0> ToWide;
> @@ -826,10 +776,9 @@ std::error_code setLastModificationAndAc
>
> std::error_code mapped_file_region::init(int FD, uint64_t Offset,
> mapmode Mode) {
> - this->FD = FD;
> this->Mode = Mode;
> - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
> - if (FileHandle == INVALID_HANDLE_VALUE)
> + HANDLE OrigFileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
> + if (OrigFileHandle == INVALID_HANDLE_VALUE)
> return make_error_code(errc::bad_file_descriptor);
>
> DWORD flprotect;
> @@ -840,7 +789,7 @@ std::error_code mapped_file_region::init
> }
>
> HANDLE FileMappingHandle =
> - ::CreateFileMappingW(FileHandle, 0, flprotect,
> + ::CreateFileMappingW(OrigFileHandle, 0, flprotect,
> Hi_32(Size),
> Lo_32(Size),
> 0);
> @@ -878,9 +827,20 @@ std::error_code mapped_file_region::init
> Size = mbi.RegionSize;
> }
>
> - // Close all the handles except for the view. It will keep the other handles
> - // alive.
> + // Close the file mapping handle, as it's kept alive by the file mapping. But
> + // neither the file mapping nor the file mapping handle keep the file handle
> + // alive, so we need to keep a reference to the file in case all other handles
> + // are closed and the file is deleted, which may cause invalid data to be read
> + // from the file.
> ::CloseHandle(FileMappingHandle);
> + if (!::DuplicateHandle(::GetCurrentProcess(), OrigFileHandle,
> + ::GetCurrentProcess(), &FileHandle, 0, 0,
> + DUPLICATE_SAME_ACCESS)) {
> + std::error_code ec = mapWindowsError(GetLastError());
> + ::UnmapViewOfFile(Mapping);
> + return ec;
> + }
> +
> return std::error_code();
> }
>
> @@ -902,10 +862,10 @@ mapped_file_region::~mapped_file_region(
> // flushed and subsequent process's attempts to read a file can return
> // invalid data. Calling FlushFileBuffers on the write handle is
> // sufficient to ensure that this bug is not triggered.
> - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
> - if (FileHandle != INVALID_HANDLE_VALUE)
> - ::FlushFileBuffers(FileHandle);
> + ::FlushFileBuffers(FileHandle);
> }
> +
> + ::CloseHandle(FileHandle);
> }
> }
>
> @@ -1056,16 +1016,6 @@ static std::error_code nativeFileToFd(Ex
> return std::error_code();
> }
>
> -static DWORD nativeOpenFlags(OpenFlags Flags) {
> - DWORD Result = 0;
> - if (Flags & OF_Delete)
> - Result |= FILE_FLAG_DELETE_ON_CLOSE;
> -
> - if (Result == 0)
> - Result = FILE_ATTRIBUTE_NORMAL;
> - return Result;
> -}
> -
> static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) {
> // This is a compatibility hack. Really we should respect the creation
> // disposition, but a lot of old code relied on the implicit assumption that
> @@ -1142,7 +1092,6 @@ Expected<file_t> openNativeFile(const Tw
> assert((!(Disp == CD_CreateNew) || !(Flags & OF_Append)) &&
> "Cannot specify both 'CreateNew' and 'Append' file creation flags!");
>
> - DWORD NativeFlags = nativeOpenFlags(Flags);
> DWORD NativeDisp = nativeDisposition(Disp, Flags);
> DWORD NativeAccess = nativeAccess(Access, Flags);
>
> @@ -1152,9 +1101,15 @@ Expected<file_t> openNativeFile(const Tw
>
> file_t Result;
> std::error_code EC = openNativeFileInternal(
> - Name, Result, NativeDisp, NativeAccess, NativeFlags, Inherit);
> + Name, Result, NativeDisp, NativeAccess, FILE_ATTRIBUTE_NORMAL, Inherit);
> if (EC)
> return errorCodeToError(EC);
> + if (Flags & OF_Delete) {
> + if ((EC = setDeleteDisposition(Result, true))) {
> + ::CloseHandle(Result);
> + return errorCodeToError(EC);
> + }
> + }
> return Result;
> }
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list