[llvm] r296887 - [Support] Provide access to current thread name/thread id.
Krzysztof Parzyszek via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 3 12:52:52 PST 2017
These are our local builds on SUSE 11.4 (glibc 2.11.3). The functions
are pthread_setname_np and pthread_getname_np.
It should be fine if the functions you added do nothing on that system,
as long as the code compiles.
If you don't have access to this kind of OS, I could come up with some
patch (test for these functions in cmake).
-Krzysztof
On 3/3/2017 2:42 PM, Zachary Turner wrote:
> Which function does it not provide specifically? Can you link me to a
> failing buildbot?
>
> On Fri, Mar 3, 2017 at 11:01 AM Krzysztof Parzyszek via llvm-commits
> <llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>> wrote:
>
> This thing fails to build on older Linuxes (e.g. SUSE).
> Glibc 2.11.3 does not provide this function.
>
> This breaks some of our builds.
>
> -Krzysztof
>
>
> On 3/3/2017 11:15 AM, Zachary Turner via llvm-commits wrote:
> > Author: zturner
> > Date: Fri Mar 3 11:15:17 2017
> > New Revision: 296887
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=296887&view=rev
> > Log:
> > [Support] Provide access to current thread name/thread id.
> >
> > Applications often need the current thread id when making
> > system calls, and some operating systems provide the notion
> > of a thread name, which can be useful in enabling better
> > diagnostics when debugging or logging.
> >
> > This patch adds an accessor for the thread id, and "best effort"
> > getters and setters for the thread name. Since this is
> > non critical functionality, no error is returned to indicate
> > that a platform doesn't support thread names.
> >
> > Differential Revision: https://reviews.llvm.org/D30526
> >
> > Added:
> > llvm/trunk/lib/Support/Unix/Threading.inc
> > llvm/trunk/lib/Support/Windows/Threading.inc
> > Modified:
> > llvm/trunk/include/llvm/Support/Threading.h
> > llvm/trunk/lib/Support/Threading.cpp
> >
> > Modified: llvm/trunk/include/llvm/Support/Threading.h
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Threading.h?rev=296887&r1=296886&r2=296887&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/include/llvm/Support/Threading.h (original)
> > +++ llvm/trunk/include/llvm/Support/Threading.h Fri Mar 3
> 11:15:17 2017
> > @@ -15,6 +15,7 @@
> > #ifndef LLVM_SUPPORT_THREADING_H
> > #define LLVM_SUPPORT_THREADING_H
> >
> > +#include "llvm/ADT/SmallVector.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.
> > @@ -42,24 +43,26 @@
> > #endif
> >
> > namespace llvm {
> > - /// Returns true if LLVM is compiled with support for
> multi-threading, and
> > - /// false otherwise.
> > - bool llvm_is_multithreaded();
> > -
> > - /// llvm_execute_on_thread - Execute the given \p UserFn on a
> separate
> > - /// thread, passing it the provided \p UserData and waits for
> thread
> > - /// completion.
> > - ///
> > - /// This function does not guarantee that the code will
> actually be executed
> > - /// on a separate thread or honoring the requested stack size,
> but tries to do
> > - /// so where system support is available.
> > - ///
> > - /// \param UserFn - The callback to execute.
> > - /// \param UserData - An argument to pass to the callback function.
> > - /// \param RequestedStackSize - If non-zero, a requested size
> (in bytes) for
> > - /// the thread stack.
> > - void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData,
> > - unsigned RequestedStackSize = 0);
> > +class Twine;
> > +
> > +/// Returns true if LLVM is compiled with support for
> multi-threading, and
> > +/// false otherwise.
> > +bool llvm_is_multithreaded();
> > +
> > +/// llvm_execute_on_thread - Execute the given \p UserFn on a
> separate
> > +/// thread, passing it the provided \p UserData and waits for thread
> > +/// completion.
> > +///
> > +/// This function does not guarantee that the code will actually
> be executed
> > +/// on a separate thread or honoring the requested stack size,
> but tries to do
> > +/// so where system support is available.
> > +///
> > +/// \param UserFn - The callback to execute.
> > +/// \param UserData - An argument to pass to the callback function.
> > +/// \param RequestedStackSize - If non-zero, a requested size (in
> bytes) for
> > +/// the thread stack.
> > +void llvm_execute_on_thread(void (*UserFn)(void *), void *UserData,
> > + unsigned RequestedStackSize = 0);
> >
> > #if LLVM_THREADING_USE_STD_CALL_ONCE
> >
> > @@ -127,6 +130,28 @@ namespace llvm {
> > /// thread::hardware_concurrency().
> > /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF
> > unsigned heavyweight_hardware_concurrency();
> > +
> > + /// \brief 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();
> > +
> > + /// \brief 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);
> > +
> > + /// \brief 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);
> > }
> >
> > #endif
> >
> > Modified: llvm/trunk/lib/Support/Threading.cpp
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Threading.cpp?rev=296887&r1=296886&r2=296887&view=diff
> >
> ==============================================================================
> > --- llvm/trunk/lib/Support/Threading.cpp (original)
> > +++ llvm/trunk/lib/Support/Threading.cpp Fri Mar 3 11:15:17 2017
> > @@ -14,14 +14,21 @@
> >
> > #include "llvm/Support/Threading.h"
> > #include "llvm/Config/config.h"
> > -#include "llvm/Support/Atomic.h"
> > #include "llvm/Support/Host.h"
> > -#include "llvm/Support/Mutex.h"
> > #include "llvm/Support/thread.h"
> > +
> > #include <cassert>
> > +#include <errno.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> >
> > using namespace llvm;
> >
> >
> +//===----------------------------------------------------------------------===//
> > +//=== WARNING: Implementation here must contain only TRULY
> operating system
> > +//=== independent code.
> >
> +//===----------------------------------------------------------------------===//
> > +
> > bool llvm::llvm_is_multithreaded() {
> > #if LLVM_ENABLE_THREADS != 0
> > return true;
> > @@ -30,100 +37,38 @@ bool llvm::llvm_is_multithreaded() {
> > #endif
> > }
> >
> > -#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H)
> > -#include <pthread.h>
> > -
> > -struct ThreadInfo {
> > - void (*UserFn)(void *);
> > - void *UserData;
> > -};
> > -static void *ExecuteOnThread_Dispatch(void *Arg) {
> > - ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg);
> > - TI->UserFn(TI->UserData);
> > - return nullptr;
> > -}
> > -
> > -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData,
> > +#if LLVM_ENABLE_THREADS == 0 ||
> \
> > + (!defined(LLVM_ON_WIN32) && !defined(HAVE_PTHREAD_H))
> > +// Support for non-Win32, non-pthread implementation.
> > +void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData,
> > unsigned RequestedStackSize) {
> > - ThreadInfo Info = { Fn, UserData };
> > - pthread_attr_t Attr;
> > - pthread_t Thread;
> > -
> > - // Construct the attributes object.
> > - if (::pthread_attr_init(&Attr) != 0)
> > - return;
> > -
> > - // Set the requested stack size, if given.
> > - if (RequestedStackSize != 0) {
> > - if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0)
> > - goto error;
> > - }
> > -
> > - // Construct and execute the thread.
> > - if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch,
> &Info) != 0)
> > - goto error;
> > -
> > - // Wait for the thread and clean up.
> > - ::pthread_join(Thread, nullptr);
> > -
> > - error:
> > - ::pthread_attr_destroy(&Attr);
> > + (void)RequestedStackSize;
> > + Fn(UserData);
> > }
> > -#elif LLVM_ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32)
> > -#include "Windows/WindowsSupport.h"
> > -#include <process.h>
> > -
> > -// Windows will at times define MemoryFence.
> > -#ifdef MemoryFence
> > -#undef MemoryFence
> > -#endif
> >
> > -struct ThreadInfo {
> > - void (*func)(void*);
> > - void *param;
> > -};
> > -
> > -static unsigned __stdcall ThreadCallback(void *param) {
> > - struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo
> *>(param);
> > - info->func(info->param);
> > +unsigned llvm::heavyweight_hardware_concurrency() { return 1; }
> >
> > - return 0;
> > -}
> > +uint64_t llvm::get_threadid_np() { return 0; }
> >
> > -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData,
> > - unsigned RequestedStackSize) {
> > - struct ThreadInfo param = { Fn, UserData };
> > +void llvm::set_thread_name(const Twine &Name) {}
> >
> > - HANDLE hThread = (HANDLE)::_beginthreadex(NULL,
> > - RequestedStackSize,
> ThreadCallback,
> > - ¶m, 0, NULL);
> > -
> > - if (hThread) {
> > - // We actually don't care whether the wait succeeds or fails, in
> > - // the same way we don't care whether the pthread_join call
> succeeds
> > - // or fails. There's not much we could do if this were to
> fail. But
> > - // on success, this call will wait until the thread finishes
> executing
> > - // before returning.
> > - (void)::WaitForSingleObject(hThread, INFINITE);
> > - ::CloseHandle(hThread);
> > - }
> > -}
> > -#else
> > -// Support for non-Win32, non-pthread implementation.
> > -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData,
> > - unsigned RequestedStackSize) {
> > - (void) RequestedStackSize;
> > - Fn(UserData);
> > -}
> > +void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
> Name.clear(); }
> >
> > -#endif
> > +#else
> >
> > unsigned llvm::heavyweight_hardware_concurrency() {
> > -#if !LLVM_ENABLE_THREADS
> > - return 1;
> > -#endif
> > int NumPhysical = sys::getHostNumPhysicalCores();
> > if (NumPhysical == -1)
> > return thread::hardware_concurrency();
> > return NumPhysical;
> > }
> > +
> > +// Include the platform-specific parts of this class.
> > +#ifdef LLVM_ON_UNIX
> > +#include "Unix/Threading.inc"
> > +#endif
> > +#ifdef LLVM_ON_WIN32
> > +#include "Windows/Threading.inc"
> > +#endif
> > +
> > +#endif
> >
> > Added: llvm/trunk/lib/Support/Unix/Threading.inc
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Threading.inc?rev=296887&view=auto
> >
> ==============================================================================
> > --- llvm/trunk/lib/Support/Unix/Threading.inc (added)
> > +++ llvm/trunk/lib/Support/Unix/Threading.inc Fri Mar 3 11:15:17 2017
> > @@ -0,0 +1,181 @@
> > +//===- Unix/Threading.inc - Unix Threading Implementation -----
> -*- C++ -*-===//
> > +//
> > +// The LLVM Compiler Infrastructure
> > +//
> > +// This file is distributed under the University of Illinois Open
> Source
> > +// License. See LICENSE.TXT for details.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +//
> > +// This file provides the Unix specific implementation of
> Threading functions.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +
> > +#include "llvm/ADT/SmallString.h"
> > +#include "llvm/ADT/Twine.h"
> > +
> > +#if defined(__APPLE__)
> > +#include <mach/mach_init.h>
> > +#include <mach/mach_port.h>
> > +#endif
> > +
> > +#include <pthread.h>
> > +
> > +#if defined(__FreeBSD__)
> > +#include <pthread_np.h>
> > +#endif
> > +
> > +#if defined(__NetBSD__)
> > +#include <lwp.h>
> > +#endif
> > +
> > +#if defined(__linux__)
> > +#include <sys/syscall.h>
> > +#endif
> > +
> > +#if defined(__NetBSD__) || defined(__FreeBSD__) ||
> defined(__FreeBSD_kernel__)
> > +#include <sys/sysctl.h>
> > +#include <sys/user.h>
> > +#endif
> > +
> > +namespace {
> > + struct ThreadInfo {
> > + void(*UserFn)(void *);
> > + void *UserData;
> > + };
> > +}
> > +
> > +static void *ExecuteOnThread_Dispatch(void *Arg) {
> > + ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg);
> > + TI->UserFn(TI->UserData);
> > + return nullptr;
> > +}
> > +
> > +void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData,
> > + unsigned RequestedStackSize) {
> > + ThreadInfo Info = { Fn, UserData };
> > + pthread_attr_t Attr;
> > + pthread_t Thread;
> > +
> > + // Construct the attributes object.
> > + if (::pthread_attr_init(&Attr) != 0)
> > + return;
> > +
> > + // Set the requested stack size, if given.
> > + if (RequestedStackSize != 0) {
> > + if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0)
> > + goto error;
> > + }
> > +
> > + // Construct and execute the thread.
> > + if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch,
> &Info) != 0)
> > + goto error;
> > +
> > + // Wait for the thread and clean up.
> > + ::pthread_join(Thread, nullptr);
> > +
> > +error:
> > + ::pthread_attr_destroy(&Attr);
> > +}
> > +
> > +
> > +uint64_t llvm::get_threadid() {
> > +#if defined(__APPLE__)
> > + // Calling "mach_thread_self()" bumps the reference count on
> the thread
> > + // port, so we need to deallocate it. mach_task_self() doesn't
> bump the ref
> > + // count.
> > + thread_port_t Self = mach_thread_self();
> > + mach_port_deallocate(mach_task_self(), Self);
> > + return Self;
> > +#elif defined(__FreeBSD__)
> > + return uint64_t(pthread_getthreadid_np());
> > +#elif defined(__NetBSD__)
> > + return uint64_t(_lwp_self());
> > +#elif defined(__ANDROID__)
> > + return uint64_t(gettid());
> > +#elif defined(__linux__)
> > + return uint64_t(syscall(SYS_gettid));
> > +#elif defined(LLVM_ON_WIN32)
> > + return uint64_t(::GetCurrentThreadId());
> > +#else
> > + return uint64_t(pthread_self());
> > +#endif
> > +}
> > +
> > +
> > +void llvm::set_thread_name(const Twine &Name) {
> > + // Make sure the input is null terminated.
> > + SmallString<64> Storage;
> > + StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
> > +#if defined(__linux__)
> > +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) ||
> defined(__ANDROID__)
> > + ::pthread_setname_np(::pthread_self(), NameStr.data());
> > +#endif
> > +#elif defined(__FreeBSD__)
> > + ::pthread_set_name_np(::pthread_self(), NameStr.data());
> > +#elif defined(__NetBSD__)
> > + ::pthread_setname_np(::pthread_self(), "%s",
> > + const_cast<char *>(NameStr.data()));
> > +#elif defined(__APPLE__)
> > + ::pthread_setname_np(NameStr.data());
> > +#endif
> > +}
> > +
> > +void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
> > + Name.clear();
> > +
> > +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
> > +#if defined(__FreeBSD_kernel__)
> > + int pid = ::pthread_self();
> > +#else
> > + int pid = ::getpid();
> > +#endif
> > +
> > + int tid = ::pthread_getthreadid_np();
> > +
> > + struct kinfo_proc *kp = nullptr, *nkp;
> > + size_t len = 0;
> > + int error;
> > + int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID |
> KERN_PROC_INC_THREAD,
> > + (int)pid };
> > +
> > + while (1) {
> > + error = sysctl(ctl, 4, kp, &len, nullptr, 0);
> > + if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
> > + // Add extra space in case threads are added before next call.
> > + len += sizeof(*kp) + len / 10;
> > + nkp = (struct kinfo_proc *)realloc(kp, len);
> > + if (nkp == nullptr) {
> > + free(kp);
> > + return;
> > + }
> > + kp = nkp;
> > + continue;
> > + }
> > + if (error != 0)
> > + len = 0;
> > + break;
> > + }
> > +
> > + for (size_t i = 0; i < len / sizeof(*kp); i++) {
> > + if (kp[i].ki_tid == (lwpid_t)tid) {
> > + Name.append(kp[i].ki_tdname, kp[i].ki_tdname +
> strlen(kp[i].ki_tdname));
> > + break;
> > + }
> > + }
> > + free(kp);
> > + return;
> > +#elif defined(__NetBSD__)
> > + char buf[PTHREAD_MAX_NAMELEN_NP];
> > + ::pthread_getname_np(::pthread_self(), buf,
> PTHREAD_MAX_NAMELEN_NP);
> > +
> > + Name.append(buf, buf + strlen(buf));
> > +#elif defined(__linux__)
> > +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) ||
> defined(__ANDROID__)
> > + constexpr int MAXNAMELEN = 16;
> > + char Buffer[MAXNAMELEN];
> > + if (0 == ::pthread_getname_np(::pthread_self(), Buffer,
> MAXNAMELEN))
> > + Name.append(Buffer, Buffer + strlen(Buffer));
> > +#endif
> > +#endif
> > +}
> >
> > Added: llvm/trunk/lib/Support/Windows/Threading.inc
> > URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Threading.inc?rev=296887&view=auto
> >
> ==============================================================================
> > --- llvm/trunk/lib/Support/Windows/Threading.inc (added)
> > +++ llvm/trunk/lib/Support/Windows/Threading.inc Fri Mar 3
> 11:15:17 2017
> > @@ -0,0 +1,101 @@
> > +//===- 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.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +//
> > +// This file provides the Win32 specific implementation of
> Threading functions.
> > +//
> >
> +//===----------------------------------------------------------------------===//
> > +
> > +#include "llvm/ADT/SmallString.h"
> > +#include "llvm/ADT/Twine.h"
> > +
> > +#include "Windows/WindowsSupport.h"
> > +#include <process.h>
> > +
> > +// Windows will at times define MemoryFence.
> > +#ifdef MemoryFence
> > +#undef MemoryFence
> > +#endif
> > +
> > +namespace {
> > + struct ThreadInfo {
> > + void(*func)(void*);
> > + void *param;
> > + };
> > +}
> > +
> > +static unsigned __stdcall ThreadCallback(void *param) {
> > + struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo
> *>(param);
> > + info->func(info->param);
> > +
> > + return 0;
> > +}
> > +
> > +void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData,
> > + unsigned RequestedStackSize) {
> > + struct ThreadInfo param = { Fn, UserData };
> > +
> > + HANDLE hThread = (HANDLE)::_beginthreadex(NULL,
> > + RequestedStackSize, ThreadCallback,
> > + ¶m, 0, NULL);
> > +
> > + if (hThread) {
> > + // We actually don't care whether the wait succeeds or fails, in
> > + // the same way we don't care whether the pthread_join call
> succeeds
> > + // or fails. There's not much we could do if this were to
> fail. But
> > + // on success, this call will wait until the thread finishes
> executing
> > + // before returning.
> > + (void)::WaitForSingleObject(hThread, INFINITE);
> > + ::CloseHandle(hThread);
> > + }
> > +}
> > +
> > +uint64_t llvm::get_threadid() {
> > + return uint64_t(::GetCurrentThreadId());
> > +}
> > +
> > +void llvm::set_thread_name(const Twine &Name) {
> > +#if defined(_MSC_VER)
> > + // Make sure the input is null terminated.
> > + SmallString<64> Storage;
> > + StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
> > + constexpr DWORD MS_VC_EXCEPTION = 0x406D1388;
> > +
> > +#pragma pack(push, 8)
> > + struct THREADNAME_INFO {
> > + DWORD dwType; // Must be 0x1000.
> > + LPCSTR szName; // Pointer to thread name
> > + DWORD dwThreadId; // Thread ID (-1 == current thread)
> > + DWORD dwFlags; // Reserved. Do not use.
> > + };
> > +#pragma pack(pop)
> > +
> > + THREADNAME_INFO info;
> > + info.dwType = 0x1000;
> > + info.szName = NameStr.data();
> > + info.dwThreadId = ::GetCurrentThreadId();
> > + info.dwFlags = 0;
> > +
> > + __try {
> > + ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) /
> sizeof(ULONG_PTR),
> > + (ULONG_PTR *)&info);
> > + }
> > + __except (EXCEPTION_EXECUTE_HANDLER) {
> > + }
> > +#endif
> > +}
> > +
> > +void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
> > + // "Name" is not an inherent property of a thread on Windows.
> In fact, when
> > + // you "set" the name, you are only firing a one-time message
> to a debugger
> > + // which it interprets as a program setting its threads' name.
> We may be
> > + // able to get fancy by creating a TLS entry when someone calls
> > + // set_thread_name so that subsequent calls to get_thread_name
> return this
> > + // value.
> > + Name.clear();
> > +}
> >
> >
> > _______________________________________________
> > llvm-commits mailing list
> > llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
> >
>
> --
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
> hosted by The Linux Foundation
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
More information about the llvm-commits
mailing list