Merge llvm, clang, lld, lldb, compiler-rt and libc++ r306956, and update
build glue.
This commit is contained in:
commit
a580b01494
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/clang500-import/; revision=320572
@ -160,7 +160,11 @@ struct QuarantineCallback {
|
||||
}
|
||||
|
||||
void *Allocate(uptr size) {
|
||||
return get_allocator().Allocate(cache_, size, 1);
|
||||
void *res = get_allocator().Allocate(cache_, size, 1);
|
||||
// TODO(alekseys): Consider making quarantine OOM-friendly.
|
||||
if (UNLIKELY(!res))
|
||||
return DieOnFailure::OnOOM();
|
||||
return res;
|
||||
}
|
||||
|
||||
void Deallocate(void *p) {
|
||||
@ -524,8 +528,7 @@ struct Allocator {
|
||||
|
||||
// Expects the chunk to already be marked as quarantined by using
|
||||
// AtomicallySetQuarantineFlagIfAllocated.
|
||||
void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
|
||||
AllocType alloc_type) {
|
||||
void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) {
|
||||
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
|
||||
CHECK_GE(m->alloc_tid, 0);
|
||||
if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
|
||||
@ -603,7 +606,7 @@ struct Allocator {
|
||||
ReportNewDeleteSizeMismatch(p, delete_size, stack);
|
||||
}
|
||||
|
||||
QuarantineChunk(m, ptr, stack, alloc_type);
|
||||
QuarantineChunk(m, ptr, stack);
|
||||
}
|
||||
|
||||
void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) {
|
||||
@ -632,7 +635,7 @@ struct Allocator {
|
||||
}
|
||||
|
||||
void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
|
||||
if (CallocShouldReturnNullDueToOverflow(size, nmemb))
|
||||
if (CheckForCallocOverflow(size, nmemb))
|
||||
return AsanAllocator::FailureHandler::OnBadRequest();
|
||||
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
|
||||
// If the memory comes from the secondary allocator no need to clear it
|
||||
|
@ -579,17 +579,6 @@ INTERCEPTOR(char*, __strdup, const char *s) {
|
||||
}
|
||||
#endif // ASAN_INTERCEPT___STRDUP
|
||||
|
||||
INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
|
||||
SIZE_T length = internal_wcslen(s);
|
||||
if (!asan_init_is_running) {
|
||||
ENSURE_ASAN_INITED();
|
||||
ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
|
||||
void *ctx;
|
||||
ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
|
||||
@ -722,7 +711,6 @@ void InitializeAsanInterceptors() {
|
||||
// Intercept str* functions.
|
||||
ASAN_INTERCEPT_FUNC(strcat); // NOLINT
|
||||
ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
|
||||
ASAN_INTERCEPT_FUNC(wcslen);
|
||||
ASAN_INTERCEPT_FUNC(strncat);
|
||||
ASAN_INTERCEPT_FUNC(strncpy);
|
||||
ASAN_INTERCEPT_FUNC(strdup);
|
||||
|
@ -25,22 +25,26 @@
|
||||
// dllexport would normally do. We need to export them in order to make the
|
||||
// VS2015 dynamic CRT (MD) work.
|
||||
#if SANITIZER_WINDOWS
|
||||
# define CXX_OPERATOR_ATTRIBUTE
|
||||
# ifdef _WIN64
|
||||
# pragma comment(linker, "/export:??2@YAPEAX_K@Z") // operator new
|
||||
# pragma comment(linker, "/export:??3@YAXPEAX@Z") // operator delete
|
||||
# pragma comment(linker, "/export:??3@YAXPEAX_K@Z") // sized operator delete
|
||||
# pragma comment(linker, "/export:??_U@YAPEAX_K@Z") // operator new[]
|
||||
# pragma comment(linker, "/export:??_V@YAXPEAX@Z") // operator delete[]
|
||||
# else
|
||||
# pragma comment(linker, "/export:??2@YAPAXI@Z") // operator new
|
||||
# pragma comment(linker, "/export:??3@YAXPAX@Z") // operator delete
|
||||
# pragma comment(linker, "/export:??3@YAXPAXI@Z") // sized operator delete
|
||||
# pragma comment(linker, "/export:??_U@YAPAXI@Z") // operator new[]
|
||||
# pragma comment(linker, "/export:??_V@YAXPAX@Z") // operator delete[]
|
||||
# endif
|
||||
#define CXX_OPERATOR_ATTRIBUTE
|
||||
#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:"##sym))
|
||||
#ifdef _WIN64
|
||||
COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new
|
||||
COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow
|
||||
COMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete
|
||||
COMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete
|
||||
COMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[]
|
||||
COMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[]
|
||||
#else
|
||||
# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
|
||||
COMMENT_EXPORT("??2@YAPAXI@Z") // operator new
|
||||
COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow
|
||||
COMMENT_EXPORT("??3@YAXPAX@Z") // operator delete
|
||||
COMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete
|
||||
COMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[]
|
||||
COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]
|
||||
#endif
|
||||
#undef COMMENT_EXPORT
|
||||
#else
|
||||
#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
using namespace __asan; // NOLINT
|
||||
@ -63,12 +67,17 @@ struct nothrow_t {};
|
||||
enum class align_val_t: size_t {};
|
||||
} // namespace std
|
||||
|
||||
#define OPERATOR_NEW_BODY(type) \
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(type, nothrow) \
|
||||
GET_STACK_TRACE_MALLOC;\
|
||||
return asan_memalign(0, size, &stack, type);
|
||||
#define OPERATOR_NEW_BODY_ALIGN(type) \
|
||||
void *res = asan_memalign(0, size, &stack, type);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
return res;
|
||||
#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \
|
||||
GET_STACK_TRACE_MALLOC;\
|
||||
return asan_memalign((uptr)align, size, &stack, type);
|
||||
void *res = asan_memalign((uptr)align, size, &stack, type);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
return res;
|
||||
|
||||
// On OS X it's not enough to just provide our own 'operator new' and
|
||||
// 'operator delete' implementations, because they're going to be in the
|
||||
@ -79,40 +88,42 @@ enum class align_val_t: size_t {};
|
||||
// OS X we need to intercept them using their mangled names.
|
||||
#if !SANITIZER_MAC
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
|
||||
void *operator new(size_t size)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
|
||||
void *operator new[](size_t size)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW); }
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
|
||||
{ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::align_val_t align)
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); }
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::align_val_t align)
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); }
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); }
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); }
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); }
|
||||
{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); }
|
||||
|
||||
#else // SANITIZER_MAC
|
||||
INTERCEPTOR(void *, _Znwm, size_t size) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW);
|
||||
OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR(void *, _Znam, size_t size) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR);
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW);
|
||||
OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR);
|
||||
OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -85,6 +85,7 @@ INTERCEPT_LIBRARY_FUNCTION(strstr);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strtok);
|
||||
INTERCEPT_LIBRARY_FUNCTION(strtol);
|
||||
INTERCEPT_LIBRARY_FUNCTION(wcslen);
|
||||
INTERCEPT_LIBRARY_FUNCTION(wcsnlen);
|
||||
|
||||
#ifdef _WIN64
|
||||
INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler);
|
||||
|
@ -74,7 +74,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
|
||||
size = 1;
|
||||
if (size > kMaxAllowedMallocSize) {
|
||||
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
|
||||
return nullptr;
|
||||
return Allocator::FailureHandler::OnBadRequest();
|
||||
}
|
||||
void *p = allocator.Allocate(GetAllocatorCache(), size, alignment);
|
||||
// Do not rely on the allocator to clear the memory (it's slow).
|
||||
@ -99,7 +99,7 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
|
||||
if (new_size > kMaxAllowedMallocSize) {
|
||||
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
|
||||
allocator.Deallocate(GetAllocatorCache(), p);
|
||||
return nullptr;
|
||||
return Allocator::FailureHandler::OnBadRequest();
|
||||
}
|
||||
p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
|
||||
RegisterAllocation(stack, p, new_size);
|
||||
@ -134,6 +134,8 @@ void *lsan_realloc(void *p, uptr size, const StackTrace &stack) {
|
||||
}
|
||||
|
||||
void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) {
|
||||
if (CheckForCallocOverflow(size, nmemb))
|
||||
return Allocator::FailureHandler::OnBadRequest();
|
||||
size *= nmemb;
|
||||
return Allocate(stack, size, 1, true);
|
||||
}
|
||||
|
@ -70,7 +70,6 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
|
||||
CHECK(allocated < kCallocPoolSize);
|
||||
return mem;
|
||||
}
|
||||
if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr;
|
||||
ENSURE_LSAN_INITED;
|
||||
GET_STACK_TRACE_MALLOC;
|
||||
return lsan_calloc(nmemb, size, stack);
|
||||
@ -199,24 +198,38 @@ INTERCEPTOR(int, mprobe, void *ptr) {
|
||||
}
|
||||
#endif // SANITIZER_INTERCEPT_MCHECK_MPROBE
|
||||
|
||||
#define OPERATOR_NEW_BODY \
|
||||
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(nothrow) \
|
||||
ENSURE_LSAN_INITED; \
|
||||
GET_STACK_TRACE_MALLOC; \
|
||||
return Allocate(stack, size, 1, kAlwaysClearMemory);
|
||||
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *res = Allocate(stack, size, 1, kAlwaysClearMemory);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
return res;
|
||||
|
||||
#define OPERATOR_DELETE_BODY \
|
||||
ENSURE_LSAN_INITED; \
|
||||
Deallocate(ptr);
|
||||
|
||||
// On OS X it's not enough to just provide our own 'operator new' and
|
||||
// 'operator delete' implementations, because they're going to be in the runtime
|
||||
// dylib, and the main executable will depend on both the runtime dylib and
|
||||
// libstdc++, each of has its implementation of new and delete.
|
||||
// To make sure that C++ allocation/deallocation operators are overridden on
|
||||
// OS X we need to intercept them using their mangled names.
|
||||
#if !SANITIZER_MAC
|
||||
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(true /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(true /*nothrow*/); }
|
||||
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
@ -224,9 +237,31 @@ void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void operator delete[](void *ptr, std::nothrow_t const &) {
|
||||
OPERATOR_DELETE_BODY;
|
||||
}
|
||||
void operator delete[](void *ptr, std::nothrow_t const &)
|
||||
{ OPERATOR_DELETE_BODY; }
|
||||
|
||||
#else // SANITIZER_MAC
|
||||
|
||||
INTERCEPTOR(void *, _Znwm, size_t size)
|
||||
{ OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR(void *, _Znam, size_t size)
|
||||
{ OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(true /*nothrow*/); }
|
||||
INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)
|
||||
{ OPERATOR_NEW_BODY(true /*nothrow*/); }
|
||||
|
||||
INTERCEPTOR(void, _ZdlPv, void *ptr)
|
||||
{ OPERATOR_DELETE_BODY; }
|
||||
INTERCEPTOR(void, _ZdaPv, void *ptr)
|
||||
{ OPERATOR_DELETE_BODY; }
|
||||
INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY; }
|
||||
INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
|
||||
{ OPERATOR_DELETE_BODY; }
|
||||
|
||||
#endif // !SANITIZER_MAC
|
||||
|
||||
|
||||
///// Thread initialization and finalization. /////
|
||||
|
||||
|
@ -195,7 +195,7 @@ void MsanDeallocate(StackTrace *stack, void *p) {
|
||||
}
|
||||
|
||||
void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
|
||||
if (CallocShouldReturnNullDueToOverflow(size, nmemb))
|
||||
if (CheckForCallocOverflow(size, nmemb))
|
||||
return Allocator::FailureHandler::OnBadRequest();
|
||||
return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true);
|
||||
}
|
||||
|
@ -538,49 +538,6 @@ INTERCEPTOR(int, mbrtowc, wchar_t *dest, const char *src, SIZE_T n, void *ps) {
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
|
||||
ENSURE_MSAN_INITED();
|
||||
SIZE_T res = REAL(wcslen)(s);
|
||||
CHECK_UNPOISONED(s, sizeof(wchar_t) * (res + 1));
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) {
|
||||
ENSURE_MSAN_INITED();
|
||||
SIZE_T res = REAL(wcsnlen)(s, n);
|
||||
CHECK_UNPOISONED(s, sizeof(wchar_t) * Min(res + 1, n));
|
||||
return res;
|
||||
}
|
||||
|
||||
// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
|
||||
INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
|
||||
ENSURE_MSAN_INITED();
|
||||
wchar_t *res = REAL(wcschr)(s, wc, ps);
|
||||
return res;
|
||||
}
|
||||
|
||||
// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
|
||||
INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
|
||||
ENSURE_MSAN_INITED();
|
||||
GET_STORE_STACK_TRACE;
|
||||
wchar_t *res = REAL(wcscpy)(dest, src);
|
||||
CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1),
|
||||
&stack);
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src,
|
||||
SIZE_T n) { // NOLINT
|
||||
ENSURE_MSAN_INITED();
|
||||
GET_STORE_STACK_TRACE;
|
||||
SIZE_T copy_size = REAL(wcsnlen)(src, n);
|
||||
if (copy_size < n) copy_size++; // trailing \0
|
||||
wchar_t *res = REAL(wcsncpy)(dest, src, n); // NOLINT
|
||||
CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack);
|
||||
__msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t));
|
||||
return res;
|
||||
}
|
||||
|
||||
// wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, SIZE_T n);
|
||||
INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dest, const wchar_t *src, SIZE_T n) {
|
||||
ENSURE_MSAN_INITED();
|
||||
@ -1424,6 +1381,35 @@ INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// wchar_t *wcschr(const wchar_t *wcs, wchar_t wc);
|
||||
INTERCEPTOR(wchar_t *, wcschr, void *s, wchar_t wc, void *ps) {
|
||||
ENSURE_MSAN_INITED();
|
||||
wchar_t *res = REAL(wcschr)(s, wc, ps);
|
||||
return res;
|
||||
}
|
||||
|
||||
// wchar_t *wcscpy(wchar_t *dest, const wchar_t *src);
|
||||
INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dest, const wchar_t *src) {
|
||||
ENSURE_MSAN_INITED();
|
||||
GET_STORE_STACK_TRACE;
|
||||
wchar_t *res = REAL(wcscpy)(dest, src);
|
||||
CopyShadowAndOrigin(dest, src, sizeof(wchar_t) * (REAL(wcslen)(src) + 1),
|
||||
&stack);
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(wchar_t *, wcsncpy, wchar_t *dest, const wchar_t *src,
|
||||
SIZE_T n) { // NOLINT
|
||||
ENSURE_MSAN_INITED();
|
||||
GET_STORE_STACK_TRACE;
|
||||
SIZE_T copy_size = REAL(wcsnlen)(src, n);
|
||||
if (copy_size < n) copy_size++; // trailing \0
|
||||
wchar_t *res = REAL(wcsncpy)(dest, src, n); // NOLINT
|
||||
CopyShadowAndOrigin(dest, src, copy_size * sizeof(wchar_t), &stack);
|
||||
__msan_unpoison(dest + copy_size, (n - copy_size) * sizeof(wchar_t));
|
||||
return res;
|
||||
}
|
||||
|
||||
// These interface functions reside here so that they can use
|
||||
// REAL(memset), etc.
|
||||
void __msan_unpoison(const void *a, uptr size) {
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "msan.h"
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
|
||||
#if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
|
||||
|
||||
@ -27,18 +28,25 @@ namespace std {
|
||||
} // namespace std
|
||||
|
||||
|
||||
#define OPERATOR_NEW_BODY \
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(nothrow) \
|
||||
GET_MALLOC_STACK_TRACE; \
|
||||
return MsanReallocate(&stack, 0, size, sizeof(u64), false)
|
||||
void *res = MsanReallocate(&stack, 0, size, sizeof(u64), false);\
|
||||
if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
|
||||
return res
|
||||
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *operator new(size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(true /*nothrow*/);
|
||||
}
|
||||
INTERCEPTOR_ATTRIBUTE
|
||||
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
|
||||
void *operator new[](size_t size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(true /*nothrow*/);
|
||||
}
|
||||
|
||||
#define OPERATOR_DELETE_BODY \
|
||||
GET_MALLOC_STACK_TRACE; \
|
||||
|
@ -19,8 +19,6 @@
|
||||
|
||||
COMPILER_RT_WEAK uint64_t INSTR_PROF_RAW_VERSION_VAR = INSTR_PROF_RAW_VERSION;
|
||||
|
||||
COMPILER_RT_WEAK char INSTR_PROF_PROFILE_NAME_VAR[1] = {0};
|
||||
|
||||
COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) {
|
||||
return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64)
|
||||
: (INSTR_PROF_RAW_MAGIC_32);
|
||||
|
@ -45,15 +45,24 @@ uint64_t __llvm_profile_get_size_for_buffer_internal(
|
||||
(CountersEnd - CountersBegin) * sizeof(uint64_t) + NamesSize + Padding;
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY
|
||||
void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer) {
|
||||
BufferWriter->Write = lprofBufferWriter;
|
||||
BufferWriter->WriterCtx = Buffer;
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) {
|
||||
return lprofWriteData(lprofBufferWriter, Buffer, 0);
|
||||
ProfDataWriter BufferWriter;
|
||||
initBufferWriter(&BufferWriter, Buffer);
|
||||
return lprofWriteData(&BufferWriter, 0, 0);
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
|
||||
char *Buffer, const __llvm_profile_data *DataBegin,
|
||||
const __llvm_profile_data *DataEnd, const uint64_t *CountersBegin,
|
||||
const uint64_t *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
|
||||
return lprofWriteDataImpl(lprofBufferWriter, Buffer, DataBegin, DataEnd,
|
||||
CountersBegin, CountersEnd, 0, NamesBegin,
|
||||
NamesEnd);
|
||||
ProfDataWriter BufferWriter;
|
||||
initBufferWriter(&BufferWriter, Buffer);
|
||||
return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin,
|
||||
CountersEnd, 0, NamesBegin, NamesEnd, 0);
|
||||
}
|
||||
|
@ -91,24 +91,39 @@ static const char *getCurFilename(char *FilenameBuf);
|
||||
static unsigned doMerging() { return lprofCurFilename.MergePoolSize; }
|
||||
|
||||
/* Return 1 if there is an error, otherwise return 0. */
|
||||
static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
|
||||
void **WriterCtx) {
|
||||
static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
|
||||
uint32_t NumIOVecs) {
|
||||
uint32_t I;
|
||||
FILE *File = (FILE *)*WriterCtx;
|
||||
FILE *File = (FILE *)This->WriterCtx;
|
||||
for (I = 0; I < NumIOVecs; I++) {
|
||||
if (IOVecs[I].Data) {
|
||||
if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
|
||||
IOVecs[I].NumElm)
|
||||
return 1;
|
||||
} else {
|
||||
if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void initFileWriter(ProfDataWriter *This, FILE *File) {
|
||||
This->Write = fileWriter;
|
||||
This->WriterCtx = File;
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY ProfBufferIO *
|
||||
lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
|
||||
FreeHook = &free;
|
||||
DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1);
|
||||
VPBufferSize = BufferSz;
|
||||
return lprofCreateBufferIO(fileWriter, File);
|
||||
ProfDataWriter *fileWriter =
|
||||
(ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1);
|
||||
initFileWriter(fileWriter, File);
|
||||
ProfBufferIO *IO = lprofCreateBufferIO(fileWriter);
|
||||
IO->OwnFileWriter = 1;
|
||||
return IO;
|
||||
}
|
||||
|
||||
static void setupIOBuffer() {
|
||||
@ -122,9 +137,10 @@ static void setupIOBuffer() {
|
||||
|
||||
/* Read profile data in \c ProfileFile and merge with in-memory
|
||||
profile counters. Returns -1 if there is fatal error, otheriwse
|
||||
0 is returned.
|
||||
0 is returned. Returning 0 does not mean merge is actually
|
||||
performed. If merge is actually done, *MergeDone is set to 1.
|
||||
*/
|
||||
static int doProfileMerging(FILE *ProfileFile) {
|
||||
static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
|
||||
uint64_t ProfileFileSize;
|
||||
char *ProfileBuffer;
|
||||
|
||||
@ -169,6 +185,8 @@ static int doProfileMerging(FILE *ProfileFile) {
|
||||
__llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
|
||||
(void)munmap(ProfileBuffer, ProfileFileSize);
|
||||
|
||||
*MergeDone = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -190,7 +208,7 @@ static void createProfileDir(const char *Filename) {
|
||||
* dumper. With profile merging enabled, each executable as well as any of
|
||||
* its instrumented shared libraries dump profile data into their own data file.
|
||||
*/
|
||||
static FILE *openFileForMerging(const char *ProfileFileName) {
|
||||
static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) {
|
||||
FILE *ProfileFile;
|
||||
int rc;
|
||||
|
||||
@ -199,15 +217,14 @@ static FILE *openFileForMerging(const char *ProfileFileName) {
|
||||
if (!ProfileFile)
|
||||
return NULL;
|
||||
|
||||
rc = doProfileMerging(ProfileFile);
|
||||
if (rc || COMPILER_RT_FTRUNCATE(ProfileFile, 0L) ||
|
||||
rc = doProfileMerging(ProfileFile, MergeDone);
|
||||
if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) ||
|
||||
fseek(ProfileFile, 0L, SEEK_SET) == -1) {
|
||||
PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
|
||||
strerror(errno));
|
||||
fclose(ProfileFile);
|
||||
return NULL;
|
||||
}
|
||||
fseek(ProfileFile, 0L, SEEK_SET);
|
||||
return ProfileFile;
|
||||
}
|
||||
|
||||
@ -216,17 +233,20 @@ static int writeFile(const char *OutputName) {
|
||||
int RetVal;
|
||||
FILE *OutputFile;
|
||||
|
||||
int MergeDone = 0;
|
||||
if (!doMerging())
|
||||
OutputFile = fopen(OutputName, "ab");
|
||||
else
|
||||
OutputFile = openFileForMerging(OutputName);
|
||||
OutputFile = openFileForMerging(OutputName, &MergeDone);
|
||||
|
||||
if (!OutputFile)
|
||||
return -1;
|
||||
|
||||
FreeHook = &free;
|
||||
setupIOBuffer();
|
||||
RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader());
|
||||
ProfDataWriter fileWriter;
|
||||
initFileWriter(&fileWriter, OutputFile);
|
||||
RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);
|
||||
|
||||
fclose(OutputFile);
|
||||
return RetVal;
|
||||
|
@ -48,17 +48,21 @@ typedef struct ProfDataIOVec {
|
||||
size_t NumElm;
|
||||
} ProfDataIOVec;
|
||||
|
||||
typedef uint32_t (*WriterCallback)(ProfDataIOVec *, uint32_t NumIOVecs,
|
||||
void **WriterCtx);
|
||||
struct ProfDataWriter;
|
||||
typedef uint32_t (*WriterCallback)(struct ProfDataWriter *This, ProfDataIOVec *,
|
||||
uint32_t NumIOVecs);
|
||||
|
||||
typedef struct ProfDataWriter {
|
||||
WriterCallback Write;
|
||||
void *WriterCtx;
|
||||
} ProfDataWriter;
|
||||
|
||||
/*!
|
||||
* The data structure for buffered IO of profile data.
|
||||
*/
|
||||
typedef struct ProfBufferIO {
|
||||
/* File handle. */
|
||||
void *File;
|
||||
/* Low level IO callback. */
|
||||
WriterCallback FileWriter;
|
||||
ProfDataWriter *FileWriter;
|
||||
uint32_t OwnFileWriter;
|
||||
/* The start of the buffer. */
|
||||
uint8_t *BufferStart;
|
||||
/* Total size of the buffer. */
|
||||
@ -73,7 +77,7 @@ ProfBufferIO *lprofCreateBufferIOInternal(void *File, uint32_t BufferSz);
|
||||
/*!
|
||||
* This is the interface to create a handle for buffered IO.
|
||||
*/
|
||||
ProfBufferIO *lprofCreateBufferIO(WriterCallback FileWriter, void *File);
|
||||
ProfBufferIO *lprofCreateBufferIO(ProfDataWriter *FileWriter);
|
||||
|
||||
/*!
|
||||
* The interface to destroy the bufferIO handle and reclaim
|
||||
@ -96,8 +100,9 @@ int lprofBufferIOFlush(ProfBufferIO *BufferIO);
|
||||
/* The low level interface to write data into a buffer. It is used as the
|
||||
* callback by other high level writer methods such as buffered IO writer
|
||||
* and profile data writer. */
|
||||
uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
|
||||
void **WriterCtx);
|
||||
uint32_t lprofBufferWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
|
||||
uint32_t NumIOVecs);
|
||||
void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer);
|
||||
|
||||
struct ValueProfData;
|
||||
struct ValueProfRecord;
|
||||
@ -133,15 +138,17 @@ typedef struct VPDataReaderType {
|
||||
uint32_t N);
|
||||
} VPDataReaderType;
|
||||
|
||||
int lprofWriteData(WriterCallback Writer, void *WriterCtx,
|
||||
VPDataReaderType *VPDataReader);
|
||||
int lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx,
|
||||
/* Write profile data to destinitation. If SkipNameDataWrite is set to 1,
|
||||
the name data is already in destintation, we just skip over it. */
|
||||
int lprofWriteData(ProfDataWriter *Writer, VPDataReaderType *VPDataReader,
|
||||
int SkipNameDataWrite);
|
||||
int lprofWriteDataImpl(ProfDataWriter *Writer,
|
||||
const __llvm_profile_data *DataBegin,
|
||||
const __llvm_profile_data *DataEnd,
|
||||
const uint64_t *CountersBegin,
|
||||
const uint64_t *CountersEnd,
|
||||
VPDataReaderType *VPDataReader, const char *NamesBegin,
|
||||
const char *NamesEnd);
|
||||
const char *NamesEnd, int SkipNameDataWrite);
|
||||
|
||||
/* Merge value profile data pointed to by SrcValueProfData into
|
||||
* in-memory profile counters pointed by to DstData. */
|
||||
|
18
contrib/compiler-rt/lib/profile/InstrProfilingNameVar.c
Normal file
18
contrib/compiler-rt/lib/profile/InstrProfilingNameVar.c
Normal file
@ -0,0 +1,18 @@
|
||||
//===- InstrProfilingNameVar.c - profile name variable setup --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "InstrProfiling.h"
|
||||
|
||||
/* char __llvm_profile_filename[1]
|
||||
*
|
||||
* The runtime should only provide its own definition of this symbol when the
|
||||
* user has not specified one. Set this up by moving the runtime's copy of this
|
||||
* symbol to an object file within the archive.
|
||||
*/
|
||||
COMPILER_RT_WEAK char INSTR_PROF_PROFILE_NAME_VAR[1] = {0};
|
@ -31,41 +31,44 @@ COMPILER_RT_VISIBILITY uint32_t VPBufferSize = 0;
|
||||
/* The buffer writer is reponsponsible in keeping writer state
|
||||
* across the call.
|
||||
*/
|
||||
COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataIOVec *IOVecs,
|
||||
uint32_t NumIOVecs,
|
||||
void **WriterCtx) {
|
||||
COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataWriter *This,
|
||||
ProfDataIOVec *IOVecs,
|
||||
uint32_t NumIOVecs) {
|
||||
uint32_t I;
|
||||
char **Buffer = (char **)WriterCtx;
|
||||
char **Buffer = (char **)&This->WriterCtx;
|
||||
for (I = 0; I < NumIOVecs; I++) {
|
||||
size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
|
||||
if (IOVecs[I].Data)
|
||||
memcpy(*Buffer, IOVecs[I].Data, Length);
|
||||
*Buffer += Length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void llvmInitBufferIO(ProfBufferIO *BufferIO, WriterCallback FileWriter,
|
||||
void *File, uint8_t *Buffer, uint32_t BufferSz) {
|
||||
BufferIO->File = File;
|
||||
static void llvmInitBufferIO(ProfBufferIO *BufferIO, ProfDataWriter *FileWriter,
|
||||
uint8_t *Buffer, uint32_t BufferSz) {
|
||||
BufferIO->FileWriter = FileWriter;
|
||||
BufferIO->OwnFileWriter = 0;
|
||||
BufferIO->BufferStart = Buffer;
|
||||
BufferIO->BufferSz = BufferSz;
|
||||
BufferIO->CurOffset = 0;
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY ProfBufferIO *
|
||||
lprofCreateBufferIO(WriterCallback FileWriter, void *File) {
|
||||
lprofCreateBufferIO(ProfDataWriter *FileWriter) {
|
||||
uint8_t *Buffer = DynamicBufferIOBuffer;
|
||||
uint32_t BufferSize = VPBufferSize;
|
||||
if (!Buffer) {
|
||||
Buffer = &BufferIOBuffer[0];
|
||||
BufferSize = sizeof(BufferIOBuffer);
|
||||
}
|
||||
llvmInitBufferIO(&TheBufferIO, FileWriter, File, Buffer, BufferSize);
|
||||
llvmInitBufferIO(&TheBufferIO, FileWriter, Buffer, BufferSize);
|
||||
return &TheBufferIO;
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY void lprofDeleteBufferIO(ProfBufferIO *BufferIO) {
|
||||
if (BufferIO->OwnFileWriter)
|
||||
FreeHook(BufferIO->FileWriter);
|
||||
if (DynamicBufferIOBuffer) {
|
||||
FreeHook(DynamicBufferIOBuffer);
|
||||
DynamicBufferIOBuffer = 0;
|
||||
@ -83,13 +86,16 @@ lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) {
|
||||
/* Special case, bypass the buffer completely. */
|
||||
ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size}};
|
||||
if (Size > BufferIO->BufferSz) {
|
||||
if (BufferIO->FileWriter(IO, 1, &BufferIO->File))
|
||||
if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))
|
||||
return -1;
|
||||
} else {
|
||||
/* Write the data to buffer */
|
||||
uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset;
|
||||
lprofBufferWriter(IO, 1, (void **)&Buffer);
|
||||
BufferIO->CurOffset = Buffer - BufferIO->BufferStart;
|
||||
ProfDataWriter BufferWriter;
|
||||
initBufferWriter(&BufferWriter, (char *)Buffer);
|
||||
lprofBufferWriter(&BufferWriter, IO, 1);
|
||||
BufferIO->CurOffset =
|
||||
(uint8_t *)BufferWriter.WriterCtx - BufferIO->BufferStart;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -98,7 +104,7 @@ COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) {
|
||||
if (BufferIO->CurOffset) {
|
||||
ProfDataIOVec IO[] = {
|
||||
{BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset}};
|
||||
if (BufferIO->FileWriter(IO, 1, &BufferIO->File))
|
||||
if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))
|
||||
return -1;
|
||||
BufferIO->CurOffset = 0;
|
||||
}
|
||||
@ -201,7 +207,7 @@ static int writeOneValueProfData(ProfBufferIO *BufferIO,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeValueProfData(WriterCallback Writer, void *WriterCtx,
|
||||
static int writeValueProfData(ProfDataWriter *Writer,
|
||||
VPDataReaderType *VPDataReader,
|
||||
const __llvm_profile_data *DataBegin,
|
||||
const __llvm_profile_data *DataEnd) {
|
||||
@ -211,7 +217,7 @@ static int writeValueProfData(WriterCallback Writer, void *WriterCtx,
|
||||
if (!VPDataReader)
|
||||
return 0;
|
||||
|
||||
BufferIO = lprofCreateBufferIO(Writer, WriterCtx);
|
||||
BufferIO = lprofCreateBufferIO(Writer);
|
||||
|
||||
for (DI = DataBegin; DI < DataEnd; DI++) {
|
||||
if (writeOneValueProfData(BufferIO, VPDataReader, DI))
|
||||
@ -225,9 +231,9 @@ static int writeValueProfData(WriterCallback Writer, void *WriterCtx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY int lprofWriteData(WriterCallback Writer,
|
||||
void *WriterCtx,
|
||||
VPDataReaderType *VPDataReader) {
|
||||
COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer,
|
||||
VPDataReaderType *VPDataReader,
|
||||
int SkipNameDataWrite) {
|
||||
/* Match logic in __llvm_profile_write_buffer(). */
|
||||
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
|
||||
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
|
||||
@ -235,18 +241,17 @@ COMPILER_RT_VISIBILITY int lprofWriteData(WriterCallback Writer,
|
||||
const uint64_t *CountersEnd = __llvm_profile_end_counters();
|
||||
const char *NamesBegin = __llvm_profile_begin_names();
|
||||
const char *NamesEnd = __llvm_profile_end_names();
|
||||
return lprofWriteDataImpl(Writer, WriterCtx, DataBegin, DataEnd,
|
||||
CountersBegin, CountersEnd, VPDataReader,
|
||||
NamesBegin, NamesEnd);
|
||||
return lprofWriteDataImpl(Writer, DataBegin, DataEnd, CountersBegin,
|
||||
CountersEnd, VPDataReader, NamesBegin, NamesEnd,
|
||||
SkipNameDataWrite);
|
||||
}
|
||||
|
||||
COMPILER_RT_VISIBILITY int
|
||||
lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx,
|
||||
const __llvm_profile_data *DataBegin,
|
||||
lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
|
||||
const __llvm_profile_data *DataEnd,
|
||||
const uint64_t *CountersBegin, const uint64_t *CountersEnd,
|
||||
VPDataReaderType *VPDataReader, const char *NamesBegin,
|
||||
const char *NamesEnd) {
|
||||
const char *NamesEnd, int SkipNameDataWrite) {
|
||||
|
||||
/* Calculate size of sections. */
|
||||
const uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
|
||||
@ -268,14 +273,14 @@ lprofWriteDataImpl(WriterCallback Writer, void *WriterCtx,
|
||||
#include "InstrProfData.inc"
|
||||
|
||||
/* Write the data. */
|
||||
ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1},
|
||||
ProfDataIOVec IOVec[] = {
|
||||
{&Header, sizeof(__llvm_profile_header), 1},
|
||||
{DataBegin, sizeof(__llvm_profile_data), DataSize},
|
||||
{CountersBegin, sizeof(uint64_t), CountersSize},
|
||||
{NamesBegin, sizeof(uint8_t), NamesSize},
|
||||
{SkipNameDataWrite ? NULL : NamesBegin, sizeof(uint8_t), NamesSize},
|
||||
{Zeroes, sizeof(uint8_t), Padding}};
|
||||
if (Writer(IOVec, sizeof(IOVec) / sizeof(*IOVec), &WriterCtx))
|
||||
if (Writer->Write(Writer, IOVec, sizeof(IOVec) / sizeof(*IOVec)))
|
||||
return -1;
|
||||
|
||||
return writeValueProfData(Writer, WriterCtx, VPDataReader, DataBegin,
|
||||
DataEnd);
|
||||
return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd);
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) {
|
||||
}
|
||||
|
||||
void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
|
||||
if (CallocShouldReturnNullDueToOverflow(count, size))
|
||||
if (CheckForCallocOverflow(count, size))
|
||||
return InternalAllocator::FailureHandler::OnBadRequest();
|
||||
void *p = InternalAlloc(count * size, cache);
|
||||
if (p) internal_memset(p, 0, count * size);
|
||||
@ -202,7 +202,7 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
|
||||
low_level_alloc_callback = callback;
|
||||
}
|
||||
|
||||
bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
|
||||
bool CheckForCallocOverflow(uptr size, uptr n) {
|
||||
if (!size) return false;
|
||||
uptr max = (uptr)-1L;
|
||||
return (max / size) < n;
|
||||
@ -246,11 +246,11 @@ void *ReturnNullOrDieOnFailure::OnOOM() {
|
||||
ReportAllocatorCannotReturnNull();
|
||||
}
|
||||
|
||||
void *DieOnFailure::OnBadRequest() {
|
||||
void NORETURN *DieOnFailure::OnBadRequest() {
|
||||
ReportAllocatorCannotReturnNull();
|
||||
}
|
||||
|
||||
void *DieOnFailure::OnOOM() {
|
||||
void NORETURN *DieOnFailure::OnOOM() {
|
||||
atomic_store_relaxed(&allocator_out_of_memory, 1);
|
||||
ReportAllocatorCannotReturnNull();
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ struct ReturnNullOrDieOnFailure {
|
||||
};
|
||||
// Always dies on the failure.
|
||||
struct DieOnFailure {
|
||||
static void *OnBadRequest();
|
||||
static void *OnOOM();
|
||||
static void NORETURN *OnBadRequest();
|
||||
static void NORETURN *OnOOM();
|
||||
};
|
||||
|
||||
// Returns true if allocator detected OOM condition. Can be used to avoid memory
|
||||
@ -56,8 +56,10 @@ struct NoOpMapUnmapCallback {
|
||||
// Callback type for iterating over chunks.
|
||||
typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
|
||||
|
||||
// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
|
||||
bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
|
||||
// Returns true if calloc(size, n) call overflows on size*n calculation.
|
||||
// The caller should "return POLICY::OnBadRequest();" where POLICY is the
|
||||
// current allocator failure handling policy.
|
||||
bool CheckForCallocOverflow(uptr size, uptr n);
|
||||
|
||||
#include "sanitizer_allocator_size_class_map.h"
|
||||
#include "sanitizer_allocator_stats.h"
|
||||
|
@ -46,8 +46,10 @@ struct SizeClassAllocator64LocalCache {
|
||||
CHECK_NE(class_id, 0UL);
|
||||
CHECK_LT(class_id, kNumClasses);
|
||||
PerClass *c = &per_class_[class_id];
|
||||
if (UNLIKELY(c->count == 0))
|
||||
Refill(c, allocator, class_id);
|
||||
if (UNLIKELY(c->count == 0)) {
|
||||
if (UNLIKELY(!Refill(c, allocator, class_id)))
|
||||
return nullptr;
|
||||
}
|
||||
stats_.Add(AllocatorStatAllocated, c->class_size);
|
||||
CHECK_GT(c->count, 0);
|
||||
CompactPtrT chunk = c->chunks[--c->count];
|
||||
@ -101,13 +103,15 @@ struct SizeClassAllocator64LocalCache {
|
||||
}
|
||||
}
|
||||
|
||||
NOINLINE void Refill(PerClass *c, SizeClassAllocator *allocator,
|
||||
NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator,
|
||||
uptr class_id) {
|
||||
InitCache();
|
||||
uptr num_requested_chunks = c->max_count / 2;
|
||||
allocator->GetFromAllocator(&stats_, class_id, c->chunks,
|
||||
num_requested_chunks);
|
||||
if (UNLIKELY(!allocator->GetFromAllocator(&stats_, class_id, c->chunks,
|
||||
num_requested_chunks)))
|
||||
return false;
|
||||
c->count = num_requested_chunks;
|
||||
return true;
|
||||
}
|
||||
|
||||
NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, uptr class_id,
|
||||
|
@ -118,7 +118,6 @@ class SizeClassAllocator32 {
|
||||
}
|
||||
|
||||
void *MapWithCallback(uptr size) {
|
||||
size = RoundUpTo(size, GetPageSizeCached());
|
||||
void *res = MmapOrDie(size, "SizeClassAllocator32");
|
||||
MapUnmapCallback().OnMap((uptr)res, size);
|
||||
return res;
|
||||
@ -285,7 +284,7 @@ class SizeClassAllocator32 {
|
||||
return 0;
|
||||
MapUnmapCallback().OnMap(res, kRegionSize);
|
||||
stat->Add(AllocatorStatMapped, kRegionSize);
|
||||
CHECK_EQ(0U, (res & (kRegionSize - 1)));
|
||||
CHECK(IsAligned(res, kRegionSize));
|
||||
possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
|
||||
return res;
|
||||
}
|
||||
@ -303,17 +302,17 @@ class SizeClassAllocator32 {
|
||||
return false;
|
||||
uptr n_chunks = kRegionSize / (size + kMetadataSize);
|
||||
uptr max_count = TransferBatch::MaxCached(class_id);
|
||||
CHECK_GT(max_count, 0);
|
||||
TransferBatch *b = nullptr;
|
||||
for (uptr i = reg; i < reg + n_chunks * size; i += size) {
|
||||
if (!b) {
|
||||
b = c->CreateBatch(class_id, this, (TransferBatch*)i);
|
||||
if (!b)
|
||||
if (UNLIKELY(!b))
|
||||
return false;
|
||||
b->Clear();
|
||||
}
|
||||
b->Add((void*)i);
|
||||
if (b->Count() == max_count) {
|
||||
CHECK_GT(b->Count(), 0);
|
||||
sci->free_list.push_back(b);
|
||||
b = nullptr;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ class SizeClassAllocator64 {
|
||||
CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
|
||||
}
|
||||
SetReleaseToOSIntervalMs(release_to_os_interval_ms);
|
||||
MapWithCallback(SpaceEnd(), AdditionalSize());
|
||||
MapWithCallbackOrDie(SpaceEnd(), AdditionalSize());
|
||||
}
|
||||
|
||||
s32 ReleaseToOSIntervalMs() const {
|
||||
@ -92,16 +92,6 @@ class SizeClassAllocator64 {
|
||||
memory_order_relaxed);
|
||||
}
|
||||
|
||||
void MapWithCallback(uptr beg, uptr size) {
|
||||
CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
|
||||
MapUnmapCallback().OnMap(beg, size);
|
||||
}
|
||||
|
||||
void UnmapWithCallback(uptr beg, uptr size) {
|
||||
MapUnmapCallback().OnUnmap(beg, size);
|
||||
UnmapOrDie(reinterpret_cast<void *>(beg), size);
|
||||
}
|
||||
|
||||
static bool CanAllocate(uptr size, uptr alignment) {
|
||||
return size <= SizeClassMap::kMaxSize &&
|
||||
alignment <= SizeClassMap::kMaxSize;
|
||||
@ -116,16 +106,20 @@ class SizeClassAllocator64 {
|
||||
BlockingMutexLock l(®ion->mutex);
|
||||
uptr old_num_chunks = region->num_freed_chunks;
|
||||
uptr new_num_freed_chunks = old_num_chunks + n_chunks;
|
||||
EnsureFreeArraySpace(region, region_beg, new_num_freed_chunks);
|
||||
// Failure to allocate free array space while releasing memory is non
|
||||
// recoverable.
|
||||
if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg,
|
||||
new_num_freed_chunks)))
|
||||
DieOnFailure::OnOOM();
|
||||
for (uptr i = 0; i < n_chunks; i++)
|
||||
free_array[old_num_chunks + i] = chunks[i];
|
||||
region->num_freed_chunks = new_num_freed_chunks;
|
||||
region->n_freed += n_chunks;
|
||||
region->stats.n_freed += n_chunks;
|
||||
|
||||
MaybeReleaseToOS(class_id);
|
||||
}
|
||||
|
||||
NOINLINE void GetFromAllocator(AllocatorStats *stat, uptr class_id,
|
||||
NOINLINE bool GetFromAllocator(AllocatorStats *stat, uptr class_id,
|
||||
CompactPtrT *chunks, uptr n_chunks) {
|
||||
RegionInfo *region = GetRegionInfo(class_id);
|
||||
uptr region_beg = GetRegionBeginBySizeClass(class_id);
|
||||
@ -133,18 +127,19 @@ class SizeClassAllocator64 {
|
||||
|
||||
BlockingMutexLock l(®ion->mutex);
|
||||
if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
|
||||
PopulateFreeArray(stat, class_id, region,
|
||||
n_chunks - region->num_freed_chunks);
|
||||
if (UNLIKELY(!PopulateFreeArray(stat, class_id, region,
|
||||
n_chunks - region->num_freed_chunks)))
|
||||
return false;
|
||||
CHECK_GE(region->num_freed_chunks, n_chunks);
|
||||
}
|
||||
region->num_freed_chunks -= n_chunks;
|
||||
uptr base_idx = region->num_freed_chunks;
|
||||
for (uptr i = 0; i < n_chunks; i++)
|
||||
chunks[i] = free_array[base_idx + i];
|
||||
region->n_allocated += n_chunks;
|
||||
region->stats.n_allocated += n_chunks;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PointerIsMine(const void *p) {
|
||||
uptr P = reinterpret_cast<uptr>(p);
|
||||
if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0)
|
||||
@ -211,7 +206,7 @@ class SizeClassAllocator64 {
|
||||
|
||||
// Test-only.
|
||||
void TestOnlyUnmap() {
|
||||
UnmapWithCallback(SpaceBeg(), kSpaceSize + AdditionalSize());
|
||||
UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize());
|
||||
}
|
||||
|
||||
static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats,
|
||||
@ -224,15 +219,15 @@ class SizeClassAllocator64 {
|
||||
void PrintStats(uptr class_id, uptr rss) {
|
||||
RegionInfo *region = GetRegionInfo(class_id);
|
||||
if (region->mapped_user == 0) return;
|
||||
uptr in_use = region->n_allocated - region->n_freed;
|
||||
uptr in_use = region->stats.n_allocated - region->stats.n_freed;
|
||||
uptr avail_chunks = region->allocated_user / ClassIdToSize(class_id);
|
||||
Printf(
|
||||
" %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd "
|
||||
"%s %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd "
|
||||
"num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd\n",
|
||||
class_id, ClassIdToSize(class_id), region->mapped_user >> 10,
|
||||
region->n_allocated, region->n_freed, in_use,
|
||||
region->num_freed_chunks, avail_chunks, rss >> 10,
|
||||
region->rtoi.num_releases);
|
||||
region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id),
|
||||
region->mapped_user >> 10, region->stats.n_allocated,
|
||||
region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks,
|
||||
rss >> 10, region->rtoi.num_releases);
|
||||
}
|
||||
|
||||
void PrintStats() {
|
||||
@ -242,8 +237,8 @@ class SizeClassAllocator64 {
|
||||
for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
|
||||
RegionInfo *region = GetRegionInfo(class_id);
|
||||
total_mapped += region->mapped_user;
|
||||
n_allocated += region->n_allocated;
|
||||
n_freed += region->n_freed;
|
||||
n_allocated += region->stats.n_allocated;
|
||||
n_freed += region->stats.n_freed;
|
||||
}
|
||||
Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; "
|
||||
"remains %zd\n",
|
||||
@ -326,6 +321,11 @@ class SizeClassAllocator64 {
|
||||
|
||||
atomic_sint32_t release_to_os_interval_ms_;
|
||||
|
||||
struct Stats {
|
||||
uptr n_allocated;
|
||||
uptr n_freed;
|
||||
};
|
||||
|
||||
struct ReleaseToOsInfo {
|
||||
uptr n_freed_at_last_release;
|
||||
uptr num_releases;
|
||||
@ -341,7 +341,8 @@ class SizeClassAllocator64 {
|
||||
uptr mapped_user; // Bytes mapped for user memory.
|
||||
uptr mapped_meta; // Bytes mapped for metadata.
|
||||
u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks.
|
||||
uptr n_allocated, n_freed; // Just stats.
|
||||
bool exhausted; // Whether region is out of space for new chunks.
|
||||
Stats stats;
|
||||
ReleaseToOsInfo rtoi;
|
||||
};
|
||||
COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
|
||||
@ -386,7 +387,26 @@ class SizeClassAllocator64 {
|
||||
kFreeArraySize);
|
||||
}
|
||||
|
||||
void EnsureFreeArraySpace(RegionInfo *region, uptr region_beg,
|
||||
bool MapWithCallback(uptr beg, uptr size) {
|
||||
uptr mapped = reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(beg, size));
|
||||
if (UNLIKELY(!mapped))
|
||||
return false;
|
||||
CHECK_EQ(beg, mapped);
|
||||
MapUnmapCallback().OnMap(beg, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapWithCallbackOrDie(uptr beg, uptr size) {
|
||||
CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
|
||||
MapUnmapCallback().OnMap(beg, size);
|
||||
}
|
||||
|
||||
void UnmapWithCallbackOrDie(uptr beg, uptr size) {
|
||||
MapUnmapCallback().OnUnmap(beg, size);
|
||||
UnmapOrDie(reinterpret_cast<void *>(beg), size);
|
||||
}
|
||||
|
||||
bool EnsureFreeArraySpace(RegionInfo *region, uptr region_beg,
|
||||
uptr num_freed_chunks) {
|
||||
uptr needed_space = num_freed_chunks * sizeof(CompactPtrT);
|
||||
if (region->mapped_free_array < needed_space) {
|
||||
@ -395,66 +415,87 @@ class SizeClassAllocator64 {
|
||||
uptr current_map_end = reinterpret_cast<uptr>(GetFreeArray(region_beg)) +
|
||||
region->mapped_free_array;
|
||||
uptr new_map_size = new_mapped_free_array - region->mapped_free_array;
|
||||
MapWithCallback(current_map_end, new_map_size);
|
||||
if (UNLIKELY(!MapWithCallback(current_map_end, new_map_size)))
|
||||
return false;
|
||||
region->mapped_free_array = new_mapped_free_array;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
NOINLINE void PopulateFreeArray(AllocatorStats *stat, uptr class_id,
|
||||
NOINLINE bool PopulateFreeArray(AllocatorStats *stat, uptr class_id,
|
||||
RegionInfo *region, uptr requested_count) {
|
||||
// region->mutex is held.
|
||||
uptr size = ClassIdToSize(class_id);
|
||||
uptr beg_idx = region->allocated_user;
|
||||
uptr end_idx = beg_idx + requested_count * size;
|
||||
uptr region_beg = GetRegionBeginBySizeClass(class_id);
|
||||
if (end_idx > region->mapped_user) {
|
||||
const uptr size = ClassIdToSize(class_id);
|
||||
const uptr new_space_beg = region->allocated_user;
|
||||
const uptr new_space_end = new_space_beg + requested_count * size;
|
||||
const uptr region_beg = GetRegionBeginBySizeClass(class_id);
|
||||
|
||||
// Map more space for chunks, if necessary.
|
||||
if (new_space_end > region->mapped_user) {
|
||||
if (!kUsingConstantSpaceBeg && region->mapped_user == 0)
|
||||
region->rand_state = static_cast<u32>(region_beg >> 12); // From ASLR.
|
||||
// Do the mmap for the user memory.
|
||||
uptr map_size = kUserMapSize;
|
||||
while (end_idx > region->mapped_user + map_size)
|
||||
while (new_space_end > region->mapped_user + map_size)
|
||||
map_size += kUserMapSize;
|
||||
CHECK_GE(region->mapped_user + map_size, end_idx);
|
||||
MapWithCallback(region_beg + region->mapped_user, map_size);
|
||||
CHECK_GE(region->mapped_user + map_size, new_space_end);
|
||||
if (UNLIKELY(!MapWithCallback(region_beg + region->mapped_user,
|
||||
map_size)))
|
||||
return false;
|
||||
stat->Add(AllocatorStatMapped, map_size);
|
||||
region->mapped_user += map_size;
|
||||
}
|
||||
CompactPtrT *free_array = GetFreeArray(region_beg);
|
||||
uptr total_count = (region->mapped_user - beg_idx) / size;
|
||||
uptr num_freed_chunks = region->num_freed_chunks;
|
||||
EnsureFreeArraySpace(region, region_beg, num_freed_chunks + total_count);
|
||||
for (uptr i = 0; i < total_count; i++) {
|
||||
uptr chunk = beg_idx + i * size;
|
||||
free_array[num_freed_chunks + total_count - 1 - i] =
|
||||
PointerToCompactPtr(0, chunk);
|
||||
}
|
||||
if (kRandomShuffleChunks)
|
||||
RandomShuffle(&free_array[num_freed_chunks], total_count,
|
||||
®ion->rand_state);
|
||||
region->num_freed_chunks += total_count;
|
||||
region->allocated_user += total_count * size;
|
||||
CHECK_LE(region->allocated_user, region->mapped_user);
|
||||
const uptr new_chunks_count = (region->mapped_user - new_space_beg) / size;
|
||||
|
||||
region->allocated_meta += total_count * kMetadataSize;
|
||||
if (region->allocated_meta > region->mapped_meta) {
|
||||
uptr map_size = kMetaMapSize;
|
||||
while (region->allocated_meta > region->mapped_meta + map_size)
|
||||
map_size += kMetaMapSize;
|
||||
// Do the mmap for the metadata.
|
||||
CHECK_GE(region->mapped_meta + map_size, region->allocated_meta);
|
||||
MapWithCallback(GetMetadataEnd(region_beg) -
|
||||
region->mapped_meta - map_size, map_size);
|
||||
region->mapped_meta += map_size;
|
||||
}
|
||||
CHECK_LE(region->allocated_meta, region->mapped_meta);
|
||||
if (region->mapped_user + region->mapped_meta >
|
||||
// Calculate the required space for metadata.
|
||||
const uptr requested_allocated_meta =
|
||||
region->allocated_meta + new_chunks_count * kMetadataSize;
|
||||
uptr requested_mapped_meta = region->mapped_meta;
|
||||
while (requested_allocated_meta > requested_mapped_meta)
|
||||
requested_mapped_meta += kMetaMapSize;
|
||||
// Check whether this size class is exhausted.
|
||||
if (region->mapped_user + requested_mapped_meta >
|
||||
kRegionSize - kFreeArraySize) {
|
||||
Printf("%s: Out of memory. Dying. ", SanitizerToolName);
|
||||
if (!region->exhausted) {
|
||||
region->exhausted = true;
|
||||
Printf("%s: Out of memory. ", SanitizerToolName);
|
||||
Printf("The process has exhausted %zuMB for size class %zu.\n",
|
||||
kRegionSize / 1024 / 1024, size);
|
||||
Die();
|
||||
kRegionSize >> 20, size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Map more space for metadata, if necessary.
|
||||
if (requested_mapped_meta > region->mapped_meta) {
|
||||
if (UNLIKELY(!MapWithCallback(
|
||||
GetMetadataEnd(region_beg) - requested_mapped_meta,
|
||||
requested_mapped_meta - region->mapped_meta)))
|
||||
return false;
|
||||
region->mapped_meta = requested_mapped_meta;
|
||||
}
|
||||
|
||||
// If necessary, allocate more space for the free array and populate it with
|
||||
// newly allocated chunks.
|
||||
const uptr total_freed_chunks = region->num_freed_chunks + new_chunks_count;
|
||||
if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, total_freed_chunks)))
|
||||
return false;
|
||||
CompactPtrT *free_array = GetFreeArray(region_beg);
|
||||
for (uptr i = 0, chunk = new_space_beg; i < new_chunks_count;
|
||||
i++, chunk += size)
|
||||
free_array[total_freed_chunks - 1 - i] = PointerToCompactPtr(0, chunk);
|
||||
if (kRandomShuffleChunks)
|
||||
RandomShuffle(&free_array[region->num_freed_chunks], new_chunks_count,
|
||||
®ion->rand_state);
|
||||
|
||||
// All necessary memory is mapped and now it is safe to advance all
|
||||
// 'allocated_*' counters.
|
||||
region->num_freed_chunks += new_chunks_count;
|
||||
region->allocated_user += new_chunks_count * size;
|
||||
CHECK_LE(region->allocated_user, region->mapped_user);
|
||||
region->allocated_meta = requested_allocated_meta;
|
||||
CHECK_LE(region->allocated_meta, region->mapped_meta);
|
||||
region->exhausted = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MaybeReleaseChunkRange(uptr region_beg, uptr chunk_size,
|
||||
@ -478,8 +519,8 @@ class SizeClassAllocator64 {
|
||||
uptr n = region->num_freed_chunks;
|
||||
if (n * chunk_size < page_size)
|
||||
return; // No chance to release anything.
|
||||
if ((region->n_freed - region->rtoi.n_freed_at_last_release) * chunk_size <
|
||||
page_size) {
|
||||
if ((region->stats.n_freed -
|
||||
region->rtoi.n_freed_at_last_release) * chunk_size < page_size) {
|
||||
return; // Nothing new to release.
|
||||
}
|
||||
|
||||
@ -508,7 +549,7 @@ class SizeClassAllocator64 {
|
||||
CHECK_GT(chunk - prev, scaled_chunk_size);
|
||||
if (prev + scaled_chunk_size - range_beg >= kScaledGranularity) {
|
||||
MaybeReleaseChunkRange(region_beg, chunk_size, range_beg, prev);
|
||||
region->rtoi.n_freed_at_last_release = region->n_freed;
|
||||
region->rtoi.n_freed_at_last_release = region->stats.n_freed;
|
||||
region->rtoi.num_releases++;
|
||||
}
|
||||
range_beg = chunk;
|
||||
@ -517,5 +558,3 @@ class SizeClassAllocator64 {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -92,6 +92,9 @@ void *MmapFixedNoReserve(uptr fixed_addr, uptr size,
|
||||
const char *name = nullptr);
|
||||
void *MmapNoReserveOrDie(uptr size, const char *mem_type);
|
||||
void *MmapFixedOrDie(uptr fixed_addr, uptr size);
|
||||
// Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in
|
||||
// that case returns nullptr.
|
||||
void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size);
|
||||
void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr);
|
||||
void *MmapNoAccess(uptr size);
|
||||
// Map aligned chunk of address space; size and alignment are powers of two.
|
||||
|
@ -6199,6 +6199,57 @@ INTERCEPTOR(int, mprobe, void *ptr) {
|
||||
}
|
||||
#endif
|
||||
|
||||
INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, wcslen, s);
|
||||
SIZE_T res = REAL(wcslen)(s);
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * (res + 1));
|
||||
return res;
|
||||
}
|
||||
|
||||
INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, wcsnlen, s, n);
|
||||
SIZE_T res = REAL(wcsnlen)(s, n);
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * Min(res + 1, n));
|
||||
return res;
|
||||
}
|
||||
#define INIT_WCSLEN \
|
||||
COMMON_INTERCEPT_FUNCTION(wcslen); \
|
||||
COMMON_INTERCEPT_FUNCTION(wcsnlen);
|
||||
|
||||
#if SANITIZER_INTERCEPT_WCSCAT
|
||||
INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, wcscat, dst, src);
|
||||
SIZE_T src_size = REAL(wcslen)(src);
|
||||
SIZE_T dst_size = REAL(wcslen)(dst);
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, src, (src_size + 1) * sizeof(wchar_t));
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t));
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size,
|
||||
(src_size + 1) * sizeof(wchar_t));
|
||||
return REAL(wcscat)(dst, src); // NOLINT
|
||||
}
|
||||
|
||||
INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) {
|
||||
void *ctx;
|
||||
COMMON_INTERCEPTOR_ENTER(ctx, wcsncat, dst, src, n);
|
||||
SIZE_T src_size = REAL(wcsnlen)(src, n);
|
||||
SIZE_T dst_size = REAL(wcslen)(dst);
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, src,
|
||||
Min(src_size + 1, n) * sizeof(wchar_t));
|
||||
COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t));
|
||||
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size,
|
||||
(src_size + 1) * sizeof(wchar_t));
|
||||
return REAL(wcsncat)(dst, src, n); // NOLINT
|
||||
}
|
||||
#define INIT_WCSCAT \
|
||||
COMMON_INTERCEPT_FUNCTION(wcscat); \
|
||||
COMMON_INTERCEPT_FUNCTION(wcsncat);
|
||||
#else
|
||||
#define INIT_WCSCAT
|
||||
#endif
|
||||
|
||||
static void InitializeCommonInterceptors() {
|
||||
static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
|
||||
interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
|
||||
@ -6403,4 +6454,6 @@ static void InitializeCommonInterceptors() {
|
||||
INIT_UTMP;
|
||||
INIT_UTMPX;
|
||||
INIT_GETLOADAVG;
|
||||
INIT_WCSLEN;
|
||||
INIT_WCSCAT;
|
||||
}
|
||||
|
@ -354,5 +354,6 @@
|
||||
#define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC)
|
||||
#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC)
|
||||
#define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID
|
||||
#define SANITIZER_INTERCEPT_WCSCAT SI_NOT_WINDOWS
|
||||
|
||||
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
|
||||
|
@ -129,7 +129,7 @@ void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
int reserrno;
|
||||
if (internal_iserror(res, &reserrno))
|
||||
if (UNLIKELY(internal_iserror(res, &reserrno)))
|
||||
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
|
||||
IncreaseTotalMmap(size);
|
||||
return (void *)res;
|
||||
@ -138,7 +138,7 @@ void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
|
||||
void UnmapOrDie(void *addr, uptr size) {
|
||||
if (!addr || !size) return;
|
||||
uptr res = internal_munmap(addr, size);
|
||||
if (internal_iserror(res)) {
|
||||
if (UNLIKELY(internal_iserror(res))) {
|
||||
Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
|
||||
SanitizerToolName, size, size, addr);
|
||||
CHECK("unable to unmap" && 0);
|
||||
@ -152,7 +152,7 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
int reserrno;
|
||||
if (internal_iserror(res, &reserrno)) {
|
||||
if (UNLIKELY(internal_iserror(res, &reserrno))) {
|
||||
if (reserrno == ENOMEM)
|
||||
return nullptr;
|
||||
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
|
||||
@ -170,15 +170,15 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
|
||||
CHECK(IsPowerOfTwo(alignment));
|
||||
uptr map_size = size + alignment;
|
||||
uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
|
||||
if (!map_res)
|
||||
if (UNLIKELY(!map_res))
|
||||
return nullptr;
|
||||
uptr map_end = map_res + map_size;
|
||||
uptr res = map_res;
|
||||
if (res & (alignment - 1)) // Not aligned.
|
||||
res = (map_res + alignment) & ~(alignment - 1);
|
||||
uptr end = res + size;
|
||||
if (res != map_res)
|
||||
if (!IsAligned(res, alignment)) {
|
||||
res = (map_res + alignment - 1) & ~(alignment - 1);
|
||||
UnmapOrDie((void*)map_res, res - map_res);
|
||||
}
|
||||
uptr end = res + size;
|
||||
if (end != map_end)
|
||||
UnmapOrDie((void*)end, map_end - end);
|
||||
return (void*)res;
|
||||
@ -192,13 +192,13 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
|
||||
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
|
||||
-1, 0);
|
||||
int reserrno;
|
||||
if (internal_iserror(p, &reserrno))
|
||||
if (UNLIKELY(internal_iserror(p, &reserrno)))
|
||||
ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
|
||||
IncreaseTotalMmap(size);
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
|
||||
void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem) {
|
||||
uptr PageSize = GetPageSizeCached();
|
||||
uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
|
||||
RoundUpTo(size, PageSize),
|
||||
@ -206,8 +206,10 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
|
||||
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
|
||||
-1, 0);
|
||||
int reserrno;
|
||||
if (internal_iserror(p, &reserrno)) {
|
||||
char mem_type[30];
|
||||
if (UNLIKELY(internal_iserror(p, &reserrno))) {
|
||||
if (tolerate_enomem && reserrno == ENOMEM)
|
||||
return nullptr;
|
||||
char mem_type[40];
|
||||
internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
|
||||
fixed_addr);
|
||||
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
|
||||
@ -216,6 +218,14 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
|
||||
return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/);
|
||||
}
|
||||
|
||||
void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) {
|
||||
return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/);
|
||||
}
|
||||
|
||||
bool MprotectNoAccess(uptr addr, uptr size) {
|
||||
return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
|
||||
}
|
||||
|
@ -235,6 +235,18 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
|
||||
return p;
|
||||
}
|
||||
|
||||
void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) {
|
||||
void *p = VirtualAlloc((LPVOID)fixed_addr, size,
|
||||
MEM_COMMIT, PAGE_READWRITE);
|
||||
if (p == 0) {
|
||||
char mem_type[30];
|
||||
internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
|
||||
fixed_addr);
|
||||
return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
|
||||
// FIXME: make this really NoReserve?
|
||||
return MmapOrDie(size, mem_type);
|
||||
|
@ -22,8 +22,7 @@
|
||||
#include "sanitizer_common/sanitizer_allocator_interface.h"
|
||||
#include "sanitizer_common/sanitizer_quarantine.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace __scudo {
|
||||
@ -341,7 +340,7 @@ struct ScudoAllocator {
|
||||
// Helper function that checks for a valid Scudo chunk. nullptr isn't.
|
||||
bool isValidPointer(const void *UserPtr) {
|
||||
initThreadMaybe();
|
||||
if (!UserPtr)
|
||||
if (UNLIKELY(!UserPtr))
|
||||
return false;
|
||||
uptr UserBeg = reinterpret_cast<uptr>(UserPtr);
|
||||
if (!IsAligned(UserBeg, MinAlignment))
|
||||
@ -353,22 +352,19 @@ struct ScudoAllocator {
|
||||
void *allocate(uptr Size, uptr Alignment, AllocType Type,
|
||||
bool ForceZeroContents = false) {
|
||||
initThreadMaybe();
|
||||
if (UNLIKELY(!IsPowerOfTwo(Alignment))) {
|
||||
dieWithMessage("ERROR: alignment is not a power of 2\n");
|
||||
}
|
||||
if (Alignment > MaxAlignment)
|
||||
if (UNLIKELY(Alignment > MaxAlignment))
|
||||
return FailureHandler::OnBadRequest();
|
||||
if (Alignment < MinAlignment)
|
||||
if (UNLIKELY(Alignment < MinAlignment))
|
||||
Alignment = MinAlignment;
|
||||
if (Size >= MaxAllowedMallocSize)
|
||||
if (UNLIKELY(Size >= MaxAllowedMallocSize))
|
||||
return FailureHandler::OnBadRequest();
|
||||
if (Size == 0)
|
||||
if (UNLIKELY(Size == 0))
|
||||
Size = 1;
|
||||
|
||||
uptr NeededSize = RoundUpTo(Size, MinAlignment) + AlignedChunkHeaderSize;
|
||||
uptr AlignedSize = (Alignment > MinAlignment) ?
|
||||
NeededSize + (Alignment - AlignedChunkHeaderSize) : NeededSize;
|
||||
if (AlignedSize >= MaxAllowedMallocSize)
|
||||
if (UNLIKELY(AlignedSize >= MaxAllowedMallocSize))
|
||||
return FailureHandler::OnBadRequest();
|
||||
|
||||
// Primary and Secondary backed allocations have a different treatment. We
|
||||
@ -393,7 +389,7 @@ struct ScudoAllocator {
|
||||
Ptr = BackendAllocator.Allocate(&FallbackAllocatorCache, AllocationSize,
|
||||
AllocationAlignment, FromPrimary);
|
||||
}
|
||||
if (!Ptr)
|
||||
if (UNLIKELY(!Ptr))
|
||||
return FailureHandler::OnOOM();
|
||||
|
||||
// If requested, we will zero out the entire contents of the returned chunk.
|
||||
@ -404,7 +400,7 @@ struct ScudoAllocator {
|
||||
UnpackedHeader Header = {};
|
||||
uptr AllocBeg = reinterpret_cast<uptr>(Ptr);
|
||||
uptr UserBeg = AllocBeg + AlignedChunkHeaderSize;
|
||||
if (!IsAligned(UserBeg, Alignment)) {
|
||||
if (UNLIKELY(!IsAligned(UserBeg, Alignment))) {
|
||||
// Since the Secondary takes care of alignment, a non-aligned pointer
|
||||
// means it is from the Primary. It is also the only case where the offset
|
||||
// field of the header would be non-zero.
|
||||
@ -481,7 +477,7 @@ struct ScudoAllocator {
|
||||
void deallocate(void *UserPtr, uptr DeleteSize, AllocType Type) {
|
||||
initThreadMaybe();
|
||||
// if (&__sanitizer_free_hook) __sanitizer_free_hook(UserPtr);
|
||||
if (!UserPtr)
|
||||
if (UNLIKELY(!UserPtr))
|
||||
return;
|
||||
uptr UserBeg = reinterpret_cast<uptr>(UserPtr);
|
||||
if (UNLIKELY(!IsAligned(UserBeg, MinAlignment))) {
|
||||
@ -568,7 +564,7 @@ struct ScudoAllocator {
|
||||
// Helper function that returns the actual usable size of a chunk.
|
||||
uptr getUsableSize(const void *Ptr) {
|
||||
initThreadMaybe();
|
||||
if (!Ptr)
|
||||
if (UNLIKELY(!Ptr))
|
||||
return 0;
|
||||
uptr UserBeg = reinterpret_cast<uptr>(Ptr);
|
||||
ScudoChunk *Chunk = getScudoChunk(UserBeg);
|
||||
@ -584,10 +580,9 @@ struct ScudoAllocator {
|
||||
|
||||
void *calloc(uptr NMemB, uptr Size) {
|
||||
initThreadMaybe();
|
||||
uptr Total = NMemB * Size;
|
||||
if (Size != 0 && Total / Size != NMemB) // Overflow check
|
||||
if (CheckForCallocOverflow(NMemB, Size))
|
||||
return FailureHandler::OnBadRequest();
|
||||
return allocate(Total, MinAlignment, FromMalloc, true);
|
||||
return allocate(NMemB * Size, MinAlignment, FromMalloc, true);
|
||||
}
|
||||
|
||||
void commitBack(ScudoThreadContext *ThreadContext) {
|
||||
@ -655,10 +650,6 @@ void *scudoValloc(uptr Size) {
|
||||
return Instance.allocate(Size, GetPageSizeCached(), FromMemalign);
|
||||
}
|
||||
|
||||
void *scudoMemalign(uptr Alignment, uptr Size) {
|
||||
return Instance.allocate(Size, Alignment, FromMemalign);
|
||||
}
|
||||
|
||||
void *scudoPvalloc(uptr Size) {
|
||||
uptr PageSize = GetPageSizeCached();
|
||||
Size = RoundUpTo(Size, PageSize);
|
||||
@ -669,16 +660,27 @@ void *scudoPvalloc(uptr Size) {
|
||||
return Instance.allocate(Size, PageSize, FromMemalign);
|
||||
}
|
||||
|
||||
void *scudoMemalign(uptr Alignment, uptr Size) {
|
||||
if (UNLIKELY(!IsPowerOfTwo(Alignment)))
|
||||
return ScudoAllocator::FailureHandler::OnBadRequest();
|
||||
return Instance.allocate(Size, Alignment, FromMemalign);
|
||||
}
|
||||
|
||||
int scudoPosixMemalign(void **MemPtr, uptr Alignment, uptr Size) {
|
||||
if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Alignment % sizeof(void *)) != 0)) {
|
||||
*MemPtr = ScudoAllocator::FailureHandler::OnBadRequest();
|
||||
return EINVAL;
|
||||
}
|
||||
*MemPtr = Instance.allocate(Size, Alignment, FromMemalign);
|
||||
if (!*MemPtr)
|
||||
return ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *scudoAlignedAlloc(uptr Alignment, uptr Size) {
|
||||
// size must be a multiple of the alignment. To avoid a division, we first
|
||||
// make sure that alignment is a power of 2.
|
||||
CHECK(IsPowerOfTwo(Alignment));
|
||||
CHECK_EQ((Size & (Alignment - 1)), 0);
|
||||
// Alignment must be a power of 2, Size must be a multiple of Alignment.
|
||||
if (UNLIKELY(!IsPowerOfTwo(Alignment) || (Size & (Alignment - 1)) != 0))
|
||||
return ScudoAllocator::FailureHandler::OnBadRequest();
|
||||
return Instance.allocate(Size, Alignment, FromMalloc);
|
||||
}
|
||||
|
||||
|
@ -116,6 +116,11 @@ struct AP32 {
|
||||
typedef SizeClassAllocator32<AP32> PrimaryAllocator;
|
||||
#endif // SANITIZER_CAN_USE_ALLOCATOR64
|
||||
|
||||
// __sanitizer::RoundUp has a CHECK that is extraneous for us. Use our own.
|
||||
INLINE uptr RoundUpTo(uptr Size, uptr Boundary) {
|
||||
return (Size + Boundary - 1) & ~(Boundary - 1);
|
||||
}
|
||||
|
||||
#include "scudo_allocator_secondary.h"
|
||||
#include "scudo_allocator_combined.h"
|
||||
|
||||
|
@ -45,7 +45,7 @@ class ScudoCombinedAllocator {
|
||||
|
||||
uptr GetActuallyAllocatedSize(void *Ptr, bool FromPrimary) {
|
||||
if (FromPrimary)
|
||||
return Primary.GetActuallyAllocatedSize(Ptr);
|
||||
return PrimaryAllocator::ClassIdToSize(Primary.GetSizeClass(Ptr));
|
||||
return Secondary.GetActuallyAllocatedSize(Ptr);
|
||||
}
|
||||
|
||||
|
@ -26,13 +26,18 @@ namespace std {
|
||||
struct nothrow_t {};
|
||||
} // namespace std
|
||||
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size) {
|
||||
return scudoMalloc(size, FromNew);
|
||||
void *res = scudoMalloc(size, FromNew);
|
||||
if (UNLIKELY(!res)) DieOnFailure::OnOOM();
|
||||
return res;
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new[](size_t size) {
|
||||
return scudoMalloc(size, FromNewArray);
|
||||
void *res = scudoMalloc(size, FromNewArray);
|
||||
if (UNLIKELY(!res)) DieOnFailure::OnOOM();
|
||||
return res;
|
||||
}
|
||||
CXX_OPERATOR_ATTRIBUTE
|
||||
void *operator new(size_t size, std::nothrow_t const&) {
|
||||
|
@ -45,7 +45,7 @@ static void initOnce() {
|
||||
NumberOfContexts = getNumberOfCPUs();
|
||||
ThreadContexts = reinterpret_cast<ScudoThreadContext *>(
|
||||
MmapOrDie(sizeof(ScudoThreadContext) * NumberOfContexts, __func__));
|
||||
for (int i = 0; i < NumberOfContexts; i++)
|
||||
for (uptr i = 0; i < NumberOfContexts; i++)
|
||||
ThreadContexts[i].init();
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
|
||||
}
|
||||
|
||||
void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) {
|
||||
if (CallocShouldReturnNullDueToOverflow(size, n))
|
||||
if (CheckForCallocOverflow(size, n))
|
||||
return Allocator::FailureHandler::OnBadRequest();
|
||||
void *p = user_alloc(thr, pc, n * size);
|
||||
if (p)
|
||||
|
@ -12,6 +12,7 @@
|
||||
// Interceptors for operators new and delete.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "interception/interception.h"
|
||||
#include "sanitizer_common/sanitizer_allocator.h"
|
||||
#include "sanitizer_common/sanitizer_internal_defs.h"
|
||||
#include "tsan_interceptors.h"
|
||||
|
||||
@ -24,13 +25,15 @@ struct nothrow_t {};
|
||||
DECLARE_REAL(void *, malloc, uptr size)
|
||||
DECLARE_REAL(void, free, void *ptr)
|
||||
|
||||
#define OPERATOR_NEW_BODY(mangled_name) \
|
||||
// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
|
||||
#define OPERATOR_NEW_BODY(mangled_name, nothrow) \
|
||||
if (cur_thread()->in_symbolizer) \
|
||||
return InternalAlloc(size); \
|
||||
void *p = 0; \
|
||||
{ \
|
||||
SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
|
||||
p = user_alloc(thr, pc, size); \
|
||||
if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \
|
||||
} \
|
||||
invoke_malloc_hook(p, size); \
|
||||
return p;
|
||||
@ -38,25 +41,25 @@ DECLARE_REAL(void, free, void *ptr)
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *operator new(__sanitizer::uptr size);
|
||||
void *operator new(__sanitizer::uptr size) {
|
||||
OPERATOR_NEW_BODY(_Znwm);
|
||||
OPERATOR_NEW_BODY(_Znwm, false /*nothrow*/);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *operator new[](__sanitizer::uptr size);
|
||||
void *operator new[](__sanitizer::uptr size) {
|
||||
OPERATOR_NEW_BODY(_Znam);
|
||||
OPERATOR_NEW_BODY(_Znam, false /*nothrow*/);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *operator new(__sanitizer::uptr size, std::nothrow_t const&);
|
||||
void *operator new(__sanitizer::uptr size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t);
|
||||
OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t, true /*nothrow*/);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *operator new[](__sanitizer::uptr size, std::nothrow_t const&);
|
||||
void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
|
||||
OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t);
|
||||
OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/);
|
||||
}
|
||||
|
||||
#define OPERATOR_DELETE_BODY(mangled_name) \
|
||||
|
6
contrib/compiler-rt/lib/xray/xray_always_instrument.txt
Normal file
6
contrib/compiler-rt/lib/xray/xray_always_instrument.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# List of function matchers common to C/C++ applications that make sense to
|
||||
# always instrument. You can use this as an argument to
|
||||
# -fxray-always-instrument=<path> along with your project-specific lists.
|
||||
|
||||
# Always instrument the main function.
|
||||
fun:main
|
6
contrib/compiler-rt/lib/xray/xray_never_instrument.txt
Normal file
6
contrib/compiler-rt/lib/xray/xray_never_instrument.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# List of function matchers common to C/C++ applications that make sense to
|
||||
# never instrument. You can use this as an argument to
|
||||
# -fxray-never-instrument=<path> along with your project-specific lists.
|
||||
|
||||
# Never instrument any function whose symbol starts with __xray.
|
||||
fun:__xray*
|
@ -1176,11 +1176,6 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
|
||||
#define _LIBCPP_AVAILABILITY_ATOMIC_SHARED_PTR \
|
||||
__attribute__((availability(macosx,strict,introduced=10.9))) \
|
||||
__attribute__((availability(ios,strict,introduced=7.0)))
|
||||
#define _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION \
|
||||
__attribute__((availability(macosx,strict,introduced=10.13))) \
|
||||
__attribute__((availability(ios,strict,introduced=11.0))) \
|
||||
__attribute__((availability(tvos,strict,introduced=11.0))) \
|
||||
__attribute__((availability(watchos,strict,introduced=4.0)))
|
||||
#else
|
||||
#define _LIBCPP_AVAILABILITY_SHARED_MUTEX
|
||||
#define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS
|
||||
@ -1192,7 +1187,6 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container(
|
||||
#define _LIBCPP_AVAILABILITY_TYPEINFO_VTABLE
|
||||
#define _LIBCPP_AVAILABILITY_LOCALE_CATEGORY
|
||||
#define _LIBCPP_AVAILABILITY_ATOMIC_SHARED_PTR
|
||||
#define _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION
|
||||
#endif
|
||||
|
||||
// Define availability that depends on _LIBCPP_NO_EXCEPTIONS.
|
||||
|
@ -193,20 +193,20 @@ _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE void operato
|
||||
#endif
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void* operator new(std::size_t __sz, std::align_val_t) _THROW_BAD_ALLOC;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void* operator new(std::size_t __sz, std::align_val_t, const std::nothrow_t&) _NOEXCEPT _NOALIAS;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void operator delete(void* __p, std::align_val_t) _NOEXCEPT;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void operator delete(void* __p, std::align_val_t, const std::nothrow_t&) _NOEXCEPT;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new(std::size_t __sz, std::align_val_t) _THROW_BAD_ALLOC;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new(std::size_t __sz, std::align_val_t, const std::nothrow_t&) _NOEXCEPT _NOALIAS;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::align_val_t) _NOEXCEPT;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete(void* __p, std::align_val_t, const std::nothrow_t&) _NOEXCEPT;
|
||||
#ifndef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void operator delete(void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE void operator delete(void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT;
|
||||
#endif
|
||||
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void* operator new[](std::size_t __sz, std::align_val_t) _THROW_BAD_ALLOC;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void* operator new[](std::size_t __sz, std::align_val_t, const std::nothrow_t&) _NOEXCEPT _NOALIAS;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void operator delete[](void* __p, std::align_val_t) _NOEXCEPT;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void operator delete[](void* __p, std::align_val_t, const std::nothrow_t&) _NOEXCEPT;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new[](std::size_t __sz, std::align_val_t) _THROW_BAD_ALLOC;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new[](std::size_t __sz, std::align_val_t, const std::nothrow_t&) _NOEXCEPT _NOALIAS;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::align_val_t) _NOEXCEPT;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS void operator delete[](void* __p, std::align_val_t, const std::nothrow_t&) _NOEXCEPT;
|
||||
#ifndef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void operator delete[](void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT;
|
||||
_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE void operator delete[](void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -4004,6 +4004,10 @@ basic_string<_CharT, _Traits, _Allocator>::__subscriptable(const const_iterator*
|
||||
|
||||
#endif // _LIBCPP_DEBUG_LEVEL >= 2
|
||||
|
||||
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string<char>)
|
||||
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string<wchar_t>)
|
||||
_LIBCPP_EXTERN_TEMPLATE(string operator+<char, char_traits<char>, allocator<char> >(char const*, string const&))
|
||||
|
||||
#if _LIBCPP_STD_VER > 11
|
||||
// Literal suffixes for basic_string [basic.string.literals]
|
||||
inline namespace literals
|
||||
@ -4037,10 +4041,6 @@ inline namespace literals
|
||||
}
|
||||
#endif
|
||||
|
||||
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string<char>)
|
||||
_LIBCPP_EXTERN_TEMPLATE(class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_string<wchar_t>)
|
||||
_LIBCPP_EXTERN_TEMPLATE(string operator+<char, char_traits<char>, allocator<char> >(char const*, string const&))
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
@ -33,7 +33,7 @@ extern "C" {
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** See llvm::createBBVectorizePass function. */
|
||||
/** DEPRECATED - Use LLVMAddSLPVectorizePass */
|
||||
void LLVMAddBBVectorizePass(LLVMPassManagerRef PM);
|
||||
|
||||
/** See llvm::createLoopVectorizePass function. */
|
||||
|
@ -69,10 +69,15 @@ class AliasSet : public ilist_node<AliasSet> {
|
||||
if (AAInfo == DenseMapInfo<AAMDNodes>::getEmptyKey())
|
||||
// We don't have a AAInfo yet. Set it to NewAAInfo.
|
||||
AAInfo = NewAAInfo;
|
||||
else if (AAInfo != NewAAInfo)
|
||||
else {
|
||||
AAMDNodes Intersection(AAInfo.intersect(NewAAInfo));
|
||||
if (!Intersection) {
|
||||
// NewAAInfo conflicts with AAInfo.
|
||||
AAInfo = DenseMapInfo<AAMDNodes>::getTombstoneKey();
|
||||
|
||||
return SizeChanged;
|
||||
}
|
||||
AAInfo = Intersection;
|
||||
}
|
||||
return SizeChanged;
|
||||
}
|
||||
|
||||
|
58
contrib/llvm/include/llvm/Analysis/CFLAliasAnalysisUtils.h
Normal file
58
contrib/llvm/include/llvm/Analysis/CFLAliasAnalysisUtils.h
Normal file
@ -0,0 +1,58 @@
|
||||
//=- CFLAliasAnalysisUtils.h - Utilities for CFL Alias Analysis ----*- C++-*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// \file
|
||||
// These are the utilities/helpers used by the CFL Alias Analyses available in
|
||||
// tree, i.e. Steensgaard's and Andersens'.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H
|
||||
#define LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H
|
||||
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace cflaa {
|
||||
|
||||
template <typename AAResult> struct FunctionHandle final : public CallbackVH {
|
||||
FunctionHandle(Function *Fn, AAResult *Result)
|
||||
: CallbackVH(Fn), Result(Result) {
|
||||
assert(Fn != nullptr);
|
||||
assert(Result != nullptr);
|
||||
}
|
||||
|
||||
void deleted() override { removeSelfFromCache(); }
|
||||
void allUsesReplacedWith(Value *) override { removeSelfFromCache(); }
|
||||
|
||||
private:
|
||||
AAResult *Result;
|
||||
|
||||
void removeSelfFromCache() {
|
||||
assert(Result != nullptr);
|
||||
auto *Val = getValPtr();
|
||||
Result->evict(cast<Function>(Val));
|
||||
setValPtr(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
static inline const Function *parentFunctionOfValue(const Value *Val) {
|
||||
if (auto *Inst = dyn_cast<Instruction>(Val)) {
|
||||
auto *Bb = Inst->getParent();
|
||||
return Bb->getParent();
|
||||
}
|
||||
|
||||
if (auto *Arg = dyn_cast<Argument>(Val))
|
||||
return Arg->getParent();
|
||||
return nullptr;
|
||||
} // namespace cflaa
|
||||
} // namespace llvm
|
||||
}
|
||||
|
||||
#endif // LLVM_ANALYSIS_CFLALIASANALYSISUTILS_H
|
@ -18,8 +18,8 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/CFLAliasAnalysisUtils.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <forward_list>
|
||||
|
||||
@ -47,7 +47,7 @@ class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
|
||||
return false;
|
||||
}
|
||||
/// Evict the given function from cache
|
||||
void evict(const Function &Fn);
|
||||
void evict(const Function *Fn);
|
||||
|
||||
/// \brief Get the alias summary for the given function
|
||||
/// Return nullptr if the summary is not found or not available
|
||||
@ -57,27 +57,6 @@ class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
|
||||
AliasResult alias(const MemoryLocation &, const MemoryLocation &);
|
||||
|
||||
private:
|
||||
struct FunctionHandle final : public CallbackVH {
|
||||
FunctionHandle(Function *Fn, CFLAndersAAResult *Result)
|
||||
: CallbackVH(Fn), Result(Result) {
|
||||
assert(Fn != nullptr);
|
||||
assert(Result != nullptr);
|
||||
}
|
||||
|
||||
void deleted() override { removeSelfFromCache(); }
|
||||
void allUsesReplacedWith(Value *) override { removeSelfFromCache(); }
|
||||
|
||||
private:
|
||||
CFLAndersAAResult *Result;
|
||||
|
||||
void removeSelfFromCache() {
|
||||
assert(Result != nullptr);
|
||||
auto *Val = getValPtr();
|
||||
Result->evict(*cast<Function>(Val));
|
||||
setValPtr(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Ensures that the given function is available in the cache.
|
||||
/// Returns the appropriate entry from the cache.
|
||||
const Optional<FunctionInfo> &ensureCached(const Function &);
|
||||
@ -97,7 +76,7 @@ class CFLAndersAAResult : public AAResultBase<CFLAndersAAResult> {
|
||||
/// that simply has empty sets.
|
||||
DenseMap<const Function *, Optional<FunctionInfo>> Cache;
|
||||
|
||||
std::forward_list<FunctionHandle> Handles;
|
||||
std::forward_list<cflaa::FunctionHandle<CFLAndersAAResult>> Handles;
|
||||
};
|
||||
|
||||
/// Analysis pass providing a never-invalidated alias analysis result.
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/Analysis/CFLAliasAnalysisUtils.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
@ -85,27 +86,6 @@ class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
|
||||
}
|
||||
|
||||
private:
|
||||
struct FunctionHandle final : public CallbackVH {
|
||||
FunctionHandle(Function *Fn, CFLSteensAAResult *Result)
|
||||
: CallbackVH(Fn), Result(Result) {
|
||||
assert(Fn != nullptr);
|
||||
assert(Result != nullptr);
|
||||
}
|
||||
|
||||
void deleted() override { removeSelfFromCache(); }
|
||||
void allUsesReplacedWith(Value *) override { removeSelfFromCache(); }
|
||||
|
||||
private:
|
||||
CFLSteensAAResult *Result;
|
||||
|
||||
void removeSelfFromCache() {
|
||||
assert(Result != nullptr);
|
||||
auto *Val = getValPtr();
|
||||
Result->evict(cast<Function>(Val));
|
||||
setValPtr(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
const TargetLibraryInfo &TLI;
|
||||
|
||||
/// \brief Cached mapping of Functions to their StratifiedSets.
|
||||
@ -114,7 +94,7 @@ class CFLSteensAAResult : public AAResultBase<CFLSteensAAResult> {
|
||||
/// have any kind of recursion, it is discernable from a function
|
||||
/// that simply has empty sets.
|
||||
DenseMap<Function *, Optional<FunctionInfo>> Cache;
|
||||
std::forward_list<FunctionHandle> Handles;
|
||||
std::forward_list<cflaa::FunctionHandle<CFLSteensAAResult>> Handles;
|
||||
|
||||
FunctionInfo buildSetsFrom(Function *F);
|
||||
};
|
||||
|
@ -86,7 +86,6 @@ class IDFCalculator {
|
||||
private:
|
||||
DominatorTreeBase<BasicBlock> &DT;
|
||||
bool useLiveIn;
|
||||
DenseMap<DomTreeNode *, unsigned> DomLevels;
|
||||
const SmallPtrSetImpl<BasicBlock *> *LiveInBlocks;
|
||||
const SmallPtrSetImpl<BasicBlock *> *DefBlocks;
|
||||
};
|
||||
|
@ -139,7 +139,7 @@ class MemoryAccess
|
||||
|
||||
// Methods for support type inquiry through isa, cast, and
|
||||
// dyn_cast
|
||||
static inline bool classof(const Value *V) {
|
||||
static bool classof(const Value *V) {
|
||||
unsigned ID = V->getValueID();
|
||||
return ID == MemoryUseVal || ID == MemoryPhiVal || ID == MemoryDefVal;
|
||||
}
|
||||
@ -241,7 +241,7 @@ class MemoryUseOrDef : public MemoryAccess {
|
||||
/// \brief Get the access that produces the memory state used by this Use.
|
||||
MemoryAccess *getDefiningAccess() const { return getOperand(0); }
|
||||
|
||||
static inline bool classof(const Value *MA) {
|
||||
static bool classof(const Value *MA) {
|
||||
return MA->getValueID() == MemoryUseVal || MA->getValueID() == MemoryDefVal;
|
||||
}
|
||||
|
||||
@ -297,7 +297,7 @@ class MemoryUse final : public MemoryUseOrDef {
|
||||
// allocate space for exactly one operand
|
||||
void *operator new(size_t s) { return User::operator new(s, 1); }
|
||||
|
||||
static inline bool classof(const Value *MA) {
|
||||
static bool classof(const Value *MA) {
|
||||
return MA->getValueID() == MemoryUseVal;
|
||||
}
|
||||
|
||||
@ -353,7 +353,7 @@ class MemoryDef final : public MemoryUseOrDef {
|
||||
// allocate space for exactly one operand
|
||||
void *operator new(size_t s) { return User::operator new(s, 1); }
|
||||
|
||||
static inline bool classof(const Value *MA) {
|
||||
static bool classof(const Value *MA) {
|
||||
return MA->getValueID() == MemoryDefVal;
|
||||
}
|
||||
|
||||
@ -526,7 +526,7 @@ class MemoryPhi final : public MemoryAccess {
|
||||
return getIncomingValue(Idx);
|
||||
}
|
||||
|
||||
static inline bool classof(const Value *V) {
|
||||
static bool classof(const Value *V) {
|
||||
return V->getValueID() == MemoryPhiVal;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ class Value;
|
||||
///
|
||||
/// It allows reporting when optimizations are performed and when they are not
|
||||
/// along with the reasons for it. Hotness information of the corresponding
|
||||
/// code region can be included in the remark if DiagnosticHotnessRequested is
|
||||
/// code region can be included in the remark if DiagnosticsHotnessRequested is
|
||||
/// enabled in the LLVM context.
|
||||
class OptimizationRemarkEmitter {
|
||||
public:
|
||||
@ -45,10 +45,10 @@ class OptimizationRemarkEmitter {
|
||||
/// analysis pass).
|
||||
///
|
||||
/// Note that this ctor has a very different cost depending on whether
|
||||
/// F->getContext().getDiagnosticHotnessRequested() is on or not. If it's off
|
||||
/// F->getContext().getDiagnosticsHotnessRequested() is on or not. If it's off
|
||||
/// the operation is free.
|
||||
///
|
||||
/// Whereas if DiagnosticHotnessRequested is on, it is fairly expensive
|
||||
/// Whereas if DiagnosticsHotnessRequested is on, it is fairly expensive
|
||||
/// operation since BFI and all its required analyses are computed. This is
|
||||
/// for example useful for CGSCC passes that can't use function analyses
|
||||
/// passes in the old PM.
|
||||
|
@ -37,18 +37,38 @@
|
||||
#ifndef LLVM_ANALYSIS_REGIONINFO_H
|
||||
#define LLVM_ANALYSIS_REGIONINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class DominanceFrontier;
|
||||
class DominatorTree;
|
||||
class Loop;
|
||||
class LoopInfo;
|
||||
struct PostDominatorTree;
|
||||
class Region;
|
||||
template <class RegionTr> class RegionBase;
|
||||
class RegionInfo;
|
||||
template <class RegionTr> class RegionInfoBase;
|
||||
class RegionNode;
|
||||
|
||||
// Class to be specialized for different users of RegionInfo
|
||||
// (i.e. BasicBlocks or MachineBasicBlocks). This is only to avoid needing to
|
||||
// pass around an unreasonable number of template parameters.
|
||||
@ -59,37 +79,23 @@ struct RegionTraits {
|
||||
// RegionT
|
||||
// RegionNodeT
|
||||
// RegionInfoT
|
||||
typedef typename FuncT_::UnknownRegionTypeError BrokenT;
|
||||
using BrokenT = typename FuncT_::UnknownRegionTypeError;
|
||||
};
|
||||
|
||||
class DominatorTree;
|
||||
class DominanceFrontier;
|
||||
class Loop;
|
||||
class LoopInfo;
|
||||
struct PostDominatorTree;
|
||||
class raw_ostream;
|
||||
class Region;
|
||||
template <class RegionTr>
|
||||
class RegionBase;
|
||||
class RegionNode;
|
||||
class RegionInfo;
|
||||
template <class RegionTr>
|
||||
class RegionInfoBase;
|
||||
|
||||
template <>
|
||||
struct RegionTraits<Function> {
|
||||
typedef Function FuncT;
|
||||
typedef BasicBlock BlockT;
|
||||
typedef Region RegionT;
|
||||
typedef RegionNode RegionNodeT;
|
||||
typedef RegionInfo RegionInfoT;
|
||||
typedef DominatorTree DomTreeT;
|
||||
typedef DomTreeNode DomTreeNodeT;
|
||||
typedef DominanceFrontier DomFrontierT;
|
||||
typedef PostDominatorTree PostDomTreeT;
|
||||
typedef Instruction InstT;
|
||||
typedef Loop LoopT;
|
||||
typedef LoopInfo LoopInfoT;
|
||||
using FuncT = Function;
|
||||
using BlockT = BasicBlock;
|
||||
using RegionT = Region;
|
||||
using RegionNodeT = RegionNode;
|
||||
using RegionInfoT = RegionInfo;
|
||||
using DomTreeT = DominatorTree;
|
||||
using DomTreeNodeT = DomTreeNode;
|
||||
using DomFrontierT = DominanceFrontier;
|
||||
using PostDomTreeT = PostDominatorTree;
|
||||
using InstT = Instruction;
|
||||
using LoopT = Loop;
|
||||
using LoopInfoT = LoopInfo;
|
||||
|
||||
static unsigned getNumSuccessors(BasicBlock *BB) {
|
||||
return BB->getTerminator()->getNumSuccessors();
|
||||
@ -113,13 +119,10 @@ class RegionNodeBase {
|
||||
friend class RegionBase<Tr>;
|
||||
|
||||
public:
|
||||
typedef typename Tr::BlockT BlockT;
|
||||
typedef typename Tr::RegionT RegionT;
|
||||
using BlockT = typename Tr::BlockT;
|
||||
using RegionT = typename Tr::RegionT;
|
||||
|
||||
private:
|
||||
RegionNodeBase(const RegionNodeBase &) = delete;
|
||||
const RegionNodeBase &operator=(const RegionNodeBase &) = delete;
|
||||
|
||||
/// This is the entry basic block that starts this region node. If this is a
|
||||
/// BasicBlock RegionNode, then entry is just the basic block, that this
|
||||
/// RegionNode represents. Otherwise it is the entry of this (Sub)RegionNode.
|
||||
@ -150,6 +153,9 @@ class RegionNodeBase {
|
||||
: entry(Entry, isSubRegion), parent(Parent) {}
|
||||
|
||||
public:
|
||||
RegionNodeBase(const RegionNodeBase &) = delete;
|
||||
RegionNodeBase &operator=(const RegionNodeBase &) = delete;
|
||||
|
||||
/// @brief Get the parent Region of this RegionNode.
|
||||
///
|
||||
/// The parent Region is the Region this RegionNode belongs to. If for
|
||||
@ -247,24 +253,22 @@ class RegionNodeBase {
|
||||
/// tree, the second one creates a graphical representation using graphviz.
|
||||
template <class Tr>
|
||||
class RegionBase : public RegionNodeBase<Tr> {
|
||||
typedef typename Tr::FuncT FuncT;
|
||||
typedef typename Tr::BlockT BlockT;
|
||||
typedef typename Tr::RegionInfoT RegionInfoT;
|
||||
typedef typename Tr::RegionT RegionT;
|
||||
typedef typename Tr::RegionNodeT RegionNodeT;
|
||||
typedef typename Tr::DomTreeT DomTreeT;
|
||||
typedef typename Tr::LoopT LoopT;
|
||||
typedef typename Tr::LoopInfoT LoopInfoT;
|
||||
typedef typename Tr::InstT InstT;
|
||||
|
||||
typedef GraphTraits<BlockT *> BlockTraits;
|
||||
typedef GraphTraits<Inverse<BlockT *>> InvBlockTraits;
|
||||
typedef typename BlockTraits::ChildIteratorType SuccIterTy;
|
||||
typedef typename InvBlockTraits::ChildIteratorType PredIterTy;
|
||||
|
||||
friend class RegionInfoBase<Tr>;
|
||||
RegionBase(const RegionBase &) = delete;
|
||||
const RegionBase &operator=(const RegionBase &) = delete;
|
||||
|
||||
using FuncT = typename Tr::FuncT;
|
||||
using BlockT = typename Tr::BlockT;
|
||||
using RegionInfoT = typename Tr::RegionInfoT;
|
||||
using RegionT = typename Tr::RegionT;
|
||||
using RegionNodeT = typename Tr::RegionNodeT;
|
||||
using DomTreeT = typename Tr::DomTreeT;
|
||||
using LoopT = typename Tr::LoopT;
|
||||
using LoopInfoT = typename Tr::LoopInfoT;
|
||||
using InstT = typename Tr::InstT;
|
||||
|
||||
using BlockTraits = GraphTraits<BlockT *>;
|
||||
using InvBlockTraits = GraphTraits<Inverse<BlockT *>>;
|
||||
using SuccIterTy = typename BlockTraits::ChildIteratorType;
|
||||
using PredIterTy = typename InvBlockTraits::ChildIteratorType;
|
||||
|
||||
// Information necessary to manage this Region.
|
||||
RegionInfoT *RI;
|
||||
@ -274,12 +278,12 @@ class RegionBase : public RegionNodeBase<Tr> {
|
||||
// (The entry BasicBlock is part of RegionNode)
|
||||
BlockT *exit;
|
||||
|
||||
typedef std::vector<std::unique_ptr<RegionT>> RegionSet;
|
||||
using RegionSet = std::vector<std::unique_ptr<RegionT>>;
|
||||
|
||||
// The subregions of this region.
|
||||
RegionSet children;
|
||||
|
||||
typedef std::map<BlockT *, std::unique_ptr<RegionNodeT>> BBNodeMapT;
|
||||
using BBNodeMapT = std::map<BlockT *, std::unique_ptr<RegionNodeT>>;
|
||||
|
||||
// Save the BasicBlock RegionNodes that are element of this Region.
|
||||
mutable BBNodeMapT BBNodeMap;
|
||||
@ -308,6 +312,9 @@ class RegionBase : public RegionNodeBase<Tr> {
|
||||
RegionBase(BlockT *Entry, BlockT *Exit, RegionInfoT *RI, DomTreeT *DT,
|
||||
RegionT *Parent = nullptr);
|
||||
|
||||
RegionBase(const RegionBase &) = delete;
|
||||
RegionBase &operator=(const RegionBase &) = delete;
|
||||
|
||||
/// Delete the Region and all its subregions.
|
||||
~RegionBase();
|
||||
|
||||
@ -543,8 +550,8 @@ class RegionBase : public RegionNodeBase<Tr> {
|
||||
///
|
||||
/// These iterators iterator over all subregions of this Region.
|
||||
//@{
|
||||
typedef typename RegionSet::iterator iterator;
|
||||
typedef typename RegionSet::const_iterator const_iterator;
|
||||
using iterator = typename RegionSet::iterator;
|
||||
using const_iterator = typename RegionSet::const_iterator;
|
||||
|
||||
iterator begin() { return children.begin(); }
|
||||
iterator end() { return children.end(); }
|
||||
@ -563,12 +570,13 @@ class RegionBase : public RegionNodeBase<Tr> {
|
||||
class block_iterator_wrapper
|
||||
: public df_iterator<
|
||||
typename std::conditional<IsConst, const BlockT, BlockT>::type *> {
|
||||
typedef df_iterator<
|
||||
typename std::conditional<IsConst, const BlockT, BlockT>::type *> super;
|
||||
using super =
|
||||
df_iterator<
|
||||
typename std::conditional<IsConst, const BlockT, BlockT>::type *>;
|
||||
|
||||
public:
|
||||
typedef block_iterator_wrapper<IsConst> Self;
|
||||
typedef typename super::value_type value_type;
|
||||
using Self = block_iterator_wrapper<IsConst>;
|
||||
using value_type = typename super::value_type;
|
||||
|
||||
// Construct the begin iterator.
|
||||
block_iterator_wrapper(value_type Entry, value_type Exit)
|
||||
@ -592,8 +600,8 @@ class RegionBase : public RegionNodeBase<Tr> {
|
||||
}
|
||||
};
|
||||
|
||||
typedef block_iterator_wrapper<false> block_iterator;
|
||||
typedef block_iterator_wrapper<true> const_block_iterator;
|
||||
using block_iterator = block_iterator_wrapper<false>;
|
||||
using const_block_iterator = block_iterator_wrapper<true>;
|
||||
|
||||
block_iterator block_begin() { return block_iterator(getEntry(), getExit()); }
|
||||
|
||||
@ -604,8 +612,8 @@ class RegionBase : public RegionNodeBase<Tr> {
|
||||
}
|
||||
const_block_iterator block_end() const { return const_block_iterator(); }
|
||||
|
||||
typedef iterator_range<block_iterator> block_range;
|
||||
typedef iterator_range<const_block_iterator> const_block_range;
|
||||
using block_range = iterator_range<block_iterator>;
|
||||
using const_block_range = iterator_range<const_block_iterator>;
|
||||
|
||||
/// @brief Returns a range view of the basic blocks in the region.
|
||||
inline block_range blocks() {
|
||||
@ -626,14 +634,14 @@ class RegionBase : public RegionNodeBase<Tr> {
|
||||
/// are direct children of this Region. It does not iterate over any
|
||||
/// RegionNodes that are also element of a subregion of this Region.
|
||||
//@{
|
||||
typedef df_iterator<RegionNodeT *, df_iterator_default_set<RegionNodeT *>,
|
||||
false, GraphTraits<RegionNodeT *>>
|
||||
element_iterator;
|
||||
using element_iterator =
|
||||
df_iterator<RegionNodeT *, df_iterator_default_set<RegionNodeT *>, false,
|
||||
GraphTraits<RegionNodeT *>>;
|
||||
|
||||
typedef df_iterator<const RegionNodeT *,
|
||||
using const_element_iterator =
|
||||
df_iterator<const RegionNodeT *,
|
||||
df_iterator_default_set<const RegionNodeT *>, false,
|
||||
GraphTraits<const RegionNodeT *>>
|
||||
const_element_iterator;
|
||||
GraphTraits<const RegionNodeT *>>;
|
||||
|
||||
element_iterator element_begin();
|
||||
element_iterator element_end();
|
||||
@ -661,29 +669,26 @@ inline raw_ostream &operator<<(raw_ostream &OS, const RegionNodeBase<Tr> &Node);
|
||||
/// Tree.
|
||||
template <class Tr>
|
||||
class RegionInfoBase {
|
||||
typedef typename Tr::BlockT BlockT;
|
||||
typedef typename Tr::FuncT FuncT;
|
||||
typedef typename Tr::RegionT RegionT;
|
||||
typedef typename Tr::RegionInfoT RegionInfoT;
|
||||
typedef typename Tr::DomTreeT DomTreeT;
|
||||
typedef typename Tr::DomTreeNodeT DomTreeNodeT;
|
||||
typedef typename Tr::PostDomTreeT PostDomTreeT;
|
||||
typedef typename Tr::DomFrontierT DomFrontierT;
|
||||
typedef GraphTraits<BlockT *> BlockTraits;
|
||||
typedef GraphTraits<Inverse<BlockT *>> InvBlockTraits;
|
||||
typedef typename BlockTraits::ChildIteratorType SuccIterTy;
|
||||
typedef typename InvBlockTraits::ChildIteratorType PredIterTy;
|
||||
|
||||
friend class RegionInfo;
|
||||
friend class MachineRegionInfo;
|
||||
typedef DenseMap<BlockT *, BlockT *> BBtoBBMap;
|
||||
typedef DenseMap<BlockT *, RegionT *> BBtoRegionMap;
|
||||
|
||||
using BlockT = typename Tr::BlockT;
|
||||
using FuncT = typename Tr::FuncT;
|
||||
using RegionT = typename Tr::RegionT;
|
||||
using RegionInfoT = typename Tr::RegionInfoT;
|
||||
using DomTreeT = typename Tr::DomTreeT;
|
||||
using DomTreeNodeT = typename Tr::DomTreeNodeT;
|
||||
using PostDomTreeT = typename Tr::PostDomTreeT;
|
||||
using DomFrontierT = typename Tr::DomFrontierT;
|
||||
using BlockTraits = GraphTraits<BlockT *>;
|
||||
using InvBlockTraits = GraphTraits<Inverse<BlockT *>>;
|
||||
using SuccIterTy = typename BlockTraits::ChildIteratorType;
|
||||
using PredIterTy = typename InvBlockTraits::ChildIteratorType;
|
||||
|
||||
using BBtoBBMap = DenseMap<BlockT *, BlockT *>;
|
||||
using BBtoRegionMap = DenseMap<BlockT *, RegionT *>;
|
||||
|
||||
RegionInfoBase();
|
||||
virtual ~RegionInfoBase();
|
||||
|
||||
RegionInfoBase(const RegionInfoBase &) = delete;
|
||||
const RegionInfoBase &operator=(const RegionInfoBase &) = delete;
|
||||
|
||||
RegionInfoBase(RegionInfoBase &&Arg)
|
||||
: DT(std::move(Arg.DT)), PDT(std::move(Arg.PDT)), DF(std::move(Arg.DF)),
|
||||
@ -691,6 +696,7 @@ class RegionInfoBase {
|
||||
BBtoRegion(std::move(Arg.BBtoRegion)) {
|
||||
Arg.wipe();
|
||||
}
|
||||
|
||||
RegionInfoBase &operator=(RegionInfoBase &&RHS) {
|
||||
DT = std::move(RHS.DT);
|
||||
PDT = std::move(RHS.PDT);
|
||||
@ -701,12 +707,14 @@ class RegionInfoBase {
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~RegionInfoBase();
|
||||
|
||||
DomTreeT *DT;
|
||||
PostDomTreeT *PDT;
|
||||
DomFrontierT *DF;
|
||||
|
||||
/// The top level region.
|
||||
RegionT *TopLevelRegion;
|
||||
RegionT *TopLevelRegion = nullptr;
|
||||
|
||||
/// Map every BB to the smallest region, that contains BB.
|
||||
BBtoRegionMap BBtoRegion;
|
||||
@ -785,6 +793,9 @@ class RegionInfoBase {
|
||||
void calculate(FuncT &F);
|
||||
|
||||
public:
|
||||
RegionInfoBase(const RegionInfoBase &) = delete;
|
||||
RegionInfoBase &operator=(const RegionInfoBase &) = delete;
|
||||
|
||||
static bool VerifyRegionInfo;
|
||||
static typename RegionT::PrintStyle printStyle;
|
||||
|
||||
@ -887,21 +898,22 @@ class Region : public RegionBase<RegionTraits<Function>> {
|
||||
|
||||
class RegionInfo : public RegionInfoBase<RegionTraits<Function>> {
|
||||
public:
|
||||
typedef RegionInfoBase<RegionTraits<Function>> Base;
|
||||
using Base = RegionInfoBase<RegionTraits<Function>>;
|
||||
|
||||
explicit RegionInfo();
|
||||
|
||||
~RegionInfo() override;
|
||||
|
||||
RegionInfo(RegionInfo &&Arg) : Base(std::move(static_cast<Base &>(Arg))) {
|
||||
updateRegionTree(*this, TopLevelRegion);
|
||||
}
|
||||
|
||||
RegionInfo &operator=(RegionInfo &&RHS) {
|
||||
Base::operator=(std::move(static_cast<Base &>(RHS)));
|
||||
updateRegionTree(*this, TopLevelRegion);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~RegionInfo() override;
|
||||
|
||||
/// Handle invalidation explicitly.
|
||||
bool invalidate(Function &F, const PreservedAnalyses &PA,
|
||||
FunctionAnalysisManager::Invalidator &);
|
||||
@ -931,8 +943,8 @@ class RegionInfoPass : public FunctionPass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
explicit RegionInfoPass();
|
||||
|
||||
explicit RegionInfoPass();
|
||||
~RegionInfoPass() override;
|
||||
|
||||
RegionInfo &getRegionInfo() { return RI; }
|
||||
@ -953,10 +965,11 @@ class RegionInfoPass : public FunctionPass {
|
||||
/// \brief Analysis pass that exposes the \c RegionInfo for a function.
|
||||
class RegionInfoAnalysis : public AnalysisInfoMixin<RegionInfoAnalysis> {
|
||||
friend AnalysisInfoMixin<RegionInfoAnalysis>;
|
||||
|
||||
static AnalysisKey Key;
|
||||
|
||||
public:
|
||||
typedef RegionInfo Result;
|
||||
using Result = RegionInfo;
|
||||
|
||||
RegionInfo run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
@ -967,6 +980,7 @@ class RegionInfoPrinterPass : public PassInfoMixin<RegionInfoPrinterPass> {
|
||||
|
||||
public:
|
||||
explicit RegionInfoPrinterPass(raw_ostream &OS);
|
||||
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
|
||||
@ -995,8 +1009,8 @@ RegionNodeBase<RegionTraits<Function>>::getNodeAs<Region>() const {
|
||||
template <class Tr>
|
||||
inline raw_ostream &operator<<(raw_ostream &OS,
|
||||
const RegionNodeBase<Tr> &Node) {
|
||||
typedef typename Tr::BlockT BlockT;
|
||||
typedef typename Tr::RegionT RegionT;
|
||||
using BlockT = typename Tr::BlockT;
|
||||
using RegionT = typename Tr::RegionT;
|
||||
|
||||
if (Node.isSubRegion())
|
||||
return OS << Node.template getNodeAs<RegionT>()->getNameStr();
|
||||
@ -1008,5 +1022,6 @@ extern template class RegionBase<RegionTraits<Function>>;
|
||||
extern template class RegionNodeBase<RegionTraits<Function>>;
|
||||
extern template class RegionInfoBase<RegionTraits<Function>>;
|
||||
|
||||
} // End llvm namespace
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_ANALYSIS_REGIONINFO_H
|
||||
|
@ -12,7 +12,11 @@
|
||||
#ifndef LLVM_ANALYSIS_REGIONINFOIMPL_H
|
||||
#define LLVM_ANALYSIS_REGIONINFOIMPL_H
|
||||
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Analysis/DominanceFrontier.h"
|
||||
#include "llvm/Analysis/LoopInfo.h"
|
||||
#include "llvm/Analysis/PostDominators.h"
|
||||
@ -20,9 +24,15 @@
|
||||
#include "llvm/Analysis/RegionIterator.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -303,7 +313,8 @@ RegionBase<Tr>::element_end() const {
|
||||
|
||||
template <class Tr>
|
||||
typename Tr::RegionT *RegionBase<Tr>::getSubRegionNode(BlockT *BB) const {
|
||||
typedef typename Tr::RegionT RegionT;
|
||||
using RegionT = typename Tr::RegionT;
|
||||
|
||||
RegionT *R = RI->getRegionFor(BB);
|
||||
|
||||
if (!R || R == this)
|
||||
@ -330,7 +341,8 @@ typename Tr::RegionNodeT *RegionBase<Tr>::getBBNode(BlockT *BB) const {
|
||||
if (at == BBNodeMap.end()) {
|
||||
auto Deconst = const_cast<RegionBase<Tr> *>(this);
|
||||
typename BBNodeMapT::value_type V = {
|
||||
BB, make_unique<RegionNodeT>(static_cast<RegionT *>(Deconst), BB)};
|
||||
BB,
|
||||
llvm::make_unique<RegionNodeT>(static_cast<RegionT *>(Deconst), BB)};
|
||||
at = BBNodeMap.insert(std::move(V)).first;
|
||||
}
|
||||
return at->second.get();
|
||||
@ -357,7 +369,7 @@ void RegionBase<Tr>::transferChildrenTo(RegionT *To) {
|
||||
template <class Tr>
|
||||
void RegionBase<Tr>::addSubRegion(RegionT *SubRegion, bool moveChildren) {
|
||||
assert(!SubRegion->parent && "SubRegion already has a parent!");
|
||||
assert(find_if(*this,
|
||||
assert(llvm::find_if(*this,
|
||||
[&](const std::unique_ptr<RegionT> &R) {
|
||||
return R.get() == SubRegion;
|
||||
}) == children.end() &&
|
||||
@ -402,7 +414,7 @@ typename Tr::RegionT *RegionBase<Tr>::removeSubRegion(RegionT *Child) {
|
||||
assert(Child->parent == this && "Child is not a child of this region!");
|
||||
Child->parent = nullptr;
|
||||
typename RegionSet::iterator I =
|
||||
find_if(children, [&](const std::unique_ptr<RegionT> &R) {
|
||||
llvm::find_if(children, [&](const std::unique_ptr<RegionT> &R) {
|
||||
return R.get() == Child;
|
||||
});
|
||||
assert(I != children.end() && "Region does not exit. Unable to remove.");
|
||||
@ -505,8 +517,7 @@ void RegionBase<Tr>::clearNodeCache() {
|
||||
//
|
||||
|
||||
template <class Tr>
|
||||
RegionInfoBase<Tr>::RegionInfoBase()
|
||||
: TopLevelRegion(nullptr) {}
|
||||
RegionInfoBase<Tr>::RegionInfoBase() = default;
|
||||
|
||||
template <class Tr>
|
||||
RegionInfoBase<Tr>::~RegionInfoBase() {
|
||||
@ -543,7 +554,8 @@ bool RegionInfoBase<Tr>::isCommonDomFrontier(BlockT *BB, BlockT *entry,
|
||||
template <class Tr>
|
||||
bool RegionInfoBase<Tr>::isRegion(BlockT *entry, BlockT *exit) const {
|
||||
assert(entry && exit && "entry and exit must not be null!");
|
||||
typedef typename DomFrontierT::DomSetType DST;
|
||||
|
||||
using DST = typename DomFrontierT::DomSetType;
|
||||
|
||||
DST *entrySuccs = &DF->find(entry)->second;
|
||||
|
||||
@ -689,7 +701,8 @@ void RegionInfoBase<Tr>::findRegionsWithEntry(BlockT *entry,
|
||||
|
||||
template <class Tr>
|
||||
void RegionInfoBase<Tr>::scanForRegions(FuncT &F, BBtoBBMap *ShortCut) {
|
||||
typedef typename std::add_pointer<FuncT>::type FuncPtrT;
|
||||
using FuncPtrT = typename std::add_pointer<FuncT>::type;
|
||||
|
||||
BlockT *entry = GraphTraits<FuncPtrT>::getEntryNode(&F);
|
||||
DomTreeNodeT *N = DT->getNode(entry);
|
||||
|
||||
@ -876,7 +889,7 @@ RegionInfoBase<Tr>::getCommonRegion(SmallVectorImpl<BlockT *> &BBs) const {
|
||||
|
||||
template <class Tr>
|
||||
void RegionInfoBase<Tr>::calculate(FuncT &F) {
|
||||
typedef typename std::add_pointer<FuncT>::type FuncPtrT;
|
||||
using FuncPtrT = typename std::add_pointer<FuncT>::type;
|
||||
|
||||
// ShortCut a function where for every BB the exit of the largest region
|
||||
// starting with BB is stored. These regions can be threated as single BBS.
|
||||
@ -892,4 +905,4 @@ void RegionInfoBase<Tr>::calculate(FuncT &F) {
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ANALYSIS_REGIONINFOIMPL_H
|
||||
|
@ -8,17 +8,23 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This file defines the iterators to iterate over the elements of a Region.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ANALYSIS_REGIONITERATOR_H
|
||||
#define LLVM_ANALYSIS_REGIONITERATOR_H
|
||||
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/RegionInfo.h"
|
||||
#include "llvm/IR/CFG.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BasicBlock;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// @brief Hierarchical RegionNode successor iterator.
|
||||
///
|
||||
@ -33,10 +39,9 @@ namespace llvm {
|
||||
template <class NodeRef, class BlockT, class RegionT>
|
||||
class RNSuccIterator
|
||||
: public std::iterator<std::forward_iterator_tag, NodeRef> {
|
||||
typedef std::iterator<std::forward_iterator_tag, NodeRef> super;
|
||||
|
||||
typedef GraphTraits<BlockT*> BlockTraits;
|
||||
typedef typename BlockTraits::ChildIteratorType SuccIterTy;
|
||||
using super = std::iterator<std::forward_iterator_tag, NodeRef>;
|
||||
using BlockTraits = GraphTraits<BlockT *>;
|
||||
using SuccIterTy = typename BlockTraits::ChildIteratorType;
|
||||
|
||||
// The iterator works in two modes, bb mode or region mode.
|
||||
enum ItMode {
|
||||
@ -92,16 +97,15 @@ class RNSuccIterator
|
||||
inline bool isExit(BlockT* BB) const {
|
||||
return getNode()->getParent()->getExit() == BB;
|
||||
}
|
||||
public:
|
||||
typedef RNSuccIterator<NodeRef, BlockT, RegionT> Self;
|
||||
|
||||
typedef typename super::value_type value_type;
|
||||
public:
|
||||
using Self = RNSuccIterator<NodeRef, BlockT, RegionT>;
|
||||
using value_type = typename super::value_type;
|
||||
|
||||
/// @brief Create begin iterator of a RegionNode.
|
||||
inline RNSuccIterator(NodeRef node)
|
||||
: Node(node, node->isSubRegion() ? ItRgBegin : ItBB),
|
||||
BItor(BlockTraits::child_begin(node->getEntry())) {
|
||||
|
||||
// Skip the exit block
|
||||
if (!isRegionMode())
|
||||
while (BlockTraits::child_end(node->getEntry()) != BItor && isExit(*BItor))
|
||||
@ -153,7 +157,6 @@ class RNSuccIterator
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// @brief Flat RegionNode iterator.
|
||||
///
|
||||
@ -163,16 +166,16 @@ class RNSuccIterator
|
||||
template <class NodeRef, class BlockT, class RegionT>
|
||||
class RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT>
|
||||
: public std::iterator<std::forward_iterator_tag, NodeRef> {
|
||||
typedef std::iterator<std::forward_iterator_tag, NodeRef> super;
|
||||
typedef GraphTraits<BlockT*> BlockTraits;
|
||||
typedef typename BlockTraits::ChildIteratorType SuccIterTy;
|
||||
using super = std::iterator<std::forward_iterator_tag, NodeRef>;
|
||||
using BlockTraits = GraphTraits<BlockT *>;
|
||||
using SuccIterTy = typename BlockTraits::ChildIteratorType;
|
||||
|
||||
NodeRef Node;
|
||||
SuccIterTy Itor;
|
||||
|
||||
public:
|
||||
typedef RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT> Self;
|
||||
typedef typename super::value_type value_type;
|
||||
using Self = RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT>;
|
||||
using value_type = typename super::value_type;
|
||||
|
||||
/// @brief Create the iterator from a RegionNode.
|
||||
///
|
||||
@ -255,8 +258,8 @@ inline RNSuccIterator<NodeRef, BlockT, RegionT> succ_end(NodeRef Node) {
|
||||
|
||||
#define RegionNodeGraphTraits(NodeT, BlockT, RegionT) \
|
||||
template <> struct GraphTraits<NodeT *> { \
|
||||
typedef NodeT *NodeRef; \
|
||||
typedef RNSuccIterator<NodeRef, BlockT, RegionT> ChildIteratorType; \
|
||||
using NodeRef = NodeT *; \
|
||||
using ChildIteratorType = RNSuccIterator<NodeRef, BlockT, RegionT>; \
|
||||
static NodeRef getEntryNode(NodeRef N) { return N; } \
|
||||
static inline ChildIteratorType child_begin(NodeRef N) { \
|
||||
return RNSuccIterator<NodeRef, BlockT, RegionT>(N); \
|
||||
@ -266,9 +269,9 @@ inline RNSuccIterator<NodeRef, BlockT, RegionT> succ_end(NodeRef Node) {
|
||||
} \
|
||||
}; \
|
||||
template <> struct GraphTraits<FlatIt<NodeT *>> { \
|
||||
typedef NodeT *NodeRef; \
|
||||
typedef RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT> \
|
||||
ChildIteratorType; \
|
||||
using NodeRef = NodeT *; \
|
||||
using ChildIteratorType = \
|
||||
RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT>; \
|
||||
static NodeRef getEntryNode(NodeRef N) { return N; } \
|
||||
static inline ChildIteratorType child_begin(NodeRef N) { \
|
||||
return RNSuccIterator<FlatIt<NodeRef>, BlockT, RegionT>(N); \
|
||||
@ -280,7 +283,7 @@ inline RNSuccIterator<NodeRef, BlockT, RegionT> succ_end(NodeRef Node) {
|
||||
|
||||
#define RegionGraphTraits(RegionT, NodeT) \
|
||||
template <> struct GraphTraits<RegionT *> : public GraphTraits<NodeT *> { \
|
||||
typedef df_iterator<NodeRef> nodes_iterator; \
|
||||
using nodes_iterator = df_iterator<NodeRef>; \
|
||||
static NodeRef getEntryNode(RegionT *R) { \
|
||||
return R->getNode(R->getEntry()); \
|
||||
} \
|
||||
@ -294,9 +297,9 @@ inline RNSuccIterator<NodeRef, BlockT, RegionT> succ_end(NodeRef Node) {
|
||||
template <> \
|
||||
struct GraphTraits<FlatIt<RegionT *>> \
|
||||
: public GraphTraits<FlatIt<NodeT *>> { \
|
||||
typedef df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false, \
|
||||
GraphTraits<FlatIt<NodeRef>>> \
|
||||
nodes_iterator; \
|
||||
using nodes_iterator = \
|
||||
df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false, \
|
||||
GraphTraits<FlatIt<NodeRef>>>; \
|
||||
static NodeRef getEntryNode(RegionT *R) { \
|
||||
return R->getBBNode(R->getEntry()); \
|
||||
} \
|
||||
@ -315,17 +318,19 @@ RegionGraphTraits(Region, RegionNode);
|
||||
RegionGraphTraits(const Region, const RegionNode);
|
||||
|
||||
template <> struct GraphTraits<RegionInfo*>
|
||||
: public GraphTraits<FlatIt<RegionNode*> > {
|
||||
typedef df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
|
||||
GraphTraits<FlatIt<NodeRef>>>
|
||||
nodes_iterator;
|
||||
: public GraphTraits<FlatIt<RegionNode*>> {
|
||||
using nodes_iterator =
|
||||
df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
|
||||
GraphTraits<FlatIt<NodeRef>>>;
|
||||
|
||||
static NodeRef getEntryNode(RegionInfo *RI) {
|
||||
return GraphTraits<FlatIt<Region*> >::getEntryNode(RI->getTopLevelRegion());
|
||||
return GraphTraits<FlatIt<Region*>>::getEntryNode(RI->getTopLevelRegion());
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_begin(RegionInfo* RI) {
|
||||
return nodes_iterator::begin(getEntryNode(RI));
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(RegionInfo *RI) {
|
||||
return nodes_iterator::end(getEntryNode(RI));
|
||||
}
|
||||
@ -333,21 +338,23 @@ template <> struct GraphTraits<RegionInfo*>
|
||||
|
||||
template <> struct GraphTraits<RegionInfoPass*>
|
||||
: public GraphTraits<RegionInfo *> {
|
||||
typedef df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
|
||||
GraphTraits<FlatIt<NodeRef>>>
|
||||
nodes_iterator;
|
||||
using nodes_iterator =
|
||||
df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
|
||||
GraphTraits<FlatIt<NodeRef>>>;
|
||||
|
||||
static NodeRef getEntryNode(RegionInfoPass *RI) {
|
||||
return GraphTraits<RegionInfo*>::getEntryNode(&RI->getRegionInfo());
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_begin(RegionInfoPass* RI) {
|
||||
return GraphTraits<RegionInfo*>::nodes_begin(&RI->getRegionInfo());
|
||||
}
|
||||
|
||||
static nodes_iterator nodes_end(RegionInfoPass *RI) {
|
||||
return GraphTraits<RegionInfo*>::nodes_end(&RI->getRegionInfo());
|
||||
}
|
||||
};
|
||||
|
||||
} // End namespace llvm
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_ANALYSIS_REGIONITERATOR_H
|
||||
|
@ -262,7 +262,7 @@ class SCEVEqualPredicate final : public SCEVPredicate {
|
||||
const SCEVConstant *getRHS() const { return RHS; }
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEVPredicate *P) {
|
||||
static bool classof(const SCEVPredicate *P) {
|
||||
return P->getKind() == P_Equal;
|
||||
}
|
||||
};
|
||||
@ -360,7 +360,7 @@ class SCEVWrapPredicate final : public SCEVPredicate {
|
||||
bool isAlwaysTrue() const override;
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEVPredicate *P) {
|
||||
static bool classof(const SCEVPredicate *P) {
|
||||
return P->getKind() == P_Wrap;
|
||||
}
|
||||
};
|
||||
@ -406,7 +406,7 @@ class SCEVUnionPredicate final : public SCEVPredicate {
|
||||
unsigned getComplexity() const override { return Preds.size(); }
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEVPredicate *P) {
|
||||
static bool classof(const SCEVPredicate *P) {
|
||||
return P->getKind() == P_Union;
|
||||
}
|
||||
};
|
||||
@ -1197,20 +1197,8 @@ class ScalarEvolution {
|
||||
const SCEV *getConstant(const APInt &Val);
|
||||
const SCEV *getConstant(Type *Ty, uint64_t V, bool isSigned = false);
|
||||
const SCEV *getTruncateExpr(const SCEV *Op, Type *Ty);
|
||||
|
||||
typedef SmallDenseMap<std::pair<const SCEV *, Type *>, const SCEV *, 8>
|
||||
ExtendCacheTy;
|
||||
const SCEV *getZeroExtendExpr(const SCEV *Op, Type *Ty);
|
||||
const SCEV *getZeroExtendExprCached(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache);
|
||||
const SCEV *getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache);
|
||||
|
||||
const SCEV *getSignExtendExpr(const SCEV *Op, Type *Ty);
|
||||
const SCEV *getSignExtendExprCached(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache);
|
||||
const SCEV *getSignExtendExprImpl(const SCEV *Op, Type *Ty,
|
||||
ExtendCacheTy &Cache);
|
||||
const SCEV *getZeroExtendExpr(const SCEV *Op, Type *Ty, unsigned Depth = 0);
|
||||
const SCEV *getSignExtendExpr(const SCEV *Op, Type *Ty, unsigned Depth = 0);
|
||||
const SCEV *getAnyExtendExpr(const SCEV *Op, Type *Ty);
|
||||
const SCEV *getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
|
||||
SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap,
|
||||
|
@ -46,7 +46,7 @@ namespace llvm {
|
||||
Type *getType() const { return V->getType(); }
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scConstant;
|
||||
}
|
||||
};
|
||||
@ -65,7 +65,7 @@ namespace llvm {
|
||||
Type *getType() const { return Ty; }
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scTruncate ||
|
||||
S->getSCEVType() == scZeroExtend ||
|
||||
S->getSCEVType() == scSignExtend;
|
||||
@ -82,7 +82,7 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scTruncate;
|
||||
}
|
||||
};
|
||||
@ -97,7 +97,7 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scZeroExtend;
|
||||
}
|
||||
};
|
||||
@ -112,7 +112,7 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scSignExtend;
|
||||
}
|
||||
};
|
||||
@ -167,7 +167,7 @@ namespace llvm {
|
||||
}
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scAddExpr ||
|
||||
S->getSCEVType() == scMulExpr ||
|
||||
S->getSCEVType() == scSMaxExpr ||
|
||||
@ -185,7 +185,7 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scAddExpr ||
|
||||
S->getSCEVType() == scMulExpr ||
|
||||
S->getSCEVType() == scSMaxExpr ||
|
||||
@ -217,7 +217,7 @@ namespace llvm {
|
||||
}
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scAddExpr;
|
||||
}
|
||||
};
|
||||
@ -234,7 +234,7 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scMulExpr;
|
||||
}
|
||||
};
|
||||
@ -263,7 +263,7 @@ namespace llvm {
|
||||
}
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scUDivExpr;
|
||||
}
|
||||
};
|
||||
@ -345,7 +345,7 @@ namespace llvm {
|
||||
}
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scAddRecExpr;
|
||||
}
|
||||
};
|
||||
@ -363,7 +363,7 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scSMaxExpr;
|
||||
}
|
||||
};
|
||||
@ -382,7 +382,7 @@ namespace llvm {
|
||||
|
||||
public:
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scUMaxExpr;
|
||||
}
|
||||
};
|
||||
@ -428,7 +428,7 @@ namespace llvm {
|
||||
Type *getType() const { return getValPtr()->getType(); }
|
||||
|
||||
/// Methods for support type inquiry through isa, cast, and dyn_cast:
|
||||
static inline bool classof(const SCEV *S) {
|
||||
static bool classof(const SCEV *S) {
|
||||
return S->getSCEVType() == scUnknown;
|
||||
}
|
||||
};
|
||||
|
@ -216,9 +216,23 @@ class TargetTransformInfo {
|
||||
/// other context they may not be folded. This routine can distinguish such
|
||||
/// cases.
|
||||
///
|
||||
/// \p Operands is a list of operands which can be a result of transformations
|
||||
/// of the current operands. The number of the operands on the list must equal
|
||||
/// to the number of the current operands the IR user has. Their order on the
|
||||
/// list must be the same as the order of the current operands the IR user
|
||||
/// has.
|
||||
///
|
||||
/// The returned cost is defined in terms of \c TargetCostConstants, see its
|
||||
/// comments for a detailed explanation of the cost values.
|
||||
int getUserCost(const User *U) const;
|
||||
int getUserCost(const User *U, ArrayRef<const Value *> Operands) const;
|
||||
|
||||
/// \brief This is a helper function which calls the two-argument getUserCost
|
||||
/// with \p Operands which are the current operands U has.
|
||||
int getUserCost(const User *U) const {
|
||||
SmallVector<const Value *, 4> Operands(U->value_op_begin(),
|
||||
U->value_op_end());
|
||||
return getUserCost(U, Operands);
|
||||
}
|
||||
|
||||
/// \brief Return true if branch divergence exists.
|
||||
///
|
||||
@ -366,7 +380,8 @@ class TargetTransformInfo {
|
||||
/// \brief Get target-customized preferences for the generic loop unrolling
|
||||
/// transformation. The caller will initialize UP with the current
|
||||
/// target-independent defaults.
|
||||
void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) const;
|
||||
void getUnrollingPreferences(Loop *L, ScalarEvolution &,
|
||||
UnrollingPreferences &UP) const;
|
||||
|
||||
/// @}
|
||||
|
||||
@ -823,13 +838,15 @@ class TargetTransformInfo::Concept {
|
||||
ArrayRef<const Value *> Arguments) = 0;
|
||||
virtual unsigned getEstimatedNumberOfCaseClusters(const SwitchInst &SI,
|
||||
unsigned &JTSize) = 0;
|
||||
virtual int getUserCost(const User *U) = 0;
|
||||
virtual int
|
||||
getUserCost(const User *U, ArrayRef<const Value *> Operands) = 0;
|
||||
virtual bool hasBranchDivergence() = 0;
|
||||
virtual bool isSourceOfDivergence(const Value *V) = 0;
|
||||
virtual bool isAlwaysUniform(const Value *V) = 0;
|
||||
virtual unsigned getFlatAddressSpace() = 0;
|
||||
virtual bool isLoweredToCall(const Function *F) = 0;
|
||||
virtual void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) = 0;
|
||||
virtual void getUnrollingPreferences(Loop *L, ScalarEvolution &,
|
||||
UnrollingPreferences &UP) = 0;
|
||||
virtual bool isLegalAddImmediate(int64_t Imm) = 0;
|
||||
virtual bool isLegalICmpImmediate(int64_t Imm) = 0;
|
||||
virtual bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV,
|
||||
@ -998,7 +1015,9 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
ArrayRef<const Value *> Arguments) override {
|
||||
return Impl.getIntrinsicCost(IID, RetTy, Arguments);
|
||||
}
|
||||
int getUserCost(const User *U) override { return Impl.getUserCost(U); }
|
||||
int getUserCost(const User *U, ArrayRef<const Value *> Operands) override {
|
||||
return Impl.getUserCost(U, Operands);
|
||||
}
|
||||
bool hasBranchDivergence() override { return Impl.hasBranchDivergence(); }
|
||||
bool isSourceOfDivergence(const Value *V) override {
|
||||
return Impl.isSourceOfDivergence(V);
|
||||
@ -1015,8 +1034,9 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
|
||||
bool isLoweredToCall(const Function *F) override {
|
||||
return Impl.isLoweredToCall(F);
|
||||
}
|
||||
void getUnrollingPreferences(Loop *L, UnrollingPreferences &UP) override {
|
||||
return Impl.getUnrollingPreferences(L, UP);
|
||||
void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
|
||||
UnrollingPreferences &UP) override {
|
||||
return Impl.getUnrollingPreferences(L, SE, UP);
|
||||
}
|
||||
bool isLegalAddImmediate(int64_t Imm) override {
|
||||
return Impl.isLegalAddImmediate(Imm);
|
||||
|
@ -217,7 +217,8 @@ class TargetTransformInfoImplBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
void getUnrollingPreferences(Loop *, TTI::UnrollingPreferences &) {}
|
||||
void getUnrollingPreferences(Loop *, ScalarEvolution &,
|
||||
TTI::UnrollingPreferences &) {}
|
||||
|
||||
bool isLegalAddImmediate(int64_t Imm) { return false; }
|
||||
|
||||
@ -684,14 +685,14 @@ class TargetTransformInfoImplCRTPBase : public TargetTransformInfoImplBase {
|
||||
return static_cast<T *>(this)->getIntrinsicCost(IID, RetTy, ParamTys);
|
||||
}
|
||||
|
||||
unsigned getUserCost(const User *U) {
|
||||
unsigned getUserCost(const User *U, ArrayRef<const Value *> Operands) {
|
||||
if (isa<PHINode>(U))
|
||||
return TTI::TCC_Free; // Model all PHI nodes as free.
|
||||
|
||||
if (const GEPOperator *GEP = dyn_cast<GEPOperator>(U)) {
|
||||
SmallVector<Value *, 4> Indices(GEP->idx_begin(), GEP->idx_end());
|
||||
return static_cast<T *>(this)->getGEPCost(
|
||||
GEP->getSourceElementType(), GEP->getPointerOperand(), Indices);
|
||||
return static_cast<T *>(this)->getGEPCost(GEP->getSourceElementType(),
|
||||
GEP->getPointerOperand(),
|
||||
Operands.drop_front());
|
||||
}
|
||||
|
||||
if (auto CS = ImmutableCallSite(U)) {
|
||||
|
@ -382,7 +382,7 @@ enum RelocationTypesARM64 {
|
||||
IMAGE_REL_ARM64_ADDR32 = 0x0001,
|
||||
IMAGE_REL_ARM64_ADDR32NB = 0x0002,
|
||||
IMAGE_REL_ARM64_BRANCH26 = 0x0003,
|
||||
IMAGE_REL_ARM64_PAGEBASE_REL2 = 0x0004,
|
||||
IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004,
|
||||
IMAGE_REL_ARM64_REL21 = 0x0005,
|
||||
IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006,
|
||||
IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007,
|
||||
|
@ -62,6 +62,9 @@ enum LLVMConstants : uint32_t {
|
||||
const uint32_t DW_CIE_ID = UINT32_MAX;
|
||||
const uint64_t DW64_CIE_ID = UINT64_MAX;
|
||||
|
||||
// Identifier of an invalid DIE offset in the .debug_info section.
|
||||
const uint32_t DW_INVALID_OFFSET = UINT32_MAX;
|
||||
|
||||
enum Tag : uint16_t {
|
||||
#define HANDLE_DW_TAG(ID, NAME, VERSION, VENDOR) DW_TAG_##NAME = ID,
|
||||
#include "llvm/BinaryFormat/Dwarf.def"
|
||||
|
@ -112,6 +112,11 @@ struct WasmRelocation {
|
||||
int64_t Addend; // A value to add to the symbol.
|
||||
};
|
||||
|
||||
struct WasmLinkingData {
|
||||
uint32_t DataSize;
|
||||
uint32_t DataAlignment;
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
WASM_SEC_CUSTOM = 0, // Custom / User-defined section
|
||||
WASM_SEC_TYPE = 1, // Function signature declarations
|
||||
@ -177,6 +182,8 @@ enum class ValType {
|
||||
enum : unsigned {
|
||||
WASM_STACK_POINTER = 0x1,
|
||||
WASM_SYMBOL_INFO = 0x2,
|
||||
WASM_DATA_SIZE = 0x3,
|
||||
WASM_DATA_ALIGNMENT = 0x4,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
|
@ -111,9 +111,14 @@ namespace llvm {
|
||||
|
||||
struct BitcodeFileContents {
|
||||
std::vector<BitcodeModule> Mods;
|
||||
StringRef Symtab, StrtabForSymtab;
|
||||
};
|
||||
|
||||
/// Returns the contents of a bitcode file.
|
||||
/// Returns the contents of a bitcode file. This includes the raw contents of
|
||||
/// the symbol table embedded in the bitcode file. Clients which require a
|
||||
/// symbol table should prefer to use irsymtab::read instead of this function
|
||||
/// because it creates a reader for the irsymtab and handles upgrading bitcode
|
||||
/// files without a symbol table or with an old symbol table.
|
||||
Expected<BitcodeFileContents> getBitcodeFileContents(MemoryBufferRef Buffer);
|
||||
|
||||
/// Returns a list of modules in the specified bitcode buffer.
|
||||
|
@ -28,18 +28,34 @@ namespace llvm {
|
||||
std::unique_ptr<BitstreamWriter> Stream;
|
||||
|
||||
StringTableBuilder StrtabBuilder{StringTableBuilder::RAW};
|
||||
bool WroteStrtab = false;
|
||||
|
||||
// Owns any strings created by the irsymtab writer until we create the
|
||||
// string table.
|
||||
BumpPtrAllocator Alloc;
|
||||
|
||||
bool WroteStrtab = false, WroteSymtab = false;
|
||||
|
||||
void writeBlob(unsigned Block, unsigned Record, StringRef Blob);
|
||||
|
||||
std::vector<Module *> Mods;
|
||||
|
||||
public:
|
||||
/// Create a BitcodeWriter that writes to Buffer.
|
||||
BitcodeWriter(SmallVectorImpl<char> &Buffer);
|
||||
|
||||
~BitcodeWriter();
|
||||
|
||||
/// Attempt to write a symbol table to the bitcode file. This must be called
|
||||
/// at most once after all modules have been written.
|
||||
///
|
||||
/// A reader does not require a symbol table to interpret a bitcode file;
|
||||
/// the symbol table is needed only to improve link-time performance. So
|
||||
/// this function may decide not to write a symbol table. It may so decide
|
||||
/// if, for example, the target is unregistered or the IR is malformed.
|
||||
void writeSymtab();
|
||||
|
||||
/// Write the bitcode file's string table. This must be called exactly once
|
||||
/// after all modules have been written.
|
||||
/// after all modules and the optional symbol table have been written.
|
||||
void writeStrtab();
|
||||
|
||||
/// Copy the string table for another module into this bitcode file. This
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
namespace llvm {
|
||||
namespace bitc {
|
||||
// The only top-level block types are MODULE, IDENTIFICATION and STRTAB.
|
||||
// The only top-level block types are MODULE, IDENTIFICATION, STRTAB and SYMTAB.
|
||||
enum BlockIDs {
|
||||
// Blocks
|
||||
MODULE_BLOCK_ID = FIRST_APPLICATION_BLOCKID,
|
||||
@ -57,6 +57,8 @@ enum BlockIDs {
|
||||
STRTAB_BLOCK_ID,
|
||||
|
||||
FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID,
|
||||
|
||||
SYMTAB_BLOCK_ID,
|
||||
};
|
||||
|
||||
/// Identification block contains a string that describes the producer details,
|
||||
@ -571,6 +573,10 @@ enum StrtabCodes {
|
||||
STRTAB_BLOB = 1,
|
||||
};
|
||||
|
||||
enum SymtabCodes {
|
||||
SYMTAB_BLOB = 1,
|
||||
};
|
||||
|
||||
} // End bitc namespace
|
||||
} // End llvm namespace
|
||||
|
||||
|
@ -277,7 +277,8 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
|
||||
|
||||
unsigned getInliningThresholdMultiplier() { return 1; }
|
||||
|
||||
void getUnrollingPreferences(Loop *L, TTI::UnrollingPreferences &UP) {
|
||||
void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
|
||||
TTI::UnrollingPreferences &UP) {
|
||||
// This unrolling functionality is target independent, but to provide some
|
||||
// motivation for its intended use, for x86:
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/GlobalISel/CallLowering.h - Call lowering --*- C++ -*-===//
|
||||
//===- llvm/CodeGen/GlobalISel/CallLowering.h - Call lowering ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -15,21 +15,31 @@
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_CALLLOWERING_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_CALLLOWERING_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/CodeGen/CallingConvLower.h"
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/CodeGen/MachineValueType.h"
|
||||
#include "llvm/IR/CallSite.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Target/TargetCallingConv.h"
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
// Forward declarations.
|
||||
|
||||
class DataLayout;
|
||||
class Function;
|
||||
class MachineIRBuilder;
|
||||
class MachineOperand;
|
||||
struct MachinePointerInfo;
|
||||
class MachineRegisterInfo;
|
||||
class TargetLowering;
|
||||
class Type;
|
||||
class Value;
|
||||
|
||||
class CallLowering {
|
||||
const TargetLowering *TLI;
|
||||
|
||||
public:
|
||||
struct ArgInfo {
|
||||
unsigned Reg;
|
||||
@ -49,6 +59,12 @@ class CallLowering {
|
||||
/// arugment should go, exactly what happens can vary slightly. This
|
||||
/// class abstracts the differences.
|
||||
struct ValueHandler {
|
||||
ValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
|
||||
CCAssignFn *AssignFn)
|
||||
: MIRBuilder(MIRBuilder), MRI(MRI), AssignFn(AssignFn) {}
|
||||
|
||||
virtual ~ValueHandler() = default;
|
||||
|
||||
/// Materialize a VReg containing the address of the specified
|
||||
/// stack-based object. This is either based on a FrameIndex or
|
||||
/// direct SP manipulation, depending on the context. \p MPO
|
||||
@ -89,12 +105,6 @@ class CallLowering {
|
||||
return AssignFn(ValNo, ValVT, LocVT, LocInfo, Info.Flags, State);
|
||||
}
|
||||
|
||||
ValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
|
||||
CCAssignFn *AssignFn)
|
||||
: MIRBuilder(MIRBuilder), MRI(MRI), AssignFn(AssignFn) {}
|
||||
|
||||
virtual ~ValueHandler() {}
|
||||
|
||||
MachineIRBuilder &MIRBuilder;
|
||||
MachineRegisterInfo &MRI;
|
||||
CCAssignFn *AssignFn;
|
||||
@ -112,7 +122,6 @@ class CallLowering {
|
||||
return static_cast<const XXXTargetLowering *>(TLI);
|
||||
}
|
||||
|
||||
|
||||
template <typename FuncInfoTy>
|
||||
void setArgFlags(ArgInfo &Arg, unsigned OpNum, const DataLayout &DL,
|
||||
const FuncInfoTy &FuncInfo) const;
|
||||
@ -126,7 +135,7 @@ class CallLowering {
|
||||
|
||||
public:
|
||||
CallLowering(const TargetLowering *TLI) : TLI(TLI) {}
|
||||
virtual ~CallLowering() {}
|
||||
virtual ~CallLowering() = default;
|
||||
|
||||
/// This hook must be implemented to lower outgoing return values, described
|
||||
/// by \p Val, into the specified virtual register \p VReg.
|
||||
@ -200,6 +209,7 @@ class CallLowering {
|
||||
unsigned ResReg, ArrayRef<unsigned> ArgRegs,
|
||||
std::function<unsigned()> GetCalleeReg) const;
|
||||
};
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_CALLLOWERING_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/GlobalISel/IRTranslator.h - IRTranslator ---*- C++ -*-===//
|
||||
//===- llvm/CodeGen/GlobalISel/IRTranslator.h - IRTranslator ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -19,24 +19,33 @@
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|
||||
|
||||
#include "Types.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/GlobalISel/Types.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
// Forward declarations.
|
||||
|
||||
class AllocaInst;
|
||||
class BasicBlock;
|
||||
class CallInst;
|
||||
class CallLowering;
|
||||
class Constant;
|
||||
class DataLayout;
|
||||
class Instruction;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class OptimizationRemarkEmitter;
|
||||
class MachineRegisterInfo;
|
||||
class OptimizationRemarkEmitter;
|
||||
class PHINode;
|
||||
class TargetPassConfig;
|
||||
class User;
|
||||
class Value;
|
||||
|
||||
// Technically the pass should run on an hypothetical MachineModule,
|
||||
// since it should translate Global into some sort of MachineGlobal.
|
||||
@ -53,6 +62,7 @@ class IRTranslator : public MachineFunctionPass {
|
||||
private:
|
||||
/// Interface used to lower the everything related to calls.
|
||||
const CallLowering *CLI;
|
||||
|
||||
/// Mapping of the values of the current LLVM IR function
|
||||
/// to the related virtual registers.
|
||||
ValueToVReg ValToVReg;
|
||||
@ -67,7 +77,7 @@ class IRTranslator : public MachineFunctionPass {
|
||||
// a mapping between the edges arriving at the BasicBlock to the corresponding
|
||||
// created MachineBasicBlocks. Some BasicBlocks that get translated to a
|
||||
// single MachineBasicBlock may also end up in this Map.
|
||||
typedef std::pair<const BasicBlock *, const BasicBlock *> CFGEdge;
|
||||
using CFGEdge = std::pair<const BasicBlock *, const BasicBlock *>;
|
||||
DenseMap<CFGEdge, SmallVector<MachineBasicBlock *, 1>> MachinePreds;
|
||||
|
||||
// List of stubbed PHI instructions, for values and basic blocks to be filled
|
||||
@ -165,7 +175,6 @@ class IRTranslator : public MachineFunctionPass {
|
||||
return translateCompare(U, MIRBuilder);
|
||||
}
|
||||
|
||||
|
||||
/// Add remaining operands onto phis we've translated. Executed after all
|
||||
/// MachineBasicBlocks for the function have been created.
|
||||
void finishPendingPhis();
|
||||
@ -356,7 +365,7 @@ class IRTranslator : public MachineFunctionPass {
|
||||
MachineFunction *MF;
|
||||
|
||||
/// MachineRegisterInfo used to create virtual registers.
|
||||
MachineRegisterInfo *MRI;
|
||||
MachineRegisterInfo *MRI = nullptr;
|
||||
|
||||
const DataLayout *DL;
|
||||
|
||||
@ -430,5 +439,6 @@ class IRTranslator : public MachineFunctionPass {
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//==-- llvm/CodeGen/GlobalISel/InstructionSelector.h -------------*- C++ -*-==//
|
||||
//===- llvm/CodeGen/GlobalISel/InstructionSelector.h ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -16,15 +16,16 @@
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class MachineInstrBuilder;
|
||||
class MachineFunction;
|
||||
class MachineOperand;
|
||||
class MachineRegisterInfo;
|
||||
class RegisterBankInfo;
|
||||
@ -60,7 +61,7 @@ class PredicateBitsetImpl : public std::bitset<MaxPredicates> {
|
||||
/// Provides the logic to select generic machine instructions.
|
||||
class InstructionSelector {
|
||||
public:
|
||||
virtual ~InstructionSelector() {}
|
||||
virtual ~InstructionSelector() = default;
|
||||
|
||||
/// Select the (possibly generic) instruction \p I to only use target-specific
|
||||
/// opcodes. It is OK to insert multiple instructions, but they cannot be
|
||||
@ -76,7 +77,7 @@ class InstructionSelector {
|
||||
virtual bool select(MachineInstr &I) const = 0;
|
||||
|
||||
protected:
|
||||
typedef std::function<void(MachineInstrBuilder &)> ComplexRendererFn;
|
||||
using ComplexRendererFn = std::function<void(MachineInstrBuilder &)>;
|
||||
|
||||
InstructionSelector();
|
||||
|
||||
@ -110,6 +111,6 @@ class InstructionSelector {
|
||||
bool isObviouslySafeToFold(MachineInstr &MI) const;
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//==-- llvm/CodeGen/GlobalISel/LegalizerInfo.h -------------------*- C++ -*-==//
|
||||
//===- llvm/CodeGen/GlobalISel/LegalizerInfo.h ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -12,33 +12,36 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZER_H
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/CodeGen/LowLevelType.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/LowLevelTypeImpl.h"
|
||||
#include "llvm/Target/TargetOpcodes.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
class LLVMContext;
|
||||
|
||||
class MachineInstr;
|
||||
class MachineIRBuilder;
|
||||
class MachineRegisterInfo;
|
||||
class Type;
|
||||
class VectorType;
|
||||
|
||||
/// Legalization is decided based on an instruction's opcode, which type slot
|
||||
/// we're considering, and what the existing type is. These aspects are gathered
|
||||
/// together for convenience in the InstrAspect class.
|
||||
struct InstrAspect {
|
||||
unsigned Opcode;
|
||||
unsigned Idx;
|
||||
unsigned Idx = 0;
|
||||
LLT Type;
|
||||
|
||||
InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Idx(0), Type(Type) {}
|
||||
InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {}
|
||||
InstrAspect(unsigned Opcode, unsigned Idx, LLT Type)
|
||||
: Opcode(Opcode), Idx(Idx), Type(Type) {}
|
||||
|
||||
@ -104,6 +107,19 @@ class LegalizerInfo {
|
||||
/// before any query is made or incorrect results may be returned.
|
||||
void computeTables();
|
||||
|
||||
static bool needsLegalizingToDifferentSize(const LegalizeAction Action) {
|
||||
switch (Action) {
|
||||
case NarrowScalar:
|
||||
case WidenScalar:
|
||||
case FewerElements:
|
||||
case MoreElements:
|
||||
case Unsupported:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// More friendly way to set an action for common types that have an LLT
|
||||
/// representation.
|
||||
void setAction(const InstrAspect &Aspect, LegalizeAction Action) {
|
||||
@ -125,7 +141,6 @@ class LegalizerInfo {
|
||||
ScalarInVectorActions[std::make_pair(Opcode, ScalarTy)] = Action;
|
||||
}
|
||||
|
||||
|
||||
/// Determine what action should be taken to legalize the given generic
|
||||
/// instruction opcode, type-index and type. Requires computeTables to have
|
||||
/// been called.
|
||||
@ -145,7 +160,7 @@ class LegalizerInfo {
|
||||
|
||||
/// Iterate the given function (typically something like doubling the width)
|
||||
/// on Ty until we find a legal type for this operation.
|
||||
Optional<LLT> findLegalType(const InstrAspect &Aspect,
|
||||
Optional<LLT> findLegalizableSize(const InstrAspect &Aspect,
|
||||
function_ref<LLT(LLT)> NextType) const {
|
||||
LegalizeAction Action;
|
||||
const TypeMap &Map = Actions[Aspect.Opcode - FirstOp][Aspect.Idx];
|
||||
@ -158,10 +173,9 @@ class LegalizerInfo {
|
||||
if (DefaultIt == DefaultActions.end())
|
||||
return None;
|
||||
Action = DefaultIt->second;
|
||||
}
|
||||
else
|
||||
} else
|
||||
Action = ActionIt->second;
|
||||
} while(Action != Legal);
|
||||
} while (needsLegalizingToDifferentSize(Action));
|
||||
return Ty;
|
||||
}
|
||||
|
||||
@ -203,18 +217,17 @@ class LegalizerInfo {
|
||||
static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START;
|
||||
static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END;
|
||||
|
||||
typedef DenseMap<LLT, LegalizeAction> TypeMap;
|
||||
typedef DenseMap<std::pair<unsigned, LLT>, LegalizeAction> SIVActionMap;
|
||||
using TypeMap = DenseMap<LLT, LegalizeAction>;
|
||||
using SIVActionMap = DenseMap<std::pair<unsigned, LLT>, LegalizeAction>;
|
||||
|
||||
SmallVector<TypeMap, 1> Actions[LastOp - FirstOp + 1];
|
||||
SIVActionMap ScalarInVectorActions;
|
||||
DenseMap<std::pair<unsigned, LLT>, uint16_t> MaxLegalVectorElts;
|
||||
DenseMap<unsigned, LegalizeAction> DefaultActions;
|
||||
|
||||
bool TablesInitialized;
|
||||
bool TablesInitialized = false;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_LEGALIZERINFO_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//== llvm/CodeGen/GlobalISel/RegBankSelect.h - Reg Bank Selector -*- C++ -*-==//
|
||||
//=- llvm/CodeGen/GlobalISel/RegBankSelect.h - Reg Bank Selector --*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -64,20 +64,27 @@
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
// Forward declarations.
|
||||
|
||||
class BlockFrequency;
|
||||
class MachineBranchProbabilityInfo;
|
||||
class MachineBlockFrequencyInfo;
|
||||
class MachineBranchProbabilityInfo;
|
||||
class MachineOperand;
|
||||
class MachineRegisterInfo;
|
||||
class Pass;
|
||||
class raw_ostream;
|
||||
class TargetPassConfig;
|
||||
class TargetRegisterInfo;
|
||||
class raw_ostream;
|
||||
|
||||
/// This pass implements the reg bank selector pass used in the GlobalISel
|
||||
/// pipeline. At the end of this pass, all register operands have been assigned
|
||||
@ -105,6 +112,7 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
protected:
|
||||
/// Tell if the insert point has already been materialized.
|
||||
bool WasMaterialized = false;
|
||||
|
||||
/// Materialize the insertion point.
|
||||
///
|
||||
/// If isSplit() is true, this involves actually splitting
|
||||
@ -128,7 +136,7 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
virtual MachineBasicBlock::iterator getPointImpl() = 0;
|
||||
|
||||
public:
|
||||
virtual ~InsertPoint() {}
|
||||
virtual ~InsertPoint() = default;
|
||||
|
||||
/// The first call to this method will cause the splitting to
|
||||
/// happen if need be, then sub sequent calls just return
|
||||
@ -197,6 +205,7 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
private:
|
||||
/// Insertion point.
|
||||
MachineInstr &Instr;
|
||||
|
||||
/// Does the insertion point is before or after Instr.
|
||||
bool Before;
|
||||
|
||||
@ -216,6 +225,7 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
public:
|
||||
/// Create an insertion point before (\p Before=true) or after \p Instr.
|
||||
InstrInsertPoint(MachineInstr &Instr, bool Before = true);
|
||||
|
||||
bool isSplit() const override;
|
||||
uint64_t frequency(const Pass &P) const override;
|
||||
|
||||
@ -228,6 +238,7 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
private:
|
||||
/// Insertion point.
|
||||
MachineBasicBlock &MBB;
|
||||
|
||||
/// Does the insertion point is at the beginning or end of MBB.
|
||||
bool Beginning;
|
||||
|
||||
@ -252,6 +263,7 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
assert((Beginning || MBB.getFirstTerminator() == MBB.end()) &&
|
||||
"Invalid end point");
|
||||
}
|
||||
|
||||
bool isSplit() const override { return false; }
|
||||
uint64_t frequency(const Pass &P) const override;
|
||||
bool canMaterialize() const override { return true; };
|
||||
@ -262,10 +274,12 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
private:
|
||||
/// Source of the edge.
|
||||
MachineBasicBlock &Src;
|
||||
|
||||
/// Destination of the edge.
|
||||
/// After the materialization is done, this hold the basic block
|
||||
/// that resulted from the splitting.
|
||||
MachineBasicBlock *DstOrSplit;
|
||||
|
||||
/// P is used to update the analysis passes as applicable.
|
||||
Pass &P;
|
||||
|
||||
@ -286,9 +300,11 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
public:
|
||||
EdgeInsertPoint(MachineBasicBlock &Src, MachineBasicBlock &Dst, Pass &P)
|
||||
: InsertPoint(), Src(Src), DstOrSplit(&Dst), P(P) {}
|
||||
|
||||
bool isSplit() const override {
|
||||
return Src.succ_size() > 1 && DstOrSplit->pred_size() > 1;
|
||||
}
|
||||
|
||||
uint64_t frequency(const Pass &P) const override;
|
||||
bool canMaterialize() const override;
|
||||
};
|
||||
@ -311,9 +327,9 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
|
||||
/// \name Convenient types for a list of insertion points.
|
||||
/// @{
|
||||
typedef SmallVector<std::unique_ptr<InsertPoint>, 2> InsertionPoints;
|
||||
typedef InsertionPoints::iterator insertpt_iterator;
|
||||
typedef InsertionPoints::const_iterator const_insertpt_iterator;
|
||||
using InsertionPoints = SmallVector<std::unique_ptr<InsertPoint>, 2>;
|
||||
using insertpt_iterator = InsertionPoints::iterator;
|
||||
using const_insertpt_iterator = InsertionPoints::const_iterator;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
@ -324,7 +340,7 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
/// Are all the insert points materializeable?
|
||||
bool CanMaterialize;
|
||||
/// Is there any of the insert points needing splitting?
|
||||
bool HasSplit;
|
||||
bool HasSplit = false;
|
||||
/// Insertion point for the repair code.
|
||||
/// The repairing code needs to happen just before these points.
|
||||
InsertionPoints InsertPoints;
|
||||
@ -407,10 +423,10 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
private:
|
||||
/// Cost of the local instructions.
|
||||
/// This cost is free of basic block frequency.
|
||||
uint64_t LocalCost;
|
||||
uint64_t LocalCost = 0;
|
||||
/// Cost of the non-local instructions.
|
||||
/// This cost should include the frequency of the related blocks.
|
||||
uint64_t NonLocalCost;
|
||||
uint64_t NonLocalCost = 0;
|
||||
/// Frequency of the block where the local instructions live.
|
||||
uint64_t LocalFreq;
|
||||
|
||||
@ -468,22 +484,22 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
|
||||
/// Interface to the target lowering info related
|
||||
/// to register banks.
|
||||
const RegisterBankInfo *RBI;
|
||||
const RegisterBankInfo *RBI = nullptr;
|
||||
|
||||
/// MRI contains all the register class/bank information that this
|
||||
/// pass uses and updates.
|
||||
MachineRegisterInfo *MRI;
|
||||
MachineRegisterInfo *MRI = nullptr;
|
||||
|
||||
/// Information on the register classes for the current function.
|
||||
const TargetRegisterInfo *TRI;
|
||||
const TargetRegisterInfo *TRI = nullptr;
|
||||
|
||||
/// Get the frequency of blocks.
|
||||
/// This is required for non-fast mode.
|
||||
MachineBlockFrequencyInfo *MBFI;
|
||||
MachineBlockFrequencyInfo *MBFI = nullptr;
|
||||
|
||||
/// Get the frequency of the edges.
|
||||
/// This is required for non-fast mode.
|
||||
MachineBranchProbabilityInfo *MBPI;
|
||||
MachineBranchProbabilityInfo *MBPI = nullptr;
|
||||
|
||||
/// Current optimization remark emitter. Used to report failures.
|
||||
std::unique_ptr<MachineOptimizationRemarkEmitter> MORE;
|
||||
@ -644,6 +660,6 @@ class RegBankSelect : public MachineFunctionPass {
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//==-- llvm/CodeGen/GlobalISel/RegisterBankInfo.h ----------------*- C++ -*-==//
|
||||
//===- llvm/CodeGen/GlobalISel/RegisterBankInfo.h ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -12,26 +12,27 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANKINFO_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_REGBANKINFO_H
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_REGISTERBANKINFO_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_REGISTERBANKINFO_H
|
||||
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
|
||||
#include "llvm/CodeGen/MachineValueType.h" // For SimpleValueType.
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <memory> // For unique_ptr.
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class MachineRegisterInfo;
|
||||
class TargetInstrInfo;
|
||||
class TargetRegisterInfo;
|
||||
class raw_ostream;
|
||||
class RegisterBank;
|
||||
class TargetInstrInfo;
|
||||
class TargetRegisterClass;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// Holds all the information related to register banks.
|
||||
class RegisterBankInfo {
|
||||
@ -48,10 +49,12 @@ class RegisterBankInfo {
|
||||
/// original value. The bits are counted from less significant
|
||||
/// bits to most significant bits.
|
||||
unsigned StartIdx;
|
||||
|
||||
/// Length of this mapping in bits. This is how many bits this
|
||||
/// partial mapping covers in the original value:
|
||||
/// from StartIdx to StartIdx + Length -1.
|
||||
unsigned Length;
|
||||
|
||||
/// Register bank where the partial value lives.
|
||||
const RegisterBank *RegBank;
|
||||
|
||||
@ -180,13 +183,16 @@ class RegisterBankInfo {
|
||||
/// Identifier of the mapping.
|
||||
/// This is used to communicate between the target and the optimizers
|
||||
/// which mapping should be realized.
|
||||
unsigned ID;
|
||||
unsigned ID = InvalidMappingID;
|
||||
|
||||
/// Cost of this mapping.
|
||||
unsigned Cost;
|
||||
unsigned Cost = 0;
|
||||
|
||||
/// Mapping of all the operands.
|
||||
const ValueMapping *OperandsMapping;
|
||||
|
||||
/// Number of operands.
|
||||
unsigned NumOperands;
|
||||
unsigned NumOperands = 0;
|
||||
|
||||
const ValueMapping &getOperandMapping(unsigned i) {
|
||||
assert(i < getNumOperands() && "Out of bound operand");
|
||||
@ -213,7 +219,7 @@ class RegisterBankInfo {
|
||||
|
||||
/// Default constructor.
|
||||
/// Use this constructor to express that the mapping is invalid.
|
||||
InstructionMapping() : ID(InvalidMappingID), Cost(0), NumOperands(0) {}
|
||||
InstructionMapping() = default;
|
||||
|
||||
/// Get the cost.
|
||||
unsigned getCost() const { return Cost; }
|
||||
@ -264,7 +270,7 @@ class RegisterBankInfo {
|
||||
/// Convenient type to represent the alternatives for mapping an
|
||||
/// instruction.
|
||||
/// \todo When we move to TableGen this should be an array ref.
|
||||
typedef SmallVector<const InstructionMapping *, 4> InstructionMappings;
|
||||
using InstructionMappings = SmallVector<const InstructionMapping *, 4>;
|
||||
|
||||
/// Helper class used to get/create the virtual registers that will be used
|
||||
/// to replace the MachineOperand when applying a mapping.
|
||||
@ -273,12 +279,16 @@ class RegisterBankInfo {
|
||||
/// OpIdx-th operand starts. -1 means we do not have such mapping yet.
|
||||
/// Note: We use a SmallVector to avoid heap allocation for most cases.
|
||||
SmallVector<int, 8> OpToNewVRegIdx;
|
||||
|
||||
/// Hold the registers that will be used to map MI with InstrMapping.
|
||||
SmallVector<unsigned, 8> NewVRegs;
|
||||
|
||||
/// Current MachineRegisterInfo, used to create new virtual registers.
|
||||
MachineRegisterInfo &MRI;
|
||||
|
||||
/// Instruction being remapped.
|
||||
MachineInstr &MI;
|
||||
|
||||
/// New mapping of the instruction.
|
||||
const InstructionMapping &InstrMapping;
|
||||
|
||||
@ -373,6 +383,7 @@ class RegisterBankInfo {
|
||||
protected:
|
||||
/// Hold the set of supported register banks.
|
||||
RegisterBank **RegBanks;
|
||||
|
||||
/// Total number of register banks.
|
||||
unsigned NumRegBanks;
|
||||
|
||||
@ -729,6 +740,7 @@ operator<<(raw_ostream &OS, const RegisterBankInfo::OperandsMapper &OpdMapper) {
|
||||
/// Hashing function for PartialMapping.
|
||||
/// It is required for the hashing of ValueMapping.
|
||||
hash_code hash_value(const RegisterBankInfo::PartialMapping &PartMapping);
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_REGISTERBANKINFO_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/GlobalISel/Types.h - Types used by GISel ----*- C++ -*-===//
|
||||
//===- llvm/CodeGen/GlobalISel/Types.h - Types used by GISel ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -16,17 +16,19 @@
|
||||
#define LLVM_CODEGEN_GLOBALISEL_TYPES_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Value;
|
||||
|
||||
/// Map a value to a virtual register.
|
||||
/// For now, we chose to map aggregate types to on single virtual
|
||||
/// register. This might be revisited if it turns out to be inefficient.
|
||||
/// PR26161 tracks that.
|
||||
/// Note: We need to expose this type to the target hooks for thing like
|
||||
/// ABI lowering that would be used during IRTranslation.
|
||||
typedef DenseMap<const Value *, unsigned> ValueToVReg;
|
||||
using ValueToVReg = DenseMap<const Value *, unsigned>;
|
||||
|
||||
} // End namespace llvm.
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_TYPES_H
|
||||
|
@ -134,7 +134,7 @@ using MNV = DiagnosticInfoMIROptimization::MachineArgument;
|
||||
///
|
||||
/// It allows reporting when optimizations are performed and when they are not
|
||||
/// along with the reasons for it. Hotness information of the corresponding
|
||||
/// code region can be included in the remark if DiagnosticHotnessRequested is
|
||||
/// code region can be included in the remark if DiagnosticsHotnessRequested is
|
||||
/// enabled in the LLVM context.
|
||||
class MachineOptimizationRemarkEmitter {
|
||||
public:
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- llvm/CodeGen/MachinePassRegistry.h ----------------------*- C++ -*-===//
|
||||
//===- llvm/CodeGen/MachinePassRegistry.h -----------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -18,13 +18,13 @@
|
||||
#ifndef LLVM_CODEGEN_MACHINEPASSREGISTRY_H
|
||||
#define LLVM_CODEGEN_MACHINEPASSREGISTRY_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
typedef void *(*MachinePassCtor)();
|
||||
|
||||
using MachinePassCtor = void *(*)();
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
@ -34,36 +34,30 @@ typedef void *(*MachinePassCtor)();
|
||||
//===----------------------------------------------------------------------===//
|
||||
class MachinePassRegistryListener {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
MachinePassRegistryListener() {}
|
||||
virtual ~MachinePassRegistryListener() {}
|
||||
MachinePassRegistryListener() = default;
|
||||
virtual ~MachinePassRegistryListener() = default;
|
||||
|
||||
virtual void NotifyAdd(StringRef N, MachinePassCtor C, StringRef D) = 0;
|
||||
virtual void NotifyRemove(StringRef N) = 0;
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// MachinePassRegistryNode - Machine pass node stored in registration list.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
class MachinePassRegistryNode {
|
||||
|
||||
private:
|
||||
|
||||
MachinePassRegistryNode *Next; // Next function pass in list.
|
||||
MachinePassRegistryNode *Next = nullptr; // Next function pass in list.
|
||||
StringRef Name; // Name of function pass.
|
||||
StringRef Description; // Description string.
|
||||
MachinePassCtor Ctor; // Function pass creator.
|
||||
|
||||
public:
|
||||
|
||||
MachinePassRegistryNode(const char *N, const char *D, MachinePassCtor C)
|
||||
: Next(nullptr)
|
||||
, Name(N)
|
||||
, Description(D)
|
||||
, Ctor(C)
|
||||
{}
|
||||
: Name(N), Description(D), Ctor(C) {}
|
||||
|
||||
// Accessors
|
||||
MachinePassRegistryNode *getNext() const { return Next; }
|
||||
@ -72,25 +66,20 @@ class MachinePassRegistryNode {
|
||||
StringRef getDescription() const { return Description; }
|
||||
MachinePassCtor getCtor() const { return Ctor; }
|
||||
void setNext(MachinePassRegistryNode *N) { Next = N; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// MachinePassRegistry - Track the registration of machine passes.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
class MachinePassRegistry {
|
||||
|
||||
private:
|
||||
|
||||
MachinePassRegistryNode *List; // List of registry nodes.
|
||||
MachinePassCtor Default; // Default function pass creator.
|
||||
MachinePassRegistryListener* Listener;// Listener for list adds are removes.
|
||||
MachinePassRegistryListener *Listener; // Listener for list adds are removes.
|
||||
|
||||
public:
|
||||
|
||||
// NO CONSTRUCTOR - we don't want static constructor ordering to mess
|
||||
// with the registry.
|
||||
|
||||
@ -109,10 +98,8 @@ class MachinePassRegistry {
|
||||
/// Remove - Removes a function pass from the registration list.
|
||||
///
|
||||
void Remove(MachinePassRegistryNode *Node);
|
||||
|
||||
};
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// RegisterPassParser class - Handle the addition of new machine passes.
|
||||
@ -142,7 +129,6 @@ class RegisterPassParser : public MachinePassRegistryListener,
|
||||
}
|
||||
|
||||
// Implement the MachinePassRegistryListener callbacks.
|
||||
//
|
||||
void NotifyAdd(StringRef N, MachinePassCtor C, StringRef D) override {
|
||||
this->addLiteralOption(N, (typename RegistryClass::FunctionPassCtor)C, D);
|
||||
}
|
||||
@ -151,7 +137,6 @@ class RegisterPassParser : public MachinePassRegistryListener,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINEPASSREGISTRY_H
|
||||
|
@ -32,7 +32,7 @@
|
||||
//
|
||||
// ScheduleDAGInstrs *<Target>PassConfig::
|
||||
// createMachineScheduler(MachineSchedContext *C) {
|
||||
// return new ScheduleDAGMI(C, CustomStrategy(C));
|
||||
// return new ScheduleDAGMILive(C, CustomStrategy(C));
|
||||
// }
|
||||
//
|
||||
// The DAG builder can also be customized in a sense by adding DAG mutations
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -232,8 +233,7 @@ namespace llvm {
|
||||
Any = 255
|
||||
};
|
||||
|
||||
SimpleValueType SimpleTy;
|
||||
|
||||
SimpleValueType SimpleTy = INVALID_SIMPLE_VALUE_TYPE;
|
||||
|
||||
// A class to represent the number of elements in a vector
|
||||
//
|
||||
@ -270,7 +270,7 @@ namespace llvm {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr MVT() : SimpleTy(INVALID_SIMPLE_VALUE_TYPE) {}
|
||||
constexpr MVT() = default;
|
||||
constexpr MVT(SimpleValueType SVT) : SimpleTy(SVT) {}
|
||||
|
||||
bool operator>(const MVT& S) const { return SimpleTy > S.SimpleTy; }
|
||||
@ -780,7 +780,6 @@ namespace llvm {
|
||||
return getSizeInBits() <= VT.getSizeInBits();
|
||||
}
|
||||
|
||||
|
||||
static MVT getFloatingPointVT(unsigned BitWidth) {
|
||||
switch (BitWidth) {
|
||||
default:
|
||||
@ -982,9 +981,12 @@ namespace llvm {
|
||||
/// A simple iterator over the MVT::SimpleValueType enum.
|
||||
struct mvt_iterator {
|
||||
SimpleValueType VT;
|
||||
|
||||
mvt_iterator(SimpleValueType VT) : VT(VT) {}
|
||||
|
||||
MVT operator*() const { return VT; }
|
||||
bool operator!=(const mvt_iterator &LHS) const { return VT != LHS.VT; }
|
||||
|
||||
mvt_iterator& operator++() {
|
||||
VT = (MVT::SimpleValueType)((int)VT + 1);
|
||||
assert((int)VT <= MVT::MAX_ALLOWED_VALUETYPE &&
|
||||
@ -992,8 +994,9 @@ namespace llvm {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// A range of the MVT::SimpleValueType enum.
|
||||
typedef iterator_range<mvt_iterator> mvt_range;
|
||||
using mvt_range = iterator_range<mvt_iterator>;
|
||||
|
||||
public:
|
||||
/// SimpleValueType Iteration
|
||||
@ -1001,32 +1004,39 @@ namespace llvm {
|
||||
static mvt_range all_valuetypes() {
|
||||
return mvt_range(MVT::FIRST_VALUETYPE, MVT::LAST_VALUETYPE);
|
||||
}
|
||||
|
||||
static mvt_range integer_valuetypes() {
|
||||
return mvt_range(MVT::FIRST_INTEGER_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_INTEGER_VALUETYPE + 1));
|
||||
}
|
||||
|
||||
static mvt_range fp_valuetypes() {
|
||||
return mvt_range(MVT::FIRST_FP_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_FP_VALUETYPE + 1));
|
||||
}
|
||||
|
||||
static mvt_range vector_valuetypes() {
|
||||
return mvt_range(MVT::FIRST_VECTOR_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_VECTOR_VALUETYPE + 1));
|
||||
}
|
||||
|
||||
static mvt_range integer_vector_valuetypes() {
|
||||
return mvt_range(
|
||||
MVT::FIRST_INTEGER_VECTOR_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_INTEGER_VECTOR_VALUETYPE + 1));
|
||||
}
|
||||
|
||||
static mvt_range fp_vector_valuetypes() {
|
||||
return mvt_range(
|
||||
MVT::FIRST_FP_VECTOR_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_FP_VECTOR_VALUETYPE + 1));
|
||||
}
|
||||
|
||||
static mvt_range integer_scalable_vector_valuetypes() {
|
||||
return mvt_range(MVT::FIRST_INTEGER_SCALABLE_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_INTEGER_SCALABLE_VALUETYPE + 1));
|
||||
}
|
||||
|
||||
static mvt_range fp_scalable_vector_valuetypes() {
|
||||
return mvt_range(MVT::FIRST_FP_SCALABLE_VALUETYPE,
|
||||
(MVT::SimpleValueType)(MVT::LAST_FP_SCALABLE_VALUETYPE + 1));
|
||||
@ -1034,6 +1044,6 @@ namespace llvm {
|
||||
/// @}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_MACHINEVALUETYPE_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- MacroFusion.h - Macro Fusion ------------------------===//
|
||||
//===- MacroFusion.h - Macro Fusion -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -12,19 +12,26 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MACROFUSION_H
|
||||
#define LLVM_CODEGEN_MACROFUSION_H
|
||||
|
||||
#include <functional>
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
#include "llvm/CodeGen/MachineScheduler.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class ScheduleDAGMutation;
|
||||
class TargetInstrInfo;
|
||||
class TargetSubtargetInfo;
|
||||
|
||||
/// \brief Check if the instr pair, FirstMI and SecondMI, should be fused
|
||||
/// together. Given SecondMI, when FirstMI is unspecified, then check if
|
||||
/// SecondMI may be part of a fused pair at all.
|
||||
typedef std::function<bool(const TargetInstrInfo &TII,
|
||||
using ShouldSchedulePredTy = std::function<bool(const TargetInstrInfo &TII,
|
||||
const TargetSubtargetInfo &TSI,
|
||||
const MachineInstr *FirstMI,
|
||||
const MachineInstr &SecondMI)> ShouldSchedulePredTy;
|
||||
const MachineInstr &SecondMI)>;
|
||||
|
||||
/// \brief Create a DAG scheduling mutation to pair instructions back to back
|
||||
/// for instructions that benefit according to the target-specific
|
||||
@ -39,3 +46,5 @@ std::unique_ptr<ScheduleDAGMutation>
|
||||
createBranchMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MACROFUSION_H
|
||||
|
@ -94,7 +94,7 @@ class FixedStackPseudoSourceValue : public PseudoSourceValue {
|
||||
explicit FixedStackPseudoSourceValue(int FI)
|
||||
: PseudoSourceValue(FixedStack), FI(FI) {}
|
||||
|
||||
static inline bool classof(const PseudoSourceValue *V) {
|
||||
static bool classof(const PseudoSourceValue *V) {
|
||||
return V->kind() == FixedStack;
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ class GlobalValuePseudoSourceValue : public CallEntryPseudoSourceValue {
|
||||
public:
|
||||
GlobalValuePseudoSourceValue(const GlobalValue *GV);
|
||||
|
||||
static inline bool classof(const PseudoSourceValue *V) {
|
||||
static bool classof(const PseudoSourceValue *V) {
|
||||
return V->kind() == GlobalValueCallEntry;
|
||||
}
|
||||
|
||||
@ -140,7 +140,7 @@ class ExternalSymbolPseudoSourceValue : public CallEntryPseudoSourceValue {
|
||||
public:
|
||||
ExternalSymbolPseudoSourceValue(const char *ES);
|
||||
|
||||
static inline bool classof(const PseudoSourceValue *V) {
|
||||
static bool classof(const PseudoSourceValue *V) {
|
||||
return V->kind() == ExternalSymbolCallEntry;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ class BaseIndexOffset {
|
||||
int64_t &Off);
|
||||
|
||||
/// Parses tree in Ptr for base, index, offset addresses.
|
||||
static BaseIndexOffset match(SDValue Ptr);
|
||||
static BaseIndexOffset match(SDValue Ptr, const SelectionDAG &DAG);
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
|
@ -1743,7 +1743,7 @@ class BuildVectorSDNode : public SDNode {
|
||||
|
||||
bool isConstant() const;
|
||||
|
||||
static inline bool classof(const SDNode *N) {
|
||||
static bool classof(const SDNode *N) {
|
||||
return N->getOpcode() == ISD::BUILD_VECTOR;
|
||||
}
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===-- TargetPassConfig.h - Code Generation pass options -------*- C++ -*-===//
|
||||
//===- TargetPassConfig.h - Code Generation pass options --------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -16,19 +16,23 @@
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class PassConfigImpl;
|
||||
class ScheduleDAGInstrs;
|
||||
class LLVMTargetMachine;
|
||||
struct MachineSchedContext;
|
||||
class PassConfigImpl;
|
||||
class ScheduleDAGInstrs;
|
||||
|
||||
// The old pass manager infrastructure is hidden in a legacy namespace now.
|
||||
namespace legacy {
|
||||
|
||||
class PassManagerBase;
|
||||
}
|
||||
|
||||
} // end namespace legacy
|
||||
|
||||
using legacy::PassManagerBase;
|
||||
|
||||
/// Discriminated union of Pass ID types.
|
||||
@ -50,10 +54,11 @@ class IdentifyingPassPtr {
|
||||
AnalysisID ID;
|
||||
Pass *P;
|
||||
};
|
||||
bool IsInstance;
|
||||
bool IsInstance = false;
|
||||
|
||||
public:
|
||||
IdentifyingPassPtr() : P(nullptr), IsInstance(false) {}
|
||||
IdentifyingPassPtr(AnalysisID IDPtr) : ID(IDPtr), IsInstance(false) {}
|
||||
IdentifyingPassPtr() : P(nullptr) {}
|
||||
IdentifyingPassPtr(AnalysisID IDPtr) : ID(IDPtr) {}
|
||||
IdentifyingPassPtr(Pass *InstancePtr) : P(InstancePtr), IsInstance(true) {}
|
||||
|
||||
bool isValid() const { return P; }
|
||||
@ -63,6 +68,7 @@ class IdentifyingPassPtr {
|
||||
assert(!IsInstance && "Not a Pass ID");
|
||||
return ID;
|
||||
}
|
||||
|
||||
Pass *getInstance() const {
|
||||
assert(IsInstance && "Not a Pass Instance");
|
||||
return P;
|
||||
@ -93,31 +99,30 @@ class TargetPassConfig : public ImmutablePass {
|
||||
static char PostRAMachineLICMID;
|
||||
|
||||
private:
|
||||
PassManagerBase *PM;
|
||||
PassManagerBase *PM = nullptr;
|
||||
AnalysisID StartBefore = nullptr;
|
||||
AnalysisID StartAfter = nullptr;
|
||||
AnalysisID StopBefore = nullptr;
|
||||
AnalysisID StopAfter = nullptr;
|
||||
bool Started;
|
||||
bool Stopped;
|
||||
bool AddingMachinePasses;
|
||||
bool Started = true;
|
||||
bool Stopped = false;
|
||||
bool AddingMachinePasses = false;
|
||||
|
||||
protected:
|
||||
LLVMTargetMachine *TM;
|
||||
PassConfigImpl *Impl; // Internal data structures
|
||||
bool Initialized; // Flagged after all passes are configured.
|
||||
PassConfigImpl *Impl = nullptr; // Internal data structures
|
||||
bool Initialized = false; // Flagged after all passes are configured.
|
||||
|
||||
// Target Pass Options
|
||||
// Targets provide a default setting, user flags override.
|
||||
//
|
||||
bool DisableVerify;
|
||||
bool DisableVerify = false;
|
||||
|
||||
/// Default setting for -enable-tail-merge on this target.
|
||||
bool EnableTailMerge;
|
||||
bool EnableTailMerge = true;
|
||||
|
||||
/// Require processing of functions such that callees are generated before
|
||||
/// callers.
|
||||
bool RequireCodeGenSCCOrder;
|
||||
bool RequireCodeGenSCCOrder = false;
|
||||
|
||||
/// Add the actual instruction selection passes. This does not include
|
||||
/// preparation passes on IR.
|
||||
@ -296,7 +301,6 @@ class TargetPassConfig : public ImmutablePass {
|
||||
|
||||
/// printAndVerify - Add a pass to dump then verify the machine function, if
|
||||
/// those steps are enabled.
|
||||
///
|
||||
void printAndVerify(const std::string &Banner);
|
||||
|
||||
/// Add a pass to print the machine function if printing is enabled.
|
||||
@ -430,4 +434,4 @@ class TargetPassConfig : public ImmutablePass {
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_TARGETPASSCONFIG_H
|
||||
|
@ -17,7 +17,10 @@
|
||||
#define LLVM_CODEGEN_VALUETYPES_H
|
||||
|
||||
#include "llvm/CodeGen/MachineValueType.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
@ -30,13 +33,13 @@ namespace llvm {
|
||||
/// can represent.
|
||||
struct EVT {
|
||||
private:
|
||||
MVT V;
|
||||
Type *LLVMTy;
|
||||
MVT V = MVT::INVALID_SIMPLE_VALUE_TYPE;
|
||||
Type *LLVMTy = nullptr;
|
||||
|
||||
public:
|
||||
constexpr EVT() : V(MVT::INVALID_SIMPLE_VALUE_TYPE), LLVMTy(nullptr) {}
|
||||
constexpr EVT(MVT::SimpleValueType SVT) : V(SVT), LLVMTy(nullptr) {}
|
||||
constexpr EVT(MVT S) : V(S), LLVMTy(nullptr) {}
|
||||
constexpr EVT() = default;
|
||||
constexpr EVT(MVT::SimpleValueType SVT) : V(SVT) {}
|
||||
constexpr EVT(MVT S) : V(S) {}
|
||||
|
||||
bool operator==(EVT VT) const {
|
||||
return !(*this != VT);
|
||||
@ -246,7 +249,6 @@ namespace llvm {
|
||||
return getSizeInBits() <= VT.getSizeInBits();
|
||||
}
|
||||
|
||||
|
||||
/// Return the SimpleValueType held in the specified simple EVT.
|
||||
MVT getSimpleVT() const {
|
||||
assert(isSimple() && "Expected a SimpleValueType!");
|
||||
@ -430,6 +432,6 @@ namespace llvm {
|
||||
unsigned getExtendedSizeInBits() const LLVM_READONLY;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_CODEGEN_VALUETYPES_H
|
||||
|
@ -25,7 +25,9 @@ class CVSymbolVisitor {
|
||||
CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks);
|
||||
|
||||
Error visitSymbolRecord(CVSymbol &Record);
|
||||
Error visitSymbolRecord(CVSymbol &Record, uint32_t Offset);
|
||||
Error visitSymbolStream(const CVSymbolArray &Symbols);
|
||||
Error visitSymbolStream(const CVSymbolArray &Symbols, uint32_t InitialOffset);
|
||||
|
||||
private:
|
||||
SymbolVisitorCallbacks &Callbacks;
|
||||
|
@ -12,13 +12,19 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace codeview {
|
||||
|
||||
class DebugStringTableSubsection;
|
||||
@ -28,24 +34,22 @@ struct FileChecksumEntry {
|
||||
FileChecksumKind Kind; // The type of checksum.
|
||||
ArrayRef<uint8_t> Checksum; // The bytes of the checksum.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
} // end namespace codeview
|
||||
|
||||
template <> struct VarStreamArrayExtractor<codeview::FileChecksumEntry> {
|
||||
public:
|
||||
typedef void ContextType;
|
||||
using ContextType = void;
|
||||
|
||||
Error operator()(BinaryStreamRef Stream, uint32_t &Len,
|
||||
codeview::FileChecksumEntry &Item);
|
||||
};
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class DebugChecksumsSubsectionRef final : public DebugSubsectionRef {
|
||||
typedef VarStreamArray<codeview::FileChecksumEntry> FileChecksumArray;
|
||||
typedef FileChecksumArray::Iterator Iterator;
|
||||
using FileChecksumArray = VarStreamArray<codeview::FileChecksumEntry>;
|
||||
using Iterator = FileChecksumArray::Iterator;
|
||||
|
||||
public:
|
||||
DebugChecksumsSubsectionRef()
|
||||
@ -89,10 +93,12 @@ class DebugChecksumsSubsection final : public DebugSubsection {
|
||||
|
||||
DenseMap<uint32_t, uint32_t> OffsetMap;
|
||||
uint32_t SerializedSize = 0;
|
||||
llvm::BumpPtrAllocator Storage;
|
||||
BumpPtrAllocator Storage;
|
||||
std::vector<FileChecksumEntry> Checksums;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGCHECKSUMSSUBSECTION_H
|
||||
|
@ -10,18 +10,21 @@
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGCROSSEXSUBSECTION_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_DEBUGCROSSEXSUBSECTION_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class DebugCrossModuleExportsSubsectionRef final : public DebugSubsectionRef {
|
||||
typedef FixedStreamArray<CrossModuleExport> ReferenceArray;
|
||||
typedef ReferenceArray::Iterator Iterator;
|
||||
using ReferenceArray = FixedStreamArray<CrossModuleExport>;
|
||||
using Iterator = ReferenceArray::Iterator;
|
||||
|
||||
public:
|
||||
DebugCrossModuleExportsSubsectionRef()
|
||||
@ -58,7 +61,8 @@ class DebugCrossModuleExportsSubsection final : public DebugSubsection {
|
||||
private:
|
||||
std::map<uint32_t, uint32_t> Mappings;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGCROSSEXSUBSECTION_H
|
||||
|
@ -11,38 +11,43 @@
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_DEBUGCROSSIMPSUBSECTION_H
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace codeview {
|
||||
|
||||
struct CrossModuleImportItem {
|
||||
const CrossModuleImport *Header = nullptr;
|
||||
llvm::FixedStreamArray<support::ulittle32_t> Imports;
|
||||
FixedStreamArray<support::ulittle32_t> Imports;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
} // end namespace codeview
|
||||
|
||||
template <> struct VarStreamArrayExtractor<codeview::CrossModuleImportItem> {
|
||||
public:
|
||||
typedef void ContextType;
|
||||
using ContextType = void;
|
||||
|
||||
Error operator()(BinaryStreamRef Stream, uint32_t &Len,
|
||||
codeview::CrossModuleImportItem &Item);
|
||||
};
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class DebugStringTableSubsection;
|
||||
|
||||
class DebugCrossModuleImportsSubsectionRef final : public DebugSubsectionRef {
|
||||
typedef VarStreamArray<CrossModuleImportItem> ReferenceArray;
|
||||
typedef ReferenceArray::Iterator Iterator;
|
||||
using ReferenceArray = VarStreamArray<CrossModuleImportItem>;
|
||||
using Iterator = ReferenceArray::Iterator;
|
||||
|
||||
public:
|
||||
DebugCrossModuleImportsSubsectionRef()
|
||||
@ -82,7 +87,9 @@ class DebugCrossModuleImportsSubsection final : public DebugSubsection {
|
||||
DebugStringTableSubsection &Strings;
|
||||
StringMap<std::vector<support::ulittle32_t>> Mappings;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGCROSSIMPSUBSECTION_H
|
||||
|
@ -7,19 +7,26 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_BUGINLINEELINESSUBSECTION_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_BUGINLINEELINESSUBSECTION_H
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGINLINEELINESSUBSECTION_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_DEBUGINLINEELINESSUBSECTION_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/Line.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace codeview {
|
||||
|
||||
class DebugInlineeLinesSubsectionRef;
|
||||
class DebugChecksumsSubsection;
|
||||
|
||||
enum class InlineeLinesSignature : uint32_t {
|
||||
@ -40,18 +47,21 @@ struct InlineeSourceLine {
|
||||
const InlineeSourceLineHeader *Header;
|
||||
FixedStreamArray<support::ulittle32_t> ExtraFiles;
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace codeview
|
||||
|
||||
template <> struct VarStreamArrayExtractor<codeview::InlineeSourceLine> {
|
||||
Error operator()(BinaryStreamRef Stream, uint32_t &Len,
|
||||
codeview::InlineeSourceLine &Item);
|
||||
|
||||
bool HasExtraFiles = false;
|
||||
};
|
||||
|
||||
namespace codeview {
|
||||
|
||||
class DebugInlineeLinesSubsectionRef final : public DebugSubsectionRef {
|
||||
typedef VarStreamArray<InlineeSourceLine> LinesArray;
|
||||
typedef LinesArray::Iterator Iterator;
|
||||
using LinesArray = VarStreamArray<InlineeSourceLine>;
|
||||
using Iterator = LinesArray::Iterator;
|
||||
|
||||
public:
|
||||
DebugInlineeLinesSubsectionRef();
|
||||
@ -99,13 +109,13 @@ class DebugInlineeLinesSubsection final : public DebugSubsection {
|
||||
|
||||
private:
|
||||
DebugChecksumsSubsection &Checksums;
|
||||
|
||||
bool HasExtraFiles = false;
|
||||
uint32_t ExtraFileCount = 0;
|
||||
|
||||
std::vector<Entry> Entries;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGINLINEELINESSUBSECTION_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- DebugLinesSubsection.h --------------------------------*- C++ -*-===//
|
||||
//===- DebugLinesSubsection.h -----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,14 +7,20 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGLINEFRAGMENT_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGLINEFRAGMENT_H
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGLINESSUBSECTION_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_DEBUGLINESSUBSECTION_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/Line.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
@ -72,8 +78,9 @@ class LineColumnExtractor {
|
||||
|
||||
class DebugLinesSubsectionRef final : public DebugSubsectionRef {
|
||||
friend class LineColumnExtractor;
|
||||
typedef VarStreamArray<LineColumnEntry, LineColumnExtractor> LineInfoArray;
|
||||
typedef LineInfoArray::Iterator Iterator;
|
||||
|
||||
using LineInfoArray = VarStreamArray<LineColumnEntry, LineColumnExtractor>;
|
||||
using Iterator = LineInfoArray::Iterator;
|
||||
|
||||
public:
|
||||
DebugLinesSubsectionRef();
|
||||
@ -130,14 +137,14 @@ class DebugLinesSubsection final : public DebugSubsection {
|
||||
|
||||
private:
|
||||
DebugChecksumsSubsection &Checksums;
|
||||
|
||||
uint32_t RelocOffset = 0;
|
||||
uint16_t RelocSegment = 0;
|
||||
uint32_t CodeSize = 0;
|
||||
LineFlags Flags = LF_None;
|
||||
std::vector<Block> Blocks;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGLINESSUBSECTION_H
|
||||
|
@ -12,17 +12,15 @@
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BinaryStreamReader;
|
||||
class BinaryStreamRef;
|
||||
class BinaryStreamWriter;
|
||||
|
||||
namespace codeview {
|
||||
|
||||
@ -83,7 +81,9 @@ class DebugStringTableSubsection : public DebugSubsection {
|
||||
StringMap<uint32_t> Strings;
|
||||
uint32_t StringSize = 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGSTRINGTABLESUBSECTION_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- DebugSubsection.h ------------------------------------*- C++ -*-===//
|
||||
//===- DebugSubsectionRecord.h ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,17 +7,22 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENTRECORD_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENTRECORD_H
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGSUBSECTIONRECORD_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_DEBUGSUBSECTIONRECORD_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamRef.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BinaryStreamWriter;
|
||||
|
||||
namespace codeview {
|
||||
|
||||
class DebugSubsection;
|
||||
@ -42,8 +47,8 @@ class DebugSubsectionRecord {
|
||||
BinaryStreamRef getRecordData() const;
|
||||
|
||||
private:
|
||||
CodeViewContainer Container;
|
||||
DebugSubsectionKind Kind;
|
||||
CodeViewContainer Container = CodeViewContainer::ObjectFile;
|
||||
DebugSubsectionKind Kind = DebugSubsectionKind::None;
|
||||
BinaryStreamRef Data;
|
||||
};
|
||||
|
||||
@ -71,7 +76,7 @@ class DebugSubsectionRecordBuilder {
|
||||
CodeViewContainer Container;
|
||||
};
|
||||
|
||||
} // namespace codeview
|
||||
} // end namespace codeview
|
||||
|
||||
template <> struct VarStreamArrayExtractor<codeview::DebugSubsectionRecord> {
|
||||
Error operator()(BinaryStreamRef Stream, uint32_t &Length,
|
||||
@ -88,8 +93,11 @@ template <> struct VarStreamArrayExtractor<codeview::DebugSubsectionRecord> {
|
||||
};
|
||||
|
||||
namespace codeview {
|
||||
typedef VarStreamArray<DebugSubsectionRecord> DebugSubsectionArray;
|
||||
}
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_MODULEDEBUGFRAGMENTRECORD_H
|
||||
using DebugSubsectionArray = VarStreamArray<DebugSubsectionRecord>;
|
||||
|
||||
} // end namespace codeview
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGSUBSECTIONRECORD_H
|
||||
|
@ -10,17 +10,23 @@
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_DEBUGSYMBOLRVASUBSECTION_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_DEBUGSYMBOLRVASUBSECTION_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BinaryStreamReader;
|
||||
|
||||
namespace codeview {
|
||||
|
||||
class DebugSymbolRVASubsectionRef final : public DebugSubsectionRef {
|
||||
public:
|
||||
typedef FixedStreamArray<support::ulittle32_t> ArrayType;
|
||||
using ArrayType = FixedStreamArray<support::ulittle32_t>;
|
||||
|
||||
DebugSymbolRVASubsectionRef();
|
||||
|
||||
@ -53,7 +59,9 @@ class DebugSymbolRVASubsection final : public DebugSubsection {
|
||||
private:
|
||||
std::vector<support::ulittle32_t> RVAs;
|
||||
};
|
||||
} // namespace codeview
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_DEBUGSYMBOLRVASUBSECTION_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- EnumTables.h Enum to string conversion tables ------------*- C++ -*-===//
|
||||
//===- EnumTables.h - Enum to string conversion tables ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -14,11 +14,11 @@
|
||||
#include "llvm/BinaryFormat/COFF.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames();
|
||||
ArrayRef<EnumEntry<TypeLeafKind>> getTypeLeafNames();
|
||||
ArrayRef<EnumEntry<uint16_t>> getRegisterNames();
|
||||
@ -38,7 +38,8 @@ ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames();
|
||||
ArrayRef<EnumEntry<uint16_t>> getTrampolineNames();
|
||||
ArrayRef<EnumEntry<COFF::SectionCharacteristics>>
|
||||
getImageSectionCharacteristicNames();
|
||||
} // namespace codeview
|
||||
} // namespace llvm
|
||||
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_ENUMTABLES_H
|
||||
|
@ -14,21 +14,27 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatProviders.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace codeview {
|
||||
|
||||
namespace detail {
|
||||
class GuidAdapter final : public llvm::FormatAdapter<ArrayRef<uint8_t>> {
|
||||
|
||||
class GuidAdapter final : public FormatAdapter<ArrayRef<uint8_t>> {
|
||||
ArrayRef<uint8_t> Guid;
|
||||
|
||||
public:
|
||||
explicit GuidAdapter(ArrayRef<uint8_t> Guid);
|
||||
explicit GuidAdapter(StringRef Guid);
|
||||
void format(llvm::raw_ostream &Stream, StringRef Style);
|
||||
|
||||
void format(raw_ostream &Stream, StringRef Style) override ;
|
||||
};
|
||||
}
|
||||
|
||||
} // end namespace detail
|
||||
|
||||
inline detail::GuidAdapter fmt_guid(StringRef Item) {
|
||||
return detail::GuidAdapter(Item);
|
||||
@ -37,11 +43,12 @@ inline detail::GuidAdapter fmt_guid(StringRef Item) {
|
||||
inline detail::GuidAdapter fmt_guid(ArrayRef<uint8_t> Item) {
|
||||
return detail::GuidAdapter(Item);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace codeview
|
||||
|
||||
template <> struct format_provider<codeview::TypeIndex> {
|
||||
public:
|
||||
static void format(const codeview::TypeIndex &V, llvm::raw_ostream &Stream,
|
||||
static void format(const codeview::TypeIndex &V, raw_ostream &Stream,
|
||||
StringRef Style) {
|
||||
if (V.isNoneType())
|
||||
Stream << "<no type>";
|
||||
@ -52,6 +59,7 @@ template <> struct format_provider<codeview::TypeIndex> {
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_FORMATTERS_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- LazyRandomTypeCollection.h ---------------------------- *- C++ --*-===//
|
||||
//===- LazyRandomTypeCollection.h -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -10,12 +10,18 @@
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/StringSaver.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
@ -43,7 +49,8 @@ namespace codeview {
|
||||
/// into M chunks of roughly equal size, this yields a worst case lookup time
|
||||
/// of O(N/M) and an amortized time of O(1).
|
||||
class LazyRandomTypeCollection : public TypeCollection {
|
||||
typedef FixedStreamArray<TypeIndexOffset> PartialOffsetArray;
|
||||
using PartialOffsetArray = FixedStreamArray<TypeIndexOffset>;
|
||||
|
||||
struct CacheEntry {
|
||||
CVType Type;
|
||||
uint32_t Offset;
|
||||
|
@ -7,23 +7,18 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_STRINGS_AND_CHECKSUMS_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_STRINGS_AND_CHECKSUMS_H
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_STRINGSANDCHECKSUMS_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_STRINGSANDCHECKSUMS_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class DebugSubsectionRecord;
|
||||
class DebugChecksumsSubsectionRef;
|
||||
class DebugStringTableSubsectionRef;
|
||||
class DebugChecksumsSubsection;
|
||||
class DebugStringTableSubsection;
|
||||
|
||||
class StringsAndChecksumsRef {
|
||||
public:
|
||||
// If no subsections are known about initially, we find as much as we can.
|
||||
@ -83,8 +78,9 @@ class StringsAndChecksums {
|
||||
public:
|
||||
using StringsPtr = std::shared_ptr<DebugStringTableSubsection>;
|
||||
using ChecksumsPtr = std::shared_ptr<DebugChecksumsSubsection>;
|
||||
|
||||
// If no subsections are known about initially, we find as much as we can.
|
||||
StringsAndChecksums() {}
|
||||
StringsAndChecksums() = default;
|
||||
|
||||
void setStrings(const StringsPtr &SP) { Strings = SP; }
|
||||
void setChecksums(const ChecksumsPtr &CP) { Checksums = CP; }
|
||||
@ -100,7 +96,7 @@ class StringsAndChecksums {
|
||||
ChecksumsPtr Checksums;
|
||||
};
|
||||
|
||||
} // namespace codeview
|
||||
} // namespace llvm
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_STRINGSANDCHECKSUMS_H
|
||||
|
@ -51,6 +51,10 @@ class SymbolDeserializer : public SymbolVisitorCallbacks {
|
||||
CodeViewContainer Container)
|
||||
: Delegate(Delegate), Container(Container) {}
|
||||
|
||||
Error visitSymbolBegin(CVSymbol &Record, uint32_t Offset) override {
|
||||
return visitSymbolBegin(Record);
|
||||
}
|
||||
|
||||
Error visitSymbolBegin(CVSymbol &Record) override {
|
||||
assert(!Mapping && "Already in a symbol mapping!");
|
||||
Mapping = llvm::make_unique<MappingInfo>(Record.content(), Container);
|
||||
|
@ -21,8 +21,6 @@
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/Support/BinaryStreamArray.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
@ -35,6 +33,7 @@ class SymbolRecord {
|
||||
|
||||
public:
|
||||
SymbolRecordKind getKind() const { return Kind; }
|
||||
|
||||
SymbolRecordKind Kind;
|
||||
};
|
||||
|
||||
@ -153,6 +152,7 @@ class CallerSym : public SymbolRecord {
|
||||
: SymbolRecord(Kind), RecordOffset(RecordOffset) {}
|
||||
|
||||
std::vector<TypeIndex> Indices;
|
||||
|
||||
uint32_t RecordOffset;
|
||||
};
|
||||
|
||||
@ -165,8 +165,8 @@ struct BinaryAnnotationIterator {
|
||||
int32_t S1;
|
||||
};
|
||||
|
||||
BinaryAnnotationIterator(ArrayRef<uint8_t> Annotations) : Data(Annotations) {}
|
||||
BinaryAnnotationIterator() = default;
|
||||
BinaryAnnotationIterator(ArrayRef<uint8_t> Annotations) : Data(Annotations) {}
|
||||
BinaryAnnotationIterator(const BinaryAnnotationIterator &Other)
|
||||
: Data(Other.Data) {}
|
||||
|
||||
@ -342,8 +342,8 @@ class InlineSiteSym : public SymbolRecord {
|
||||
: SymbolRecord(SymbolRecordKind::InlineSiteSym),
|
||||
RecordOffset(RecordOffset) {}
|
||||
|
||||
llvm::iterator_range<BinaryAnnotationIterator> annotations() const {
|
||||
return llvm::make_range(BinaryAnnotationIterator(AnnotationData),
|
||||
iterator_range<BinaryAnnotationIterator> annotations() const {
|
||||
return make_range(BinaryAnnotationIterator(AnnotationData),
|
||||
BinaryAnnotationIterator());
|
||||
}
|
||||
|
||||
@ -479,6 +479,7 @@ class DefRangeRegisterSym : public SymbolRecord {
|
||||
ulittle16_t Register;
|
||||
ulittle16_t MayHaveNoName;
|
||||
};
|
||||
|
||||
explicit DefRangeRegisterSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
|
||||
DefRangeRegisterSym(uint32_t RecordOffset)
|
||||
: SymbolRecord(SymbolRecordKind::DefRangeRegisterSym),
|
||||
@ -501,6 +502,7 @@ class DefRangeSubfieldRegisterSym : public SymbolRecord {
|
||||
ulittle16_t MayHaveNoName;
|
||||
ulittle32_t OffsetInParent;
|
||||
};
|
||||
|
||||
explicit DefRangeSubfieldRegisterSym(SymbolRecordKind Kind)
|
||||
: SymbolRecord(Kind) {}
|
||||
DefRangeSubfieldRegisterSym(uint32_t RecordOffset)
|
||||
@ -546,6 +548,7 @@ class DefRangeRegisterRelSym : public SymbolRecord {
|
||||
ulittle16_t Flags;
|
||||
little32_t BasePointerOffset;
|
||||
};
|
||||
|
||||
explicit DefRangeRegisterRelSym(SymbolRecordKind Kind) : SymbolRecord(Kind) {}
|
||||
explicit DefRangeRegisterRelSym(uint32_t RecordOffset)
|
||||
: SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym),
|
||||
@ -935,8 +938,8 @@ class ThreadLocalDataSym : public SymbolRecord {
|
||||
uint32_t RecordOffset;
|
||||
};
|
||||
|
||||
typedef CVRecord<SymbolKind> CVSymbol;
|
||||
typedef VarStreamArray<CVSymbol> CVSymbolArray;
|
||||
using CVSymbol = CVRecord<SymbolKind>;
|
||||
using CVSymbolArray = VarStreamArray<CVSymbol>;
|
||||
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===- symbolSerializer.h ---------------------------------------*- C++ -*-===//
|
||||
//===- SymbolSerializer.h ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -10,21 +10,20 @@
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_SYMBOLSERIALIZER_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_SYMBOLSERIALIZER_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/BinaryByteStream.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class BinaryStreamWriter;
|
||||
namespace codeview {
|
||||
|
||||
class SymbolSerializer : public SymbolVisitorCallbacks {
|
||||
@ -45,6 +44,8 @@ class SymbolSerializer : public SymbolVisitorCallbacks {
|
||||
}
|
||||
|
||||
public:
|
||||
SymbolSerializer(BumpPtrAllocator &Storage, CodeViewContainer Container);
|
||||
|
||||
template <typename SymType>
|
||||
static CVSymbol writeOneSymbol(SymType &Sym, BumpPtrAllocator &Storage,
|
||||
CodeViewContainer Container) {
|
||||
@ -57,13 +58,11 @@ class SymbolSerializer : public SymbolVisitorCallbacks {
|
||||
return Result;
|
||||
}
|
||||
|
||||
SymbolSerializer(BumpPtrAllocator &Storage, CodeViewContainer Container);
|
||||
|
||||
virtual Error visitSymbolBegin(CVSymbol &Record) override;
|
||||
virtual Error visitSymbolEnd(CVSymbol &Record) override;
|
||||
Error visitSymbolBegin(CVSymbol &Record) override;
|
||||
Error visitSymbolEnd(CVSymbol &Record) override;
|
||||
|
||||
#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
|
||||
virtual Error visitKnownRecord(CVSymbol &CVR, Name &Record) override { \
|
||||
Error visitKnownRecord(CVSymbol &CVR, Name &Record) override { \
|
||||
return visitKnownRecordImpl(CVR, Record); \
|
||||
}
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
@ -75,7 +74,8 @@ class SymbolSerializer : public SymbolVisitorCallbacks {
|
||||
return Mapping.visitKnownRecord(CVR, Record);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_SYMBOLSERIALIZER_H
|
||||
|
@ -30,6 +30,14 @@ class SymbolVisitorCallbackPipeline : public SymbolVisitorCallbacks {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error visitSymbolBegin(CVSymbol &Record, uint32_t Offset) override {
|
||||
for (auto Visitor : Pipeline) {
|
||||
if (auto EC = Visitor->visitSymbolBegin(Record, Offset))
|
||||
return EC;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error visitSymbolBegin(CVSymbol &Record) override {
|
||||
for (auto Visitor : Pipeline) {
|
||||
if (auto EC = Visitor->visitSymbolBegin(Record))
|
||||
|
@ -29,8 +29,10 @@ class SymbolVisitorCallbacks {
|
||||
|
||||
/// Paired begin/end actions for all symbols. Receives all record data,
|
||||
/// including the fixed-length record prefix. visitSymbolBegin() should
|
||||
/// return
|
||||
/// the type of the Symbol, or an error if it cannot be determined.
|
||||
/// return the type of the Symbol, or an error if it cannot be determined.
|
||||
virtual Error visitSymbolBegin(CVSymbol &Record, uint32_t Offset) {
|
||||
return Error::success();
|
||||
}
|
||||
virtual Error visitSymbolBegin(CVSymbol &Record) { return Error::success(); }
|
||||
virtual Error visitSymbolEnd(CVSymbol &Record) { return Error::success(); }
|
||||
|
||||
|
@ -28,6 +28,8 @@ void discoverTypeIndices(ArrayRef<uint8_t> RecordData,
|
||||
SmallVectorImpl<TiReference> &Refs);
|
||||
void discoverTypeIndices(const CVType &Type,
|
||||
SmallVectorImpl<TiReference> &Refs);
|
||||
void discoverTypeIndices(const CVType &Type,
|
||||
SmallVectorImpl<TypeIndex> &Indices);
|
||||
|
||||
/// Discover type indices in symbol records. Returns false if this is an unknown
|
||||
/// record.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
@ -25,31 +26,30 @@
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BinaryStreamReader;
|
||||
|
||||
namespace codeview {
|
||||
|
||||
using support::little32_t;
|
||||
using support::ulittle16_t;
|
||||
using support::ulittle32_t;
|
||||
|
||||
typedef CVRecord<TypeLeafKind> CVType;
|
||||
typedef RemappedRecord<TypeLeafKind> RemappedType;
|
||||
using CVType = CVRecord<TypeLeafKind>;
|
||||
using RemappedType = RemappedRecord<TypeLeafKind>;
|
||||
|
||||
struct CVMemberRecord {
|
||||
TypeLeafKind Kind;
|
||||
ArrayRef<uint8_t> Data;
|
||||
};
|
||||
typedef VarStreamArray<CVType> CVTypeArray;
|
||||
typedef iterator_range<CVTypeArray::Iterator> CVTypeRange;
|
||||
using CVTypeArray = VarStreamArray<CVType>;
|
||||
using CVTypeRange = iterator_range<CVTypeArray::Iterator>;
|
||||
|
||||
/// Equvalent to CV_fldattr_t in cvinfo.h.
|
||||
struct MemberAttributes {
|
||||
uint16_t Attrs = 0;
|
||||
|
||||
enum {
|
||||
MethodKindShift = 2,
|
||||
};
|
||||
|
||||
MemberAttributes() = default;
|
||||
|
||||
explicit MemberAttributes(MemberAccess Access)
|
||||
@ -226,6 +226,7 @@ class MemberFuncIdRecord : public TypeRecord {
|
||||
TypeIndex getClassType() const { return ClassType; }
|
||||
TypeIndex getFunctionType() const { return FunctionType; }
|
||||
StringRef getName() const { return Name; }
|
||||
|
||||
TypeIndex ClassType;
|
||||
TypeIndex FunctionType;
|
||||
StringRef Name;
|
||||
@ -330,7 +331,6 @@ class PointerRecord : public TypeRecord {
|
||||
|
||||
TypeIndex ReferentType;
|
||||
uint32_t Attrs;
|
||||
|
||||
Optional<MemberPointerInfo> MemberInfo;
|
||||
|
||||
private:
|
||||
@ -490,6 +490,7 @@ class EnumRecord : public TagRecord {
|
||||
UnderlyingType(UnderlyingType) {}
|
||||
|
||||
TypeIndex getUnderlyingType() const { return UnderlyingType; }
|
||||
|
||||
TypeIndex UnderlyingType;
|
||||
};
|
||||
|
||||
@ -505,6 +506,7 @@ class BitFieldRecord : public TypeRecord {
|
||||
TypeIndex getType() const { return Type; }
|
||||
uint8_t getBitOffset() const { return BitOffset; }
|
||||
uint8_t getBitSize() const { return BitSize; }
|
||||
|
||||
TypeIndex Type;
|
||||
uint8_t BitSize;
|
||||
uint8_t BitOffset;
|
||||
@ -527,6 +529,7 @@ class VFTableShapeRecord : public TypeRecord {
|
||||
}
|
||||
|
||||
uint32_t getEntryCount() const { return getSlots().size(); }
|
||||
|
||||
ArrayRef<VFTableSlotKind> SlotsRef;
|
||||
std::vector<VFTableSlotKind> Slots;
|
||||
};
|
||||
@ -541,9 +544,7 @@ class TypeServer2Record : public TypeRecord {
|
||||
Name(Name) {}
|
||||
|
||||
StringRef getGuid() const { return Guid; }
|
||||
|
||||
uint32_t getAge() const { return Age; }
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
|
||||
StringRef Guid;
|
||||
@ -560,8 +561,8 @@ class StringIdRecord : public TypeRecord {
|
||||
: TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {}
|
||||
|
||||
TypeIndex getId() const { return Id; }
|
||||
|
||||
StringRef getString() const { return String; }
|
||||
|
||||
TypeIndex Id;
|
||||
StringRef String;
|
||||
};
|
||||
@ -576,9 +577,7 @@ class FuncIdRecord : public TypeRecord {
|
||||
FunctionType(FunctionType), Name(Name) {}
|
||||
|
||||
TypeIndex getParentScope() const { return ParentScope; }
|
||||
|
||||
TypeIndex getFunctionType() const { return FunctionType; }
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
|
||||
TypeIndex ParentScope;
|
||||
@ -635,6 +634,7 @@ class BuildInfoRecord : public TypeRecord {
|
||||
ArgIndices(ArgIndices.begin(), ArgIndices.end()) {}
|
||||
|
||||
ArrayRef<TypeIndex> getArgs() const { return ArgIndices; }
|
||||
|
||||
SmallVector<TypeIndex, 4> ArgIndices;
|
||||
};
|
||||
|
||||
@ -656,6 +656,7 @@ class VFTableRecord : public TypeRecord {
|
||||
TypeIndex getOverriddenVTable() const { return OverriddenVFTable; }
|
||||
uint32_t getVFPtrOffset() const { return VFPtrOffset; }
|
||||
StringRef getName() const { return makeArrayRef(MethodNames).front(); }
|
||||
|
||||
ArrayRef<StringRef> getMethodNames() const {
|
||||
return makeArrayRef(MethodNames).drop_front();
|
||||
}
|
||||
@ -707,6 +708,7 @@ class MethodOverloadListRecord : public TypeRecord {
|
||||
: TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {}
|
||||
|
||||
ArrayRef<OneMethodRecord> getMethods() const { return Methods; }
|
||||
|
||||
std::vector<OneMethodRecord> Methods;
|
||||
};
|
||||
|
||||
@ -723,6 +725,7 @@ class OverloadedMethodRecord : public TypeRecord {
|
||||
uint16_t getNumOverloads() const { return NumOverloads; }
|
||||
TypeIndex getMethodList() const { return MethodList; }
|
||||
StringRef getName() const { return Name; }
|
||||
|
||||
uint16_t NumOverloads;
|
||||
TypeIndex MethodList;
|
||||
StringRef Name;
|
||||
@ -874,7 +877,6 @@ class ListContinuationRecord : public TypeRecord {
|
||||
};
|
||||
|
||||
} // end namespace codeview
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_TYPERECORD_H
|
||||
|
@ -10,19 +10,25 @@
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||
#include "llvm/Support/BinaryByteStream.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/BinaryByteStream.h"
|
||||
#include "llvm/Support/BinaryStreamWriter.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace codeview {
|
||||
|
||||
class TypeHasher;
|
||||
@ -46,7 +52,7 @@ class TypeSerializer : public TypeVisitorCallbacks {
|
||||
}
|
||||
};
|
||||
|
||||
typedef SmallVector<MutableArrayRef<uint8_t>, 2> MutableRecordList;
|
||||
using MutableRecordList = SmallVector<MutableArrayRef<uint8_t>, 2>;
|
||||
|
||||
static constexpr uint8_t ContinuationLength = 8;
|
||||
BumpPtrAllocator &RecordStorage;
|
||||
@ -82,7 +88,7 @@ class TypeSerializer : public TypeVisitorCallbacks {
|
||||
|
||||
public:
|
||||
explicit TypeSerializer(BumpPtrAllocator &Storage, bool Hash = true);
|
||||
~TypeSerializer();
|
||||
~TypeSerializer() override;
|
||||
|
||||
void reset();
|
||||
|
||||
@ -146,7 +152,8 @@ class TypeSerializer : public TypeVisitorCallbacks {
|
||||
return Error::success();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
|
||||
|
@ -10,16 +10,17 @@
|
||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERVERHANDLER_H
|
||||
#define LLVM_DEBUGINFO_CODEVIEW_TYPESERVERHANDLER_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
|
||||
class TypeServer2Record;
|
||||
class TypeVisitorCallbacks;
|
||||
|
||||
class TypeServerHandler {
|
||||
public:
|
||||
virtual ~TypeServerHandler() {}
|
||||
virtual ~TypeServerHandler() = default;
|
||||
|
||||
/// Handle a TypeServer record. If the implementation returns true
|
||||
/// the record will not be processed by the top-level visitor. If
|
||||
@ -30,7 +31,8 @@ class TypeServerHandler {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
} // end namespace codeview
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_DEBUGINFO_CODEVIEW_TYPESERVERHANDLER_H
|
||||
|
@ -12,8 +12,8 @@
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
|
||||
#include "llvm/Support/DataExtractor.h"
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
@ -41,20 +41,31 @@ class DWARFAcceleratorTable {
|
||||
|
||||
struct Header Hdr;
|
||||
struct HeaderData HdrData;
|
||||
DataExtractor AccelSection;
|
||||
DWARFDataExtractor AccelSection;
|
||||
DataExtractor StringSection;
|
||||
const RelocAddrMap& Relocs;
|
||||
|
||||
public:
|
||||
DWARFAcceleratorTable(DataExtractor AccelSection, DataExtractor StringSection,
|
||||
const RelocAddrMap &Relocs)
|
||||
: AccelSection(AccelSection), StringSection(StringSection), Relocs(Relocs) {}
|
||||
DWARFAcceleratorTable(const DWARFDataExtractor &AccelSection,
|
||||
DataExtractor StringSection)
|
||||
: AccelSection(AccelSection), StringSection(StringSection) {}
|
||||
|
||||
bool extract();
|
||||
uint32_t getNumBuckets();
|
||||
uint32_t getNumHashes();
|
||||
uint32_t getSizeHdr();
|
||||
uint32_t getHeaderDataLength();
|
||||
ArrayRef<std::pair<HeaderData::AtomType, HeaderData::Form>> getAtomsDesc();
|
||||
bool validateForms();
|
||||
|
||||
/// Return information related to the DWARF DIE we're looking for when
|
||||
/// performing a lookup by name.
|
||||
///
|
||||
/// \param HashDataOffset an offset into the hash data table
|
||||
/// \returns DIEOffset the offset into the .debug_info section for the DIE
|
||||
/// related to the input hash data offset. Currently this function returns
|
||||
/// only the DIEOffset but it can be modified to return more data regarding
|
||||
/// the DIE
|
||||
uint32_t readAtoms(uint32_t &HashDataOffset);
|
||||
void dump(raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
|
@ -20,8 +20,8 @@ class DWARFCompileUnit : public DWARFUnit {
|
||||
DWARFCompileUnit(DWARFContext &Context, const DWARFSection &Section,
|
||||
const DWARFDebugAbbrev *DA, const DWARFSection *RS,
|
||||
StringRef SS, const DWARFSection &SOS,
|
||||
const DWARFSection *AOS, StringRef LS, bool LE, bool IsDWO,
|
||||
const DWARFUnitSectionBase &UnitSection,
|
||||
const DWARFSection *AOS, const DWARFSection &LS, bool LE,
|
||||
bool IsDWO, const DWARFUnitSectionBase &UnitSection,
|
||||
const DWARFUnitIndex::Entry *Entry)
|
||||
: DWARFUnit(Context, Section, DA, RS, SS, SOS, AOS, LS, LE, IsDWO,
|
||||
UnitSection, Entry) {}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user