diff --git a/contrib/compiler-rt/include/xray/xray_interface.h b/contrib/compiler-rt/include/xray/xray_interface.h index dc0c277aa841..564613417069 100644 --- a/contrib/compiler-rt/include/xray/xray_interface.h +++ b/contrib/compiler-rt/include/xray/xray_interface.h @@ -60,7 +60,8 @@ extern int __xray_remove_handler(); /// start logging their subsequent affected function calls (if patched). /// /// Returns 1 on success, 0 on error. -extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t)); +extern int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType, + uint64_t)); /// Disables the XRay handler used to log first arguments of function calls. /// Returns 1 on success, 0 on error. diff --git a/contrib/compiler-rt/lib/asan/asan_allocator.cc b/contrib/compiler-rt/lib/asan/asan_allocator.cc index 1ded7794c9f4..57651f49cdb9 100644 --- a/contrib/compiler-rt/lib/asan/asan_allocator.cc +++ b/contrib/compiler-rt/lib/asan/asan_allocator.cc @@ -160,7 +160,7 @@ struct QuarantineCallback { } void *Allocate(uptr size) { - return get_allocator().Allocate(cache_, size, 1, false); + return get_allocator().Allocate(cache_, size, 1); } void Deallocate(void *p) { @@ -266,7 +266,8 @@ struct Allocator { } void Initialize(const AllocatorOptions &options) { - allocator.Init(options.may_return_null, options.release_to_os_interval_ms); + SetAllocatorMayReturnNull(options.may_return_null); + allocator.Init(options.release_to_os_interval_ms); SharedInitCode(options); } @@ -302,7 +303,7 @@ struct Allocator { } void ReInitialize(const AllocatorOptions &options) { - allocator.SetMayReturnNull(options.may_return_null); + SetAllocatorMayReturnNull(options.may_return_null); allocator.SetReleaseToOSIntervalMs(options.release_to_os_interval_ms); SharedInitCode(options); @@ -323,7 +324,7 @@ struct Allocator { options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10; options->min_redzone = atomic_load(&min_redzone, memory_order_acquire); options->max_redzone = atomic_load(&max_redzone, memory_order_acquire); - options->may_return_null = allocator.MayReturnNull(); + options->may_return_null = AllocatorMayReturnNull(); options->alloc_dealloc_mismatch = atomic_load(&alloc_dealloc_mismatch, memory_order_acquire); options->release_to_os_interval_ms = allocator.ReleaseToOSIntervalMs(); @@ -374,7 +375,7 @@ struct Allocator { if (UNLIKELY(!asan_inited)) AsanInitFromRtl(); if (RssLimitExceeded()) - return allocator.ReturnNullOrDieOnOOM(); + return AsanAllocator::FailureHandler::OnOOM(); Flags &fl = *flags(); CHECK(stack); const uptr min_alignment = SHADOW_GRANULARITY; @@ -407,23 +408,21 @@ struct Allocator { if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) { Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", (void*)size); - return allocator.ReturnNullOrDieOnBadRequest(); + return AsanAllocator::FailureHandler::OnBadRequest(); } AsanThread *t = GetCurrentThread(); void *allocated; if (t) { AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); - allocated = - allocator.Allocate(cache, needed_size, 8, false); + allocated = allocator.Allocate(cache, needed_size, 8); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; - allocated = - allocator.Allocate(cache, needed_size, 8, false); + allocated = allocator.Allocate(cache, needed_size, 8); } - - if (!allocated) return allocator.ReturnNullOrDieOnOOM(); + if (!allocated) + return nullptr; if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) { // Heap poisoning is enabled, but the allocator provides an unpoisoned @@ -634,7 +633,7 @@ struct Allocator { void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { if (CallocShouldReturnNullDueToOverflow(size, nmemb)) - return allocator.ReturnNullOrDieOnBadRequest(); + 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 // as it comes directly from mmap. diff --git a/contrib/compiler-rt/lib/asan/asan_report.cc b/contrib/compiler-rt/lib/asan/asan_report.cc index f751b6184c6b..2e477f258b8d 100644 --- a/contrib/compiler-rt/lib/asan/asan_report.cc +++ b/contrib/compiler-rt/lib/asan/asan_report.cc @@ -204,6 +204,14 @@ class ScopedInErrorReport { error_report_callback(buffer_copy.data()); } + if (halt_on_error_ && common_flags()->abort_on_error) { + // On Android the message is truncated to 512 characters. + // FIXME: implement "compact" error format, possibly without, or with + // highly compressed stack traces? + // FIXME: or just use the summary line as abort message? + SetAbortMessage(buffer_copy.data()); + } + // In halt_on_error = false mode, reset the current error object (before // unlocking). if (!halt_on_error_) diff --git a/contrib/compiler-rt/lib/asan/weak_symbols.txt b/contrib/compiler-rt/lib/asan/weak_symbols.txt index ba7b0272c2b1..fe680f8a9a4f 100644 --- a/contrib/compiler-rt/lib/asan/weak_symbols.txt +++ b/contrib/compiler-rt/lib/asan/weak_symbols.txt @@ -1,3 +1,12 @@ ___asan_default_options ___asan_default_suppressions ___asan_on_error +___asan_set_shadow_00 +___asan_set_shadow_f1 +___asan_set_shadow_f2 +___asan_set_shadow_f3 +___asan_set_shadow_f4 +___asan_set_shadow_f5 +___asan_set_shadow_f6 +___asan_set_shadow_f7 +___asan_set_shadow_f8 diff --git a/contrib/compiler-rt/lib/interception/interception_win.cc b/contrib/compiler-rt/lib/interception/interception_win.cc index e4f3d358f40c..b2902d57f542 100644 --- a/contrib/compiler-rt/lib/interception/interception_win.cc +++ b/contrib/compiler-rt/lib/interception/interception_win.cc @@ -477,7 +477,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { switch (*(u8*)address) { case 0xA1: // A1 XX XX XX XX XX XX XX XX : // movabs eax, dword ptr ds:[XXXXXXXX] - return 8; + return 9; } switch (*(u16*)address) { @@ -495,6 +495,11 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0x5741: // push r15 case 0x9066: // Two-byte NOP return 2; + + case 0x058B: // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX] + if (rel_offset) + *rel_offset = 2; + return 6; } switch (0x00FFFFFF & *(u32*)address) { diff --git a/contrib/compiler-rt/lib/lsan/lsan.h b/contrib/compiler-rt/lib/lsan/lsan.h index 1061d2fcfde7..7446e9507e0d 100644 --- a/contrib/compiler-rt/lib/lsan/lsan.h +++ b/contrib/compiler-rt/lib/lsan/lsan.h @@ -38,6 +38,8 @@ GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \ common_flags()->fast_unwind_on_malloc) +#define GET_STACK_TRACE_THREAD GET_STACK_TRACE(kStackTraceMax, true) + namespace __lsan { void InitializeInterceptors(); diff --git a/contrib/compiler-rt/lib/lsan/lsan_allocator.cc b/contrib/compiler-rt/lib/lsan/lsan_allocator.cc index 011979eee396..f54e953731b4 100644 --- a/contrib/compiler-rt/lib/lsan/lsan_allocator.cc +++ b/contrib/compiler-rt/lib/lsan/lsan_allocator.cc @@ -38,8 +38,8 @@ typedef CombinedAllocatorallocator_may_return_null); allocator.InitLinkerInitialized( - common_flags()->allocator_may_return_null, common_flags()->allocator_release_to_os_interval_ms); } @@ -76,7 +76,7 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment, Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size); return nullptr; } - void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false); + void *p = allocator.Allocate(GetAllocatorCache(), size, alignment); // Do not rely on the allocator to clear the memory (it's slow). if (cleared && allocator.FromPrimary(p)) memset(p, 0, size); diff --git a/contrib/compiler-rt/lib/lsan/lsan_common_mac.cc b/contrib/compiler-rt/lib/lsan/lsan_common_mac.cc index 114dd8c9019e..adde3a1b4035 100644 --- a/contrib/compiler-rt/lib/lsan/lsan_common_mac.cc +++ b/contrib/compiler-rt/lib/lsan/lsan_common_mac.cc @@ -79,8 +79,7 @@ void EnableInThisThread() { u32 GetCurrentThread() { thread_local_data_t *data = get_tls_val(false); - CHECK(data); - return data->current_thread_id; + return data ? data->current_thread_id : kInvalidTid; } void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; } diff --git a/contrib/compiler-rt/lib/lsan/lsan_mac.cc b/contrib/compiler-rt/lib/lsan/lsan_mac.cc new file mode 100644 index 000000000000..1a6f5f4899b1 --- /dev/null +++ b/contrib/compiler-rt/lib/lsan/lsan_mac.cc @@ -0,0 +1,192 @@ +//===-- lsan_mac.cc -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer, a memory leak checker. +// +// Mac-specific details. +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if SANITIZER_MAC + +#include "interception/interception.h" +#include "lsan.h" +#include "lsan_allocator.h" +#include "lsan_thread.h" + +#include + +namespace __lsan { +// Support for the following functions from libdispatch on Mac OS: +// dispatch_async_f() +// dispatch_async() +// dispatch_sync_f() +// dispatch_sync() +// dispatch_after_f() +// dispatch_after() +// dispatch_group_async_f() +// dispatch_group_async() +// TODO(glider): libdispatch API contains other functions that we don't support +// yet. +// +// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are +// they can cause jobs to run on a thread different from the current one. +// TODO(glider): if so, we need a test for this (otherwise we should remove +// them). +// +// The following functions use dispatch_barrier_async_f() (which isn't a library +// function but is exported) and are thus supported: +// dispatch_source_set_cancel_handler_f() +// dispatch_source_set_cancel_handler() +// dispatch_source_set_event_handler_f() +// dispatch_source_set_event_handler() +// +// The reference manual for Grand Central Dispatch is available at +// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html +// The implementation details are at +// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c + +typedef void *dispatch_group_t; +typedef void *dispatch_queue_t; +typedef void *dispatch_source_t; +typedef u64 dispatch_time_t; +typedef void (*dispatch_function_t)(void *block); +typedef void *(*worker_t)(void *block); + +// A wrapper for the ObjC blocks used to support libdispatch. +typedef struct { + void *block; + dispatch_function_t func; + u32 parent_tid; +} lsan_block_context_t; + +ALWAYS_INLINE +void lsan_register_worker_thread(int parent_tid) { + if (GetCurrentThread() == kInvalidTid) { + u32 tid = ThreadCreate(parent_tid, 0, true); + ThreadStart(tid, GetTid()); + SetCurrentThread(tid); + } +} + +// For use by only those functions that allocated the context via +// alloc_lsan_context(). +extern "C" void lsan_dispatch_call_block_and_release(void *block) { + lsan_block_context_t *context = (lsan_block_context_t *)block; + VReport(2, + "lsan_dispatch_call_block_and_release(): " + "context: %p, pthread_self: %p\n", + block, pthread_self()); + lsan_register_worker_thread(context->parent_tid); + // Call the original dispatcher for the block. + context->func(context->block); + lsan_free(context); +} + +} // namespace __lsan + +using namespace __lsan; // NOLINT + +// Wrap |ctxt| and |func| into an lsan_block_context_t. +// The caller retains control of the allocated context. +extern "C" lsan_block_context_t *alloc_lsan_context(void *ctxt, + dispatch_function_t func) { + GET_STACK_TRACE_THREAD; + lsan_block_context_t *lsan_ctxt = + (lsan_block_context_t *)lsan_malloc(sizeof(lsan_block_context_t), stack); + lsan_ctxt->block = ctxt; + lsan_ctxt->func = func; + lsan_ctxt->parent_tid = GetCurrentThread(); + return lsan_ctxt; +} + +// Define interceptor for dispatch_*_f function with the three most common +// parameters: dispatch_queue_t, context, dispatch_function_t. +#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ + INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ + dispatch_function_t func) { \ + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); \ + return REAL(dispatch_x_f)(dq, (void *)lsan_ctxt, \ + lsan_dispatch_call_block_and_release); \ + } + +INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) +INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) +INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) + +INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq, + void *ctxt, dispatch_function_t func) { + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); + return REAL(dispatch_after_f)(when, dq, (void *)lsan_ctxt, + lsan_dispatch_call_block_and_release); +} + +INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, + dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { + lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); + REAL(dispatch_group_async_f) + (group, dq, (void *)lsan_ctxt, lsan_dispatch_call_block_and_release); +} + +#if !defined(MISSING_BLOCKS_SUPPORT) +extern "C" { +void dispatch_async(dispatch_queue_t dq, void (^work)(void)); +void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, + void (^work)(void)); +void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, + void (^work)(void)); +void dispatch_source_set_cancel_handler(dispatch_source_t ds, + void (^work)(void)); +void dispatch_source_set_event_handler(dispatch_source_t ds, + void (^work)(void)); +} + +#define GET_LSAN_BLOCK(work) \ + void (^lsan_block)(void); \ + int parent_tid = GetCurrentThread(); \ + lsan_block = ^(void) { \ + lsan_register_worker_thread(parent_tid); \ + work(); \ + } + +INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_async)(dq, lsan_block); +} + +INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg, + dispatch_queue_t dq, void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_group_async)(dg, dq, lsan_block); +} + +INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue, + void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_after)(when, queue, lsan_block); +} + +INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds, + void (^work)(void)) { + if (!work) { + REAL(dispatch_source_set_cancel_handler)(ds, work); + return; + } + GET_LSAN_BLOCK(work); + REAL(dispatch_source_set_cancel_handler)(ds, lsan_block); +} + +INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds, + void (^work)(void)) { + GET_LSAN_BLOCK(work); + REAL(dispatch_source_set_event_handler)(ds, lsan_block); +} +#endif + +#endif // SANITIZER_MAC diff --git a/contrib/compiler-rt/lib/lsan/lsan_thread.cc b/contrib/compiler-rt/lib/lsan/lsan_thread.cc index 0ea7a6e97497..4404c8cc51d2 100644 --- a/contrib/compiler-rt/lib/lsan/lsan_thread.cc +++ b/contrib/compiler-rt/lib/lsan/lsan_thread.cc @@ -77,7 +77,7 @@ u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { /* arg */ nullptr); } -void ThreadStart(u32 tid, tid_t os_id) { +void ThreadStart(u32 tid, tid_t os_id, bool workerthread) { OnStartedArgs args; uptr stack_size = 0; uptr tls_size = 0; @@ -87,7 +87,7 @@ void ThreadStart(u32 tid, tid_t os_id) { args.tls_end = args.tls_begin + tls_size; GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); args.dtls = DTLS_Get(); - thread_registry->StartThread(tid, os_id, /*workerthread*/ false, &args); + thread_registry->StartThread(tid, os_id, workerthread, &args); } void ThreadFinish() { diff --git a/contrib/compiler-rt/lib/lsan/lsan_thread.h b/contrib/compiler-rt/lib/lsan/lsan_thread.h index 73e080e26f76..b16d3d91537f 100644 --- a/contrib/compiler-rt/lib/lsan/lsan_thread.h +++ b/contrib/compiler-rt/lib/lsan/lsan_thread.h @@ -45,7 +45,7 @@ class ThreadContext : public ThreadContextBase { void InitializeThreadRegistry(); -void ThreadStart(u32 tid, tid_t os_id); +void ThreadStart(u32 tid, tid_t os_id, bool workerthread = false); void ThreadFinish(); u32 ThreadCreate(u32 tid, uptr uid, bool detached); void ThreadJoin(u32 tid); diff --git a/contrib/compiler-rt/lib/msan/msan_allocator.cc b/contrib/compiler-rt/lib/msan/msan_allocator.cc index 1be573faa412..d0f478afc9cc 100644 --- a/contrib/compiler-rt/lib/msan/msan_allocator.cc +++ b/contrib/compiler-rt/lib/msan/msan_allocator.cc @@ -119,9 +119,8 @@ static AllocatorCache fallback_allocator_cache; static SpinMutex fallback_mutex; void MsanAllocatorInit() { - allocator.Init( - common_flags()->allocator_may_return_null, - common_flags()->allocator_release_to_os_interval_ms); + SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); + allocator.Init(common_flags()->allocator_release_to_os_interval_ms); } AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) { @@ -139,17 +138,17 @@ static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment, if (size > kMaxAllowedMallocSize) { Report("WARNING: MemorySanitizer failed to allocate %p bytes\n", (void *)size); - return allocator.ReturnNullOrDieOnBadRequest(); + return Allocator::FailureHandler::OnBadRequest(); } MsanThread *t = GetCurrentThread(); void *allocated; if (t) { AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); - allocated = allocator.Allocate(cache, size, alignment, false); + allocated = allocator.Allocate(cache, size, alignment); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; - allocated = allocator.Allocate(cache, size, alignment, false); + allocated = allocator.Allocate(cache, size, alignment); } Metadata *meta = reinterpret_cast(allocator.GetMetaData(allocated)); @@ -197,7 +196,7 @@ void MsanDeallocate(StackTrace *stack, void *p) { void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) { if (CallocShouldReturnNullDueToOverflow(size, nmemb)) - return allocator.ReturnNullOrDieOnBadRequest(); + return Allocator::FailureHandler::OnBadRequest(); return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true); } diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc index d47b5b41413c..db3ebb0336a9 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc @@ -94,8 +94,7 @@ InternalAllocator *internal_allocator() { SpinMutexLock l(&internal_alloc_init_mu); if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) == 0) { - internal_allocator_instance->Init( - /* may_return_null */ false, kReleaseToOSIntervalNever); + internal_allocator_instance->Init(kReleaseToOSIntervalNever); atomic_store(&internal_allocator_initialized, 1, memory_order_release); } } @@ -108,9 +107,9 @@ static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache, if (cache == 0) { SpinMutexLock l(&internal_allocator_cache_mu); return internal_allocator()->Allocate(&internal_allocator_cache, size, - alignment, false); + alignment); } - return internal_allocator()->Allocate(cache, size, alignment, false); + return internal_allocator()->Allocate(cache, size, alignment); } static void *RawInternalRealloc(void *ptr, uptr size, @@ -162,7 +161,7 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) { void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) { if (CallocShouldReturnNullDueToOverflow(count, size)) - return internal_allocator()->ReturnNullOrDieOnBadRequest(); + return InternalAllocator::FailureHandler::OnBadRequest(); void *p = InternalAlloc(count * size, cache); if (p) internal_memset(p, 0, count * size); return p; @@ -209,12 +208,15 @@ bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) { return (max / size) < n; } -static atomic_uint8_t reporting_out_of_memory = {0}; +static atomic_uint8_t allocator_out_of_memory = {0}; +static atomic_uint8_t allocator_may_return_null = {0}; -bool IsReportingOOM() { return atomic_load_relaxed(&reporting_out_of_memory); } +bool IsAllocatorOutOfMemory() { + return atomic_load_relaxed(&allocator_out_of_memory); +} -void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory) { - if (out_of_memory) atomic_store_relaxed(&reporting_out_of_memory, 1); +// Prints error message and kills the program. +void NORETURN ReportAllocatorCannotReturnNull() { Report("%s's allocator is terminating the process instead of returning 0\n", SanitizerToolName); Report("If you don't like this behavior set allocator_may_return_null=1\n"); @@ -222,4 +224,35 @@ void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory) { Die(); } +bool AllocatorMayReturnNull() { + return atomic_load(&allocator_may_return_null, memory_order_relaxed); +} + +void SetAllocatorMayReturnNull(bool may_return_null) { + atomic_store(&allocator_may_return_null, may_return_null, + memory_order_relaxed); +} + +void *ReturnNullOrDieOnFailure::OnBadRequest() { + if (AllocatorMayReturnNull()) + return nullptr; + ReportAllocatorCannotReturnNull(); +} + +void *ReturnNullOrDieOnFailure::OnOOM() { + atomic_store_relaxed(&allocator_out_of_memory, 1); + if (AllocatorMayReturnNull()) + return nullptr; + ReportAllocatorCannotReturnNull(); +} + +void *DieOnFailure::OnBadRequest() { + ReportAllocatorCannotReturnNull(); +} + +void *DieOnFailure::OnOOM() { + atomic_store_relaxed(&allocator_out_of_memory, 1); + ReportAllocatorCannotReturnNull(); +} + } // namespace __sanitizer diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h index 9a37a2f2145f..f59c13d1c5a5 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator.h @@ -24,12 +24,28 @@ namespace __sanitizer { -// Returns true if ReportAllocatorCannotReturnNull(true) was called. -// Can be use to avoid memory hungry operations. -bool IsReportingOOM(); +// Since flags are immutable and allocator behavior can be changed at runtime +// (unit tests or ASan on Android are some examples), allocator_may_return_null +// flag value is cached here and can be altered later. +bool AllocatorMayReturnNull(); +void SetAllocatorMayReturnNull(bool may_return_null); -// Prints error message and kills the program. -void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory); +// Allocator failure handling policies: +// Implements AllocatorMayReturnNull policy, returns null when the flag is set, +// dies otherwise. +struct ReturnNullOrDieOnFailure { + static void *OnBadRequest(); + static void *OnOOM(); +}; +// Always dies on the failure. +struct DieOnFailure { + static void *OnBadRequest(); + static void *OnOOM(); +}; + +// Returns true if allocator detected OOM condition. Can be used to avoid memory +// hungry operations. Set when AllocatorReturnNullOrDieOnOOM() is called. +bool IsAllocatorOutOfMemory(); // Allocators call these callbacks on mmap/munmap. struct NoOpMapUnmapCallback { diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_combined.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_combined.h index 2c2390b3d2c6..efd25cadfe74 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_combined.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_combined.h @@ -24,31 +24,26 @@ template // NOLINT class CombinedAllocator { public: - void InitCommon(bool may_return_null, s32 release_to_os_interval_ms) { + typedef typename SecondaryAllocator::FailureHandler FailureHandler; + + void InitLinkerInitialized(s32 release_to_os_interval_ms) { primary_.Init(release_to_os_interval_ms); - atomic_store(&may_return_null_, may_return_null, memory_order_relaxed); - } - - void InitLinkerInitialized( - bool may_return_null, s32 release_to_os_interval_ms) { - secondary_.InitLinkerInitialized(may_return_null); + secondary_.InitLinkerInitialized(); stats_.InitLinkerInitialized(); - InitCommon(may_return_null, release_to_os_interval_ms); } - void Init(bool may_return_null, s32 release_to_os_interval_ms) { - secondary_.Init(may_return_null); + void Init(s32 release_to_os_interval_ms) { + primary_.Init(release_to_os_interval_ms); + secondary_.Init(); stats_.Init(); - InitCommon(may_return_null, release_to_os_interval_ms); } - void *Allocate(AllocatorCache *cache, uptr size, uptr alignment, - bool cleared = false) { + void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) { // Returning 0 on malloc(0) may break a lot of code. if (size == 0) size = 1; if (size + alignment < size) - return ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); uptr original_size = size; // If alignment requirements are to be fulfilled by the frontend allocator // rather than by the primary or secondary, passing an alignment lower than @@ -56,49 +51,24 @@ class CombinedAllocator { // alignment check. if (alignment > 8) size = RoundUpTo(size, alignment); - void *res; - bool from_primary = primary_.CanAllocate(size, alignment); // The primary allocator should return a 2^x aligned allocation when // requested 2^x bytes, hence using the rounded up 'size' when being // serviced by the primary (this is no longer true when the primary is // using a non-fixed base address). The secondary takes care of the // alignment without such requirement, and allocating 'size' would use // extraneous memory, so we employ 'original_size'. - if (from_primary) + void *res; + if (primary_.CanAllocate(size, alignment)) res = cache->Allocate(&primary_, primary_.ClassID(size)); else res = secondary_.Allocate(&stats_, original_size, alignment); + if (!res) + return FailureHandler::OnOOM(); if (alignment > 8) CHECK_EQ(reinterpret_cast(res) & (alignment - 1), 0); - // When serviced by the secondary, the chunk comes from a mmap allocation - // and will be zero'd out anyway. We only need to clear our the chunk if - // it was serviced by the primary, hence using the rounded up 'size'. - if (cleared && res && from_primary) - internal_bzero_aligned16(res, RoundUpTo(size, 16)); return res; } - bool MayReturnNull() const { - return atomic_load(&may_return_null_, memory_order_acquire); - } - - void *ReturnNullOrDieOnBadRequest() { - if (MayReturnNull()) - return nullptr; - ReportAllocatorCannotReturnNull(false); - } - - void *ReturnNullOrDieOnOOM() { - if (MayReturnNull()) - return nullptr; - ReportAllocatorCannotReturnNull(true); - } - - void SetMayReturnNull(bool may_return_null) { - secondary_.SetMayReturnNull(may_return_null); - atomic_store(&may_return_null_, may_return_null, memory_order_release); - } - s32 ReleaseToOSIntervalMs() const { return primary_.ReleaseToOSIntervalMs(); } @@ -219,6 +189,5 @@ class CombinedAllocator { PrimaryAllocator primary_; SecondaryAllocator secondary_; AllocatorGlobalStats stats_; - atomic_uint8_t may_return_null_; }; diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h index d1890f20f810..a791d0d94894 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_internal.h @@ -47,7 +47,8 @@ typedef SizeClassAllocatorLocalCache InternalAllocatorCache; typedef CombinedAllocator > InternalAllocator; + LargeMmapAllocator + > InternalAllocator; void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr, uptr alignment = 0); diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h index b3729bf55dbb..8fa62a3bf829 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_local_cache.h @@ -144,8 +144,10 @@ struct SizeClassAllocator32LocalCache { CHECK_NE(class_id, 0UL); CHECK_LT(class_id, kNumClasses); PerClass *c = &per_class_[class_id]; - if (UNLIKELY(c->count == 0)) - Refill(allocator, class_id); + if (UNLIKELY(c->count == 0)) { + if (UNLIKELY(!Refill(allocator, class_id))) + return nullptr; + } stats_.Add(AllocatorStatAllocated, c->class_size); void *res = c->batch[--c->count]; PREFETCH(c->batch[c->count - 1]); @@ -227,14 +229,17 @@ struct SizeClassAllocator32LocalCache { Deallocate(allocator, batch_class_id, b); } - NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) { + NOINLINE bool Refill(SizeClassAllocator *allocator, uptr class_id) { InitCache(); PerClass *c = &per_class_[class_id]; TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id); + if (UNLIKELY(!b)) + return false; CHECK_GT(b->Count(), 0); b->CopyToArray(c->batch); c->count = b->Count(); DestroyBatch(class_id, allocator, b); + return true; } NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) { @@ -244,6 +249,10 @@ struct SizeClassAllocator32LocalCache { uptr first_idx_to_drain = c->count - cnt; TransferBatch *b = CreateBatch( class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]); + // Failure to allocate a batch while releasing memory is non recoverable. + // TODO(alekseys): Figure out how to do it without allocating a new batch. + if (UNLIKELY(!b)) + DieOnFailure::OnOOM(); b->SetFromArray(allocator->GetRegionBeginBySizeClass(class_id), &c->batch[first_idx_to_drain], cnt); c->count -= cnt; diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h index e13510ba33b9..d3949cc05734 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_primary32.h @@ -24,7 +24,8 @@ template struct SizeClassAllocator32LocalCache; // be returned by MmapOrDie(). // // Region: -// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize). +// a result of a single call to MmapAlignedOrDieOnFatalError(kRegionSize, +// kRegionSize). // Since the regions are aligned by kRegionSize, there are exactly // kNumPossibleRegions possible regions in the address space and so we keep // a ByteMap possible_regions to store the size classes of each Region. @@ -149,8 +150,9 @@ class SizeClassAllocator32 { CHECK_LT(class_id, kNumClasses); SizeClassInfo *sci = GetSizeClassInfo(class_id); SpinMutexLock l(&sci->mutex); - if (sci->free_list.empty()) - PopulateFreeList(stat, c, sci, class_id); + if (sci->free_list.empty() && + UNLIKELY(!PopulateFreeList(stat, c, sci, class_id))) + return nullptr; CHECK(!sci->free_list.empty()); TransferBatch *b = sci->free_list.front(); sci->free_list.pop_front(); @@ -277,8 +279,10 @@ class SizeClassAllocator32 { uptr AllocateRegion(AllocatorStats *stat, uptr class_id) { CHECK_LT(class_id, kNumClasses); - uptr res = reinterpret_cast(MmapAlignedOrDie(kRegionSize, kRegionSize, - "SizeClassAllocator32")); + uptr res = reinterpret_cast(MmapAlignedOrDieOnFatalError( + kRegionSize, kRegionSize, "SizeClassAllocator32")); + if (UNLIKELY(!res)) + return 0; MapUnmapCallback().OnMap(res, kRegionSize); stat->Add(AllocatorStatMapped, kRegionSize); CHECK_EQ(0U, (res & (kRegionSize - 1))); @@ -291,16 +295,20 @@ class SizeClassAllocator32 { return &size_class_info_array[class_id]; } - void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, + bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c, SizeClassInfo *sci, uptr class_id) { uptr size = ClassIdToSize(class_id); uptr reg = AllocateRegion(stat, class_id); + if (UNLIKELY(!reg)) + return false; uptr n_chunks = kRegionSize / (size + kMetadataSize); uptr max_count = TransferBatch::MaxCached(class_id); 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) + return false; b->Clear(); } b->Add((void*)i); @@ -314,6 +322,7 @@ class SizeClassAllocator32 { CHECK_GT(b->Count(), 0); sci->free_list.push_back(b); } + return true; } ByteMap possible_regions; diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h index 2c69f47ec4e6..261dfb5e1a28 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_allocator_secondary.h @@ -17,17 +17,19 @@ // This class can (de)allocate only large chunks of memory using mmap/unmap. // The main purpose of this allocator is to cover large and rare allocation // sizes not covered by more efficient allocators (e.g. SizeClassAllocator64). -template +template class LargeMmapAllocator { public: - void InitLinkerInitialized(bool may_return_null) { + typedef FailureHandlerT FailureHandler; + + void InitLinkerInitialized() { page_size_ = GetPageSizeCached(); - atomic_store(&may_return_null_, may_return_null, memory_order_relaxed); } - void Init(bool may_return_null) { + void Init() { internal_memset(this, 0, sizeof(*this)); - InitLinkerInitialized(may_return_null); + InitLinkerInitialized(); } void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) { @@ -37,11 +39,11 @@ class LargeMmapAllocator { map_size += alignment; // Overflow. if (map_size < size) - return ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); uptr map_beg = reinterpret_cast( MmapOrDieOnFatalError(map_size, "LargeMmapAllocator")); if (!map_beg) - return ReturnNullOrDieOnOOM(); + return FailureHandler::OnOOM(); CHECK(IsAligned(map_beg, page_size_)); MapUnmapCallback().OnMap(map_beg, map_size); uptr map_end = map_beg + map_size; @@ -75,24 +77,6 @@ class LargeMmapAllocator { return reinterpret_cast(res); } - bool MayReturnNull() const { - return atomic_load(&may_return_null_, memory_order_acquire); - } - - void *ReturnNullOrDieOnBadRequest() { - if (MayReturnNull()) return nullptr; - ReportAllocatorCannotReturnNull(false); - } - - void *ReturnNullOrDieOnOOM() { - if (MayReturnNull()) return nullptr; - ReportAllocatorCannotReturnNull(true); - } - - void SetMayReturnNull(bool may_return_null) { - atomic_store(&may_return_null_, may_return_null, memory_order_release); - } - void Deallocate(AllocatorStats *stat, void *p) { Header *h = GetHeader(p); { @@ -278,7 +262,6 @@ class LargeMmapAllocator { struct Stats { uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64]; } stats; - atomic_uint8_t may_return_null_; SpinMutex mutex_; }; diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h index 38363e875560..65b3a38f0d51 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang.h @@ -71,16 +71,25 @@ INLINE typename T::Type atomic_exchange(volatile T *a, return v; } -template -INLINE bool atomic_compare_exchange_strong(volatile T *a, - typename T::Type *cmp, +template +INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp, typename T::Type xchg, memory_order mo) { typedef typename T::Type Type; Type cmpv = *cmp; - Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); - if (prev == cmpv) - return true; + Type prev; +#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 + if (sizeof(*a) == 8) { + Type volatile *val_ptr = const_cast(&a->val_dont_use); + prev = __mips_sync_val_compare_and_swap( + reinterpret_cast(val_ptr), (u64)cmpv, (u64)xchg); + } else { + prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); + } +#else + prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg); +#endif + if (prev == cmpv) return true; *cmp = prev; return false; } diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h index 099b9f7ec8c6..d2acc311bf7d 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_atomic_clang_other.h @@ -17,6 +17,56 @@ namespace __sanitizer { +// MIPS32 does not support atomic > 4 bytes. To address this lack of +// functionality, the sanitizer library provides helper methods which use an +// internal spin lock mechanism to emulate atomic oprations when the size is +// 8 bytes. +#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 +static void __spin_lock(volatile int *lock) { + while (__sync_lock_test_and_set(lock, 1)) + while (*lock) { + } +} + +static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); } + + +// Make sure the lock is on its own cache line to prevent false sharing. +// Put it inside a struct that is aligned and padded to the typical MIPS +// cacheline which is 32 bytes. +static struct { + int lock; + char pad[32 - sizeof(int)]; +} __attribute__((aligned(32))) lock = {0}; + +template +T __mips_sync_fetch_and_add(volatile T *ptr, T val) { + T ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + *ptr = ret + val; + + __spin_unlock(&lock.lock); + + return ret; +} + +template +T __mips_sync_val_compare_and_swap(volatile T *ptr, T oldval, T newval) { + T ret; + __spin_lock(&lock.lock); + + ret = *ptr; + if (ret == oldval) *ptr = newval; + + __spin_unlock(&lock.lock); + + return ret; +} +#endif + INLINE void proc_yield(int cnt) { __asm__ __volatile__("" ::: "memory"); } @@ -53,8 +103,15 @@ INLINE typename T::Type atomic_load( // 64-bit load on 32-bit platform. // Gross, but simple and reliable. // Assume that it is not in read-only memory. +#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 + typename T::Type volatile *val_ptr = + const_cast(&a->val_dont_use); + v = __mips_sync_fetch_and_add( + reinterpret_cast(val_ptr), 0); +#else v = __sync_fetch_and_add( const_cast(&a->val_dont_use), 0); +#endif } return v; } @@ -84,7 +141,14 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { typename T::Type cmp = a->val_dont_use; typename T::Type cur; for (;;) { +#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32 + typename T::Type volatile *val_ptr = + const_cast(&a->val_dont_use); + cur = __mips_sync_val_compare_and_swap( + reinterpret_cast(val_ptr), (u64)cmp, (u64)v); +#else cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v); +#endif if (cmp == v) break; cmp = cur; diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h index 875a46009f49..560c53b6400e 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -95,7 +95,9 @@ void *MmapFixedOrDie(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. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type); +// Dies on all but out of memory errors, in the latter case returns nullptr. +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type); // Disallow access to a memory range. Use MmapFixedNoAccess to allocate an // unaccessible memory. bool MprotectNoAccess(uptr addr, uptr size); @@ -808,8 +810,11 @@ INLINE void LogMessageOnPrintf(const char *str) {} #if SANITIZER_LINUX // Initialize Android logging. Any writes before this are silently lost. void AndroidLogInit(); +void SetAbortMessage(const char *); #else INLINE void AndroidLogInit() {} +// FIXME: MacOS implementation could use CRSetCrashLogMessage. +INLINE void SetAbortMessage(const char *) {} #endif #if SANITIZER_ANDROID @@ -919,6 +924,10 @@ const s32 kReleaseToOSIntervalNever = -1; void CheckNoDeepBind(const char *filename, int flag); +// Returns the requested amount of random data (up to 256 bytes) that can then +// be used to seed a PRNG. +bool GetRandom(void *buffer, uptr length); + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc index d31c49d694ae..a94a63c7f16d 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -1604,6 +1604,32 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) { return 0; } +bool GetRandom(void *buffer, uptr length) { + if (!buffer || !length || length > 256) + return false; +#if defined(__NR_getrandom) + static atomic_uint8_t skip_getrandom_syscall; + if (!atomic_load_relaxed(&skip_getrandom_syscall)) { + // Up to 256 bytes, getrandom will not be interrupted. + uptr res = internal_syscall(SYSCALL(getrandom), buffer, length, 0); + int rverrno = 0; + if (internal_iserror(res, &rverrno) && rverrno == ENOSYS) + atomic_store_relaxed(&skip_getrandom_syscall, 1); + else if (res == length) + return true; + } +#endif + uptr fd = internal_open("/dev/urandom", O_RDONLY); + if (internal_iserror(fd)) + return false; + // internal_read deals with EINTR. + uptr res = internal_read(fd, buffer, length); + if (internal_iserror(res)) + return false; + internal_close(fd); + return true; +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 894013ddd880..b9a48a1e496b 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -551,6 +551,13 @@ void LogMessageOnPrintf(const char *str) { WriteToSyslog(str); } +#if SANITIZER_ANDROID && __ANDROID_API__ >= 21 +extern "C" void android_set_abort_message(const char *msg); +void SetAbortMessage(const char *str) { android_set_abort_message(str); } +#else +void SetAbortMessage(const char *str) {} +#endif + #endif // SANITIZER_LINUX } // namespace __sanitizer diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc index a788a091592f..b48238106dd9 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_mac.cc @@ -923,6 +923,11 @@ void CheckNoDeepBind(const char *filename, int flag) { // Do nothing. } +// FIXME: implement on this platform. +bool GetRandom(void *buffer, uptr length) { + UNIMPLEMENTED(); +} + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc index 4184a84c73f8..87c5b9add5cf 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -164,11 +164,14 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { // We want to map a chunk of address space aligned to 'alignment'. // We do it by maping a bit more and then unmaping redundant pieces. // We probably can do it with fewer syscalls in some OS-dependent way. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); uptr map_size = size + alignment; - uptr map_res = (uptr)MmapOrDie(map_size, mem_type); + uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type); + if (!map_res) + return nullptr; uptr map_end = map_res + map_size; uptr res = map_res; if (res & (alignment - 1)) // Not aligned. diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 5b1d53698707..e113fb1093d4 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -189,25 +189,7 @@ void UnsetAlternateSignalStack() { static void MaybeInstallSigaction(int signum, SignalHandlerType handler) { - switch (GetHandleSignalMode(signum)) { - case kHandleSignalNo: - return; - case kHandleSignalYes: { - struct sigaction sigact; - internal_memset(&sigact, 0, sizeof(sigact)); - CHECK_EQ(0, internal_sigaction(signum, nullptr, &sigact)); - if (sigact.sa_flags & SA_SIGINFO) { - if (sigact.sa_sigaction) return; - } else { - if (sigact.sa_handler != SIG_DFL && sigact.sa_handler != SIG_IGN && - sigact.sa_handler != SIG_ERR) - return; - } - break; - } - case kHandleSignalExclusive: - break; - } + if (GetHandleSignalMode(signum) == kHandleSignalNo) return; struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index d3c77b510d35..60ec7506c312 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -495,7 +495,7 @@ static void ChooseSymbolizerTools(IntrusiveList *list, VReport(2, "Symbolizer is disabled.\n"); return; } - if (IsReportingOOM()) { + if (IsAllocatorOutOfMemory()) { VReport(2, "Cannot use internal symbolizer: out of memory\n"); } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) { VReport(2, "Using internal symbolizer.\n"); diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc index 506e7374a329..c6a146553412 100644 --- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_win.cc @@ -131,18 +131,24 @@ void UnmapOrDie(void *addr, uptr size) { } } +static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type, + const char *mmap_type) { + error_t last_error = GetLastError(); + if (last_error == ERROR_NOT_ENOUGH_MEMORY) + return nullptr; + ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error); +} + void *MmapOrDieOnFatalError(uptr size, const char *mem_type) { void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (rv == 0) { - error_t last_error = GetLastError(); - if (last_error != ERROR_NOT_ENOUGH_MEMORY) - ReportMmapFailureAndDie(size, mem_type, "allocate", last_error); - } + if (rv == 0) + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate"); return rv; } // We want to map a chunk of address space aligned to 'alignment'. -void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { +void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment, + const char *mem_type) { CHECK(IsPowerOfTwo(size)); CHECK(IsPowerOfTwo(alignment)); @@ -152,7 +158,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { uptr mapped_addr = (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!mapped_addr) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); // If we got it right on the first try, return. Otherwise, unmap it and go to // the slow path. @@ -172,8 +178,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { mapped_addr = (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS); if (!mapped_addr) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", - GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); // Find the aligned address. uptr aligned_addr = RoundUpTo(mapped_addr, alignment); @@ -191,7 +196,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { // Fail if we can't make this work quickly. if (retries == kMaxRetries && mapped_addr == 0) - ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError()); + return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned"); return (void *)mapped_addr; } @@ -1002,6 +1007,11 @@ void CheckNoDeepBind(const char *filename, int flag) { // Do nothing. } +// FIXME: implement on this platform. +bool GetRandom(void *buffer, uptr length) { + UNIMPLEMENTED(); +} + } // namespace __sanitizer #endif // _WIN32 diff --git a/contrib/compiler-rt/lib/scudo/scudo_allocator.cpp b/contrib/compiler-rt/lib/scudo/scudo_allocator.cpp index ce69ddf55531..1d0db84a5aaf 100644 --- a/contrib/compiler-rt/lib/scudo/scudo_allocator.cpp +++ b/contrib/compiler-rt/lib/scudo/scudo_allocator.cpp @@ -273,6 +273,8 @@ struct ScudoAllocator { static const uptr MaxAllowedMallocSize = FIRST_32_SECOND_64(2UL << 30, 1ULL << 40); + typedef ReturnNullOrDieOnFailure FailureHandler; + ScudoBackendAllocator BackendAllocator; ScudoQuarantine AllocatorQuarantine; @@ -326,7 +328,8 @@ struct ScudoAllocator { DeallocationTypeMismatch = Options.DeallocationTypeMismatch; DeleteSizeMismatch = Options.DeleteSizeMismatch; ZeroContents = Options.ZeroContents; - BackendAllocator.Init(Options.MayReturnNull, Options.ReleaseToOSIntervalMs); + SetAllocatorMayReturnNull(Options.MayReturnNull); + BackendAllocator.Init(Options.ReleaseToOSIntervalMs); AllocatorQuarantine.Init( static_cast(Options.QuarantineSizeMb) << 20, static_cast(Options.ThreadLocalQuarantineSizeKb) << 10); @@ -354,11 +357,11 @@ struct ScudoAllocator { dieWithMessage("ERROR: alignment is not a power of 2\n"); } if (Alignment > MaxAlignment) - return BackendAllocator.ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); if (Alignment < MinAlignment) Alignment = MinAlignment; if (Size >= MaxAllowedMallocSize) - return BackendAllocator.ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); if (Size == 0) Size = 1; @@ -366,7 +369,7 @@ struct ScudoAllocator { uptr AlignedSize = (Alignment > MinAlignment) ? NeededSize + (Alignment - AlignedChunkHeaderSize) : NeededSize; if (AlignedSize >= MaxAllowedMallocSize) - return BackendAllocator.ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); // Primary and Secondary backed allocations have a different treatment. We // deal with alignment requirements of Primary serviced allocations here, @@ -391,7 +394,7 @@ struct ScudoAllocator { AllocationAlignment, FromPrimary); } if (!Ptr) - return BackendAllocator.ReturnNullOrDieOnOOM(); + return FailureHandler::OnOOM(); // If requested, we will zero out the entire contents of the returned chunk. if ((ForceZeroContents || ZeroContents) && FromPrimary) @@ -583,7 +586,7 @@ struct ScudoAllocator { initThreadMaybe(); uptr Total = NMemB * Size; if (Size != 0 && Total / Size != NMemB) // Overflow check - return BackendAllocator.ReturnNullOrDieOnBadRequest(); + return FailureHandler::OnBadRequest(); return allocate(Total, MinAlignment, FromMalloc, true); } diff --git a/contrib/compiler-rt/lib/scudo/scudo_allocator_combined.h b/contrib/compiler-rt/lib/scudo/scudo_allocator_combined.h index c978db55a9d9..21c45897b94e 100644 --- a/contrib/compiler-rt/lib/scudo/scudo_allocator_combined.h +++ b/contrib/compiler-rt/lib/scudo/scudo_allocator_combined.h @@ -23,11 +23,10 @@ template class ScudoCombinedAllocator { public: - void Init(bool AllocatorMayReturnNull, s32 ReleaseToOSIntervalMs) { + void Init(s32 ReleaseToOSIntervalMs) { Primary.Init(ReleaseToOSIntervalMs); - Secondary.Init(AllocatorMayReturnNull); + Secondary.Init(); Stats.Init(); - atomic_store_relaxed(&MayReturnNull, AllocatorMayReturnNull); } void *Allocate(AllocatorCache *Cache, uptr Size, uptr Alignment, @@ -37,18 +36,6 @@ class ScudoCombinedAllocator { return Secondary.Allocate(&Stats, Size, Alignment); } - void *ReturnNullOrDieOnBadRequest() { - if (atomic_load_relaxed(&MayReturnNull)) - return nullptr; - ReportAllocatorCannotReturnNull(false); - } - - void *ReturnNullOrDieOnOOM() { - if (atomic_load_relaxed(&MayReturnNull)) - return nullptr; - ReportAllocatorCannotReturnNull(true); - } - void Deallocate(AllocatorCache *Cache, void *Ptr, bool FromPrimary) { if (FromPrimary) Cache->Deallocate(&Primary, Primary.GetSizeClass(Ptr), Ptr); @@ -78,7 +65,6 @@ class ScudoCombinedAllocator { PrimaryAllocator Primary; SecondaryAllocator Secondary; AllocatorGlobalStats Stats; - atomic_uint8_t MayReturnNull; }; #endif // SCUDO_ALLOCATOR_COMBINED_H_ diff --git a/contrib/compiler-rt/lib/scudo/scudo_allocator_secondary.h b/contrib/compiler-rt/lib/scudo/scudo_allocator_secondary.h index 2950909b547e..dbfb22565f9c 100644 --- a/contrib/compiler-rt/lib/scudo/scudo_allocator_secondary.h +++ b/contrib/compiler-rt/lib/scudo/scudo_allocator_secondary.h @@ -24,9 +24,8 @@ class ScudoLargeMmapAllocator { public: - void Init(bool AllocatorMayReturnNull) { + void Init() { PageSize = GetPageSizeCached(); - atomic_store_relaxed(&MayReturnNull, AllocatorMayReturnNull); } void *Allocate(AllocatorStats *Stats, uptr Size, uptr Alignment) { @@ -42,7 +41,7 @@ class ScudoLargeMmapAllocator { uptr MapBeg = reinterpret_cast(MmapNoAccess(MapSize)); if (MapBeg == ~static_cast(0)) - return ReturnNullOrDieOnOOM(); + return ReturnNullOrDieOnFailure::OnOOM(); // A page-aligned pointer is assumed after that, so check it now. CHECK(IsAligned(MapBeg, PageSize)); uptr MapEnd = MapBeg + MapSize; @@ -96,12 +95,6 @@ class ScudoLargeMmapAllocator { return reinterpret_cast(Ptr); } - void *ReturnNullOrDieOnOOM() { - if (atomic_load_relaxed(&MayReturnNull)) - return nullptr; - ReportAllocatorCannotReturnNull(true); - } - void Deallocate(AllocatorStats *Stats, void *Ptr) { SecondaryHeader *Header = getHeader(Ptr); { @@ -140,7 +133,6 @@ class ScudoLargeMmapAllocator { const uptr HeadersSize = SecondaryHeaderSize + AlignedChunkHeaderSize; uptr PageSize; SpinMutex StatsMutex; - atomic_uint8_t MayReturnNull; }; #endif // SCUDO_ALLOCATOR_SECONDARY_H_ diff --git a/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc index 2dea24915e8a..fa0d0cafe9b6 100644 --- a/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc +++ b/contrib/compiler-rt/lib/tsan/rtl/tsan_mman.cc @@ -112,9 +112,8 @@ ScopedGlobalProcessor::~ScopedGlobalProcessor() { } void InitializeAllocator() { - allocator()->Init( - common_flags()->allocator_may_return_null, - common_flags()->allocator_release_to_os_interval_ms); + SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); + allocator()->Init(common_flags()->allocator_release_to_os_interval_ms); } void InitializeAllocatorLate() { @@ -151,7 +150,7 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) { void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) - return allocator()->ReturnNullOrDieOnBadRequest(); + return Allocator::FailureHandler::OnBadRequest(); void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); if (p == 0) return 0; @@ -164,7 +163,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)) - return allocator()->ReturnNullOrDieOnBadRequest(); + return Allocator::FailureHandler::OnBadRequest(); void *p = user_alloc(thr, pc, n * size); if (p) internal_memset(p, 0, n * size); diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc index 5dabbd8e08cc..185752719aff 100644 --- a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc +++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.cc @@ -473,9 +473,12 @@ void __ubsan::__ubsan_handle_function_type_mismatch_abort( Die(); } -static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts, - bool IsAttr) { - SourceLocation Loc = Data->Loc.acquire(); +static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr, + ReportOptions Opts, bool IsAttr) { + if (!LocPtr) + UNREACHABLE("source location pointer is null!"); + + SourceLocation Loc = LocPtr->acquire(); ErrorType ET = ErrorType::InvalidNullReturn; if (ignoreReport(Loc, Opts, ET)) @@ -491,25 +494,29 @@ static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts, : "_Nonnull return type annotation"); } -void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) { +void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data, + SourceLocation *LocPtr) { GET_REPORT_OPTIONS(false); - handleNonNullReturn(Data, Opts, true); + handleNonNullReturn(Data, LocPtr, Opts, true); } -void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) { +void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data, + SourceLocation *LocPtr) { GET_REPORT_OPTIONS(true); - handleNonNullReturn(Data, Opts, true); + handleNonNullReturn(Data, LocPtr, Opts, true); Die(); } -void __ubsan::__ubsan_handle_nullability_return(NonNullReturnData *Data) { +void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data, + SourceLocation *LocPtr) { GET_REPORT_OPTIONS(false); - handleNonNullReturn(Data, Opts, false); + handleNonNullReturn(Data, LocPtr, Opts, false); } -void __ubsan::__ubsan_handle_nullability_return_abort(NonNullReturnData *Data) { +void __ubsan::__ubsan_handle_nullability_return_v1_abort( + NonNullReturnData *Data, SourceLocation *LocPtr) { GET_REPORT_OPTIONS(true); - handleNonNullReturn(Data, Opts, false); + handleNonNullReturn(Data, LocPtr, Opts, false); Die(); } diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h index 483c18ced579..796321b81889 100644 --- a/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h +++ b/contrib/compiler-rt/lib/ubsan/ubsan_handlers.h @@ -132,14 +132,13 @@ RECOVERABLE(function_type_mismatch, ValueHandle Val) struct NonNullReturnData { - SourceLocation Loc; SourceLocation AttrLoc; }; /// \brief Handle returning null from function with the returns_nonnull /// attribute, or a return type annotated with _Nonnull. -RECOVERABLE(nonnull_return, NonNullReturnData *Data) -RECOVERABLE(nullability_return, NonNullReturnData *Data) +RECOVERABLE(nonnull_return_v1, NonNullReturnData *Data, SourceLocation *Loc) +RECOVERABLE(nullability_return_v1, NonNullReturnData *Data, SourceLocation *Loc) struct NonNullArgData { SourceLocation Loc; diff --git a/contrib/compiler-rt/lib/ubsan/ubsan_interface.inc b/contrib/compiler-rt/lib/ubsan/ubsan_interface.inc index 681476b3c91d..a69ca57cd7af 100644 --- a/contrib/compiler-rt/lib/ubsan/ubsan_interface.inc +++ b/contrib/compiler-rt/lib/ubsan/ubsan_interface.inc @@ -28,12 +28,12 @@ INTERFACE_FUNCTION(__ubsan_handle_negate_overflow) INTERFACE_FUNCTION(__ubsan_handle_negate_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg) INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg_abort) -INTERFACE_FUNCTION(__ubsan_handle_nonnull_return) -INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_abort) +INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_v1) +INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_v1_abort) INTERFACE_FUNCTION(__ubsan_handle_nullability_arg) INTERFACE_FUNCTION(__ubsan_handle_nullability_arg_abort) -INTERFACE_FUNCTION(__ubsan_handle_nullability_return) -INTERFACE_FUNCTION(__ubsan_handle_nullability_return_abort) +INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1) +INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1_abort) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort) INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow) diff --git a/contrib/compiler-rt/lib/xray/xray_interface.cc b/contrib/compiler-rt/lib/xray/xray_interface.cc index e912b6e478a3..694d34c0102b 100644 --- a/contrib/compiler-rt/lib/xray/xray_interface.cc +++ b/contrib/compiler-rt/lib/xray/xray_interface.cc @@ -312,7 +312,7 @@ __xray_unpatch_function(int32_t FuncId) XRAY_NEVER_INSTRUMENT { return patchFunction(FuncId, false); } -int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { +int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType, uint64_t)) { if (!__sanitizer::atomic_load(&XRayInitialized, __sanitizer::memory_order_acquire)) return 0; @@ -320,7 +320,7 @@ int __xray_set_handler_arg1(void (*Handler)(int32_t, XRayEntryType, uint64_t)) { // A relaxed write might not be visible even if the current thread gets // scheduled on a different CPU/NUMA node. We need to wait for everyone to // have this handler installed for consistency of collected data across CPUs. - __sanitizer::atomic_store(&XRayArgLogger, reinterpret_cast(Handler), + __sanitizer::atomic_store(&XRayArgLogger, reinterpret_cast(entry), __sanitizer::memory_order_release); return 1; } diff --git a/contrib/libc++/include/__config b/contrib/libc++/include/__config index fc24a3bc9ba9..aae053102f55 100644 --- a/contrib/libc++/include/__config +++ b/contrib/libc++/include/__config @@ -1154,6 +1154,7 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container( __attribute__((availability(watchos,strict,introduced=3.0))) #define _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS __attribute__((unavailable)) #define _LIBCPP_AVAILABILITY_BAD_ARRAY_LENGTH __attribute__((unavailable)) +#define _LIBCPP_AVAILABILITY_BAD_ANY_CAST __attribute__((unavailable)) #define _LIBCPP_AVAILABILITY_UNCAUGHT_EXCEPTIONS \ __attribute__((availability(macosx,strict,introduced=10.12))) \ __attribute__((availability(ios,strict,introduced=10.0))) \ @@ -1175,25 +1176,35 @@ _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 #define _LIBCPP_AVAILABILITY_BAD_ARRAY_LENGTH +#define _LIBCPP_AVAILABILITY_BAD_ANY_CAST #define _LIBCPP_AVAILABILITY_UNCAUGHT_EXCEPTIONS #define _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE #define _LIBCPP_AVAILABILITY_FUTURE_ERROR #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. #ifdef _LIBCPP_NO_EXCEPTIONS #define _LIBCPP_AVAILABILITY_DYNARRAY #define _LIBCPP_AVAILABILITY_FUTURE +#define _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST #else #define _LIBCPP_AVAILABILITY_DYNARRAY _LIBCPP_AVAILABILITY_BAD_ARRAY_LENGTH #define _LIBCPP_AVAILABILITY_FUTURE _LIBCPP_AVAILABILITY_FUTURE_ERROR +#define _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST \ + _LIBCPP_AVAILABILITY_BAD_ANY_CAST #endif // Availability of stream API in the dylib got dropped and re-added. The @@ -1202,9 +1213,9 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container( // availability(ios,introduced=7.0) #if defined(_LIBCPP_USE_AVAILABILITY_APPLE) && \ ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ <= 1090) || \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1090) || \ (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ <= 70000)) + __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 70000)) #define _LIBCPP_AVAILABILITY_NO_STREAMS_EXTERN_TEMPLATE #endif diff --git a/contrib/libc++/include/experimental/any b/contrib/libc++/include/experimental/any index 022b379e858b..083a2909033c 100644 --- a/contrib/libc++/include/experimental/any +++ b/contrib/libc++/include/experimental/any @@ -89,7 +89,7 @@ inline namespace fundamentals_v1 { _LIBCPP_BEGIN_NAMESPACE_LFTS -class _LIBCPP_EXCEPTION_ABI bad_any_cast : public bad_cast +class _LIBCPP_EXCEPTION_ABI _LIBCPP_AVAILABILITY_BAD_ANY_CAST bad_any_cast : public bad_cast { public: virtual const char* what() const _NOEXCEPT; @@ -98,6 +98,7 @@ public: #if _LIBCPP_STD_VER > 11 // C++ > 11 _LIBCPP_NORETURN inline _LIBCPP_ALWAYS_INLINE +_LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST void __throw_bad_any_cast() { #ifndef _LIBCPP_NO_EXCEPTIONS @@ -506,7 +507,7 @@ void swap(any & __lhs, any & __rhs) _NOEXCEPT } template -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST _ValueType any_cast(any const & __v) { static_assert( @@ -522,7 +523,7 @@ _ValueType any_cast(any const & __v) } template -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST _ValueType any_cast(any & __v) { static_assert( @@ -537,7 +538,7 @@ _ValueType any_cast(any & __v) } template -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_INLINE_VISIBILITY _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST _ValueType any_cast(any && __v) { static_assert( diff --git a/contrib/libc++/include/new b/contrib/libc++/include/new index 34df2efee09e..3945faee0e38 100644 --- a/contrib/libc++/include/new +++ b/contrib/libc++/include/new @@ -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 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; +_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; #ifndef _LIBCPP_HAS_NO_SIZED_DEALLOCATION -_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE void operator delete(void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT; +_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void operator delete(void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT; #endif -_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; +_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; #ifndef _LIBCPP_HAS_NO_SIZED_DEALLOCATION -_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_SIZED_NEW_DELETE void operator delete[](void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT; +_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_ALIGNED_ALLOCATION void operator delete[](void* __p, std::size_t __sz, std::align_val_t) _NOEXCEPT; #endif #endif diff --git a/contrib/libc++/include/numeric b/contrib/libc++/include/numeric index 39e81934dfa1..1b7d97c5be07 100644 --- a/contrib/libc++/include/numeric +++ b/contrib/libc++/include/numeric @@ -81,6 +81,20 @@ template + OutputIterator + inclusive_scan(InputIterator first, InputIterator last, OutputIterator result); // C++17 + +template + OutputIterator + inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, BinaryOperation binary_op); // C++17 + +template + OutputIterator + inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, BinaryOperation binary_op, T init); // C++17 + template OutputIterator @@ -88,6 +102,21 @@ template + OutputIterator + transform_inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, + BinaryOperation binary_op, UnaryOperation unary_op); // C++17 + +template + OutputIterator + transform_inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, + BinaryOperation binary_op, UnaryOperation unary_op, + T init); // C++17 + template OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result); @@ -295,6 +324,38 @@ exclusive_scan(_InputIterator __first, _InputIterator __last, return _VSTD::exclusive_scan(__first, __last, __result, __init, _VSTD::plus<>()); } +template +_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryOp __b, _Tp __init) +{ + for (; __first != __last; ++__first, (void) ++__result) { + __init = __b(__init, *__first); + *__result = __init; + } + return __result; +} + +template +_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryOp __b) +{ + if (__first != __last) { + typename std::iterator_traits<_InputIterator>::value_type __init = *__first; + *__result++ = __init; + if (++__first != __last) + return _VSTD::inclusive_scan(__first, __last, __result, __b, __init); + } + + return __result; +} + +template +_OutputIterator inclusive_scan(_InputIterator __first, _InputIterator __last, + _OutputIterator __result) +{ + return _VSTD::inclusive_scan(__first, __last, __result, std::plus<>()); +} + template inline _LIBCPP_INLINE_VISIBILITY @@ -316,6 +377,32 @@ transform_exclusive_scan(_InputIterator __first, _InputIterator __last, } return __result; } + +template +_OutputIterator transform_inclusive_scan(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryOp __b, _UnaryOp __u, _Tp __init) +{ + for (; __first != __last; ++__first, (void) ++__result) { + __init = __b(__init, __u(*__first)); + *__result = __init; + } + + return __result; +} + +template +_OutputIterator transform_inclusive_scan(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryOp __b, _UnaryOp __u) +{ + if (__first != __last) { + typename std::iterator_traits<_InputIterator>::value_type __init = __u(*__first); + *__result++ = __init; + if (++__first != __last) + return _VSTD::transform_inclusive_scan(__first, __last, __result, __b, __u, __init); + } + + return __result; +} #endif template diff --git a/contrib/libc++/include/variant b/contrib/libc++/include/variant index 8711ef6eb387..f8d3e28bae45 100644 --- a/contrib/libc++/include/variant +++ b/contrib/libc++/include/variant @@ -1116,6 +1116,8 @@ public: template < class _Arg, enable_if_t, variant>, int> = 0, + enable_if_t>::value, int> = 0, + enable_if_t>::value, int> = 0, class _Tp = __variant_detail::__best_match_t<_Arg, _Types...>, size_t _Ip = __find_detail::__find_unambiguous_index_sfinae<_Tp, _Types...>::value, diff --git a/contrib/libc++/src/experimental/filesystem/path.cpp b/contrib/libc++/src/experimental/filesystem/path.cpp index f49d4cd2d418..dd4026cfe13a 100644 --- a/contrib/libc++/src/experimental/filesystem/path.cpp +++ b/contrib/libc++/src/experimental/filesystem/path.cpp @@ -261,7 +261,8 @@ struct PathParser { string_view_pair separate_filename(string_view_t const & s) { if (s == "." || s == ".." || s.empty()) return string_view_pair{s, ""}; auto pos = s.find_last_of('.'); - if (pos == string_view_t::npos) return string_view_pair{s, string_view{}}; + if (pos == string_view_t::npos) + return string_view_pair{s, string_view_t{}}; return string_view_pair{s.substr(0, pos), s.substr(pos)}; } @@ -396,7 +397,7 @@ int path::__compare(string_view_t __s) const { size_t hash_value(const path& __p) noexcept { auto PP = PathParser::CreateBegin(__p.native()); size_t hash_value = 0; - std::hash hasher; + std::hash hasher; while (PP) { hash_value = __hash_combine(hash_value, hasher(*PP)); ++PP; diff --git a/contrib/llvm/include/llvm-c/OrcBindings.h b/contrib/llvm/include/llvm-c/OrcBindings.h index de2969ab1c9b..d86ea8808889 100644 --- a/contrib/llvm/include/llvm-c/OrcBindings.h +++ b/contrib/llvm/include/llvm-c/OrcBindings.h @@ -29,6 +29,8 @@ extern "C" { #endif +typedef struct LLVMOpaqueSharedModule *LLVMSharedModuleRef; +typedef struct LLVMOpaqueSharedObjectBuffer *LLVMSharedObjectBufferRef; typedef struct LLVMOrcOpaqueJITStack *LLVMOrcJITStackRef; typedef uint32_t LLVMOrcModuleHandle; typedef uint64_t LLVMOrcTargetAddress; @@ -38,6 +40,45 @@ typedef uint64_t (*LLVMOrcLazyCompileCallbackFn)(LLVMOrcJITStackRef JITStack, typedef enum { LLVMOrcErrSuccess = 0, LLVMOrcErrGeneric } LLVMOrcErrorCode; +/** + * Turn an LLVMModuleRef into an LLVMSharedModuleRef. + * + * The JIT uses shared ownership for LLVM modules, since it is generally + * difficult to know when the JIT will be finished with a module (and the JIT + * has no way of knowing when a user may be finished with one). + * + * Calling this method with an LLVMModuleRef creates a shared-pointer to the + * module, and returns a reference to this shared pointer. + * + * The shared module should be disposed when finished with by calling + * LLVMOrcDisposeSharedModule (not LLVMDisposeModule). The Module will be + * deleted when the last shared pointer owner relinquishes it. + */ + +LLVMSharedModuleRef LLVMOrcMakeSharedModule(LLVMModuleRef Mod); + +/** + * Dispose of a shared module. + * + * The module should not be accessed after this call. The module will be + * deleted once all clients (including the JIT itself) have released their + * shared pointers. + */ + +void LLVMOrcDisposeSharedModuleRef(LLVMSharedModuleRef SharedMod); + +/** + * Get an LLVMSharedObjectBufferRef from an LLVMMemoryBufferRef. + */ +LLVMSharedObjectBufferRef +LLVMOrcMakeSharedObjectBuffer(LLVMMemoryBufferRef ObjBuffer); + +/** + * Dispose of a shared object buffer. + */ +void +LLVMOrcDisposeSharedObjectBufferRef(LLVMSharedObjectBufferRef SharedObjBuffer); + /** * Create an ORC JIT stack. * @@ -95,7 +136,8 @@ LLVMOrcErrorCode LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, * Add module to be eagerly compiled. */ LLVMOrcModuleHandle -LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod, +LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, + LLVMSharedModuleRef Mod, LLVMOrcSymbolResolverFn SymbolResolver, void *SymbolResolverCtx); @@ -103,7 +145,8 @@ LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod, * Add module to be lazily compiled one function at a time. */ LLVMOrcModuleHandle -LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod, +LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, + LLVMSharedModuleRef Mod, LLVMOrcSymbolResolverFn SymbolResolver, void *SymbolResolverCtx); @@ -111,7 +154,7 @@ LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod, * Add an object file. */ LLVMOrcModuleHandle LLVMOrcAddObjectFile(LLVMOrcJITStackRef JITStack, - LLVMObjectFileRef Obj, + LLVMSharedObjectBufferRef Obj, LLVMOrcSymbolResolverFn SymbolResolver, void *SymbolResolverCtx); diff --git a/contrib/llvm/include/llvm/ADT/APFloat.h b/contrib/llvm/include/llvm/ADT/APFloat.h index bef6efde1f01..9c5e392c4808 100644 --- a/contrib/llvm/include/llvm/ADT/APFloat.h +++ b/contrib/llvm/include/llvm/ADT/APFloat.h @@ -140,8 +140,8 @@ enum lostFraction { // Example of truncated bits: // implementation classes. This struct should not define any non-static data // members. struct APFloatBase { - // TODO remove this and use APInt typedef directly. typedef APInt::WordType integerPart; + static const unsigned integerPartWidth = APInt::APINT_BITS_PER_WORD; /// A signed type to represent a floating point numbers unbiased exponent. typedef signed short ExponentType; diff --git a/contrib/llvm/include/llvm/ADT/APInt.h b/contrib/llvm/include/llvm/ADT/APInt.h index ef9c66d2d700..e5f0c35534ac 100644 --- a/contrib/llvm/include/llvm/ADT/APInt.h +++ b/contrib/llvm/include/llvm/ADT/APInt.h @@ -213,6 +213,12 @@ class LLVM_NODISCARD APInt { /// out-of-line slow case for countLeadingZeros unsigned countLeadingZerosSlowCase() const LLVM_READONLY; + /// out-of-line slow case for countLeadingOnes. + unsigned countLeadingOnesSlowCase() const LLVM_READONLY; + + /// out-of-line slow case for countTrailingZeros. + unsigned countTrailingZerosSlowCase() const LLVM_READONLY; + /// out-of-line slow case for countTrailingOnes unsigned countTrailingOnesSlowCase() const LLVM_READONLY; @@ -383,7 +389,7 @@ class LLVM_NODISCARD APInt { bool isAllOnesValue() const { if (isSingleWord()) return U.VAL == WORD_MAX >> (APINT_BITS_PER_WORD - BitWidth); - return countPopulationSlowCase() == BitWidth; + return countTrailingOnesSlowCase() == BitWidth; } /// \brief Determine if all bits are clear @@ -408,7 +414,9 @@ class LLVM_NODISCARD APInt { /// This checks to see if the value of this APInt is the maximum signed /// value for the APInt's bit width. bool isMaxSignedValue() const { - return !isNegative() && countPopulation() == BitWidth - 1; + if (isSingleWord()) + return U.VAL == ((WordType(1) << (BitWidth - 1)) - 1); + return !isNegative() && countTrailingOnesSlowCase() == BitWidth - 1; } /// \brief Determine if this is the smallest unsigned value. @@ -422,7 +430,9 @@ class LLVM_NODISCARD APInt { /// This checks to see if the value of this APInt is the minimum signed /// value for the APInt's bit width. bool isMinSignedValue() const { - return isNegative() && isPowerOf2(); + if (isSingleWord()) + return U.VAL == (WordType(1) << (BitWidth - 1)); + return isNegative() && countTrailingZerosSlowCase() == BitWidth - 1; } /// \brief Check if this APInt has an N-bits unsigned integer value. @@ -1574,7 +1584,11 @@ class LLVM_NODISCARD APInt { /// /// \returns 0 if the high order bit is not set, otherwise returns the number /// of 1 bits from the most significant to the least - unsigned countLeadingOnes() const LLVM_READONLY; + unsigned countLeadingOnes() const { + if (isSingleWord()) + return llvm::countLeadingOnes(U.VAL << (APINT_BITS_PER_WORD - BitWidth)); + return countLeadingOnesSlowCase(); + } /// Computes the number of leading bits of this APInt that are equal to its /// sign bit. @@ -1590,7 +1604,11 @@ class LLVM_NODISCARD APInt { /// /// \returns BitWidth if the value is zero, otherwise returns the number of /// zeros from the least significant bit to the first one bit. - unsigned countTrailingZeros() const LLVM_READONLY; + unsigned countTrailingZeros() const { + if (isSingleWord()) + return std::min(unsigned(llvm::countTrailingZeros(U.VAL)), BitWidth); + return countTrailingZerosSlowCase(); + } /// \brief Count the number of trailing one bits. /// diff --git a/contrib/llvm/include/llvm/ADT/StringExtras.h b/contrib/llvm/include/llvm/ADT/StringExtras.h index ffcf998a3d32..cc32bf43f29c 100644 --- a/contrib/llvm/include/llvm/ADT/StringExtras.h +++ b/contrib/llvm/include/llvm/ADT/StringExtras.h @@ -15,10 +15,12 @@ #define LLVM_ADT_STRINGEXTRAS_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include #include #include +#include #include #include #include @@ -129,6 +131,32 @@ template bool to_integer(StringRef S, N &Num, unsigned Base = 0) { return !S.getAsInteger(Base, Num); } +namespace detail { +template +inline bool to_float(const Twine &T, N &Num, N (*StrTo)(const char *, char **)) { + SmallString<32> Storage; + StringRef S = T.toNullTerminatedStringRef(Storage); + char *End; + N Temp = StrTo(S.data(), &End); + if (*End != '\0') + return false; + Num = Temp; + return true; +} +} + +inline bool to_float(const Twine &T, float &Num) { + return detail::to_float(T, Num, strtof); +} + +inline bool to_float(const Twine &T, double &Num) { + return detail::to_float(T, Num, strtod); +} + +inline bool to_float(const Twine &T, long double &Num) { + return detail::to_float(T, Num, strtold); +} + static inline std::string utostr(uint64_t X, bool isNeg = false) { char Buffer[21]; char *BufPtr = std::end(Buffer); diff --git a/contrib/llvm/include/llvm/ADT/Triple.h b/contrib/llvm/include/llvm/ADT/Triple.h index 26a991812a3a..cd560658ca4e 100644 --- a/contrib/llvm/include/llvm/ADT/Triple.h +++ b/contrib/llvm/include/llvm/ADT/Triple.h @@ -147,6 +147,7 @@ class Triple { enum OSType { UnknownOS, + Ananas, CloudABI, Darwin, DragonFly, diff --git a/contrib/llvm/include/llvm/Analysis/LazyValueInfo.h b/contrib/llvm/include/llvm/Analysis/LazyValueInfo.h index 7b178fc7bcc2..787c88cc6ec1 100644 --- a/contrib/llvm/include/llvm/Analysis/LazyValueInfo.h +++ b/contrib/llvm/include/llvm/Analysis/LazyValueInfo.h @@ -93,6 +93,13 @@ class LazyValueInfo { Constant *getConstantOnEdge(Value *V, BasicBlock *FromBB, BasicBlock *ToBB, Instruction *CxtI = nullptr); + /// Return the ConstantRage constraint that is known to hold for the + /// specified value on the specified edge. This may be only be called + /// on integer-typed Values. + ConstantRange getConstantRangeOnEdge(Value *V, BasicBlock *FromBB, + BasicBlock *ToBB, + Instruction *CxtI = nullptr); + /// Inform the analysis cache that we have threaded an edge from /// PredBB to OldSucc to be from PredBB to NewSucc instead. void threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc, BasicBlock *NewSucc); diff --git a/contrib/llvm/include/llvm/Analysis/Loads.h b/contrib/llvm/include/llvm/Analysis/Loads.h index a59c1f88e229..f110c28bfc6d 100644 --- a/contrib/llvm/include/llvm/Analysis/Loads.h +++ b/contrib/llvm/include/llvm/Analysis/Loads.h @@ -39,6 +39,15 @@ bool isDereferenceableAndAlignedPointer(const Value *V, unsigned Align, const Instruction *CtxI = nullptr, const DominatorTree *DT = nullptr); +/// Returns true if V is always dereferenceable for Size byte with alignment +/// greater or equal than requested. If the context instruction is specified +/// performs context-sensitive analysis and returns true if the pointer is +/// dereferenceable at the specified instruction. +bool isDereferenceableAndAlignedPointer(const Value *V, unsigned Align, + const APInt &Size, const DataLayout &DL, + const Instruction *CtxI = nullptr, + const DominatorTree *DT = nullptr); + /// Return true if we know that executing a load from this value cannot trap. /// /// If DT and ScanFrom are specified this method performs context-sensitive diff --git a/contrib/llvm/include/llvm/Analysis/LoopInfoImpl.h b/contrib/llvm/include/llvm/Analysis/LoopInfoImpl.h index 6ff4335f1ad5..372fc8b21745 100644 --- a/contrib/llvm/include/llvm/Analysis/LoopInfoImpl.h +++ b/contrib/llvm/include/llvm/Analysis/LoopInfoImpl.h @@ -91,8 +91,9 @@ getExitEdges(SmallVectorImpl &ExitEdges) const { /// getLoopPreheader - If there is a preheader for this loop, return it. A /// loop has a preheader if there is only one edge to the header of the loop -/// from outside of the loop. If this is the case, the block branching to the -/// header of the loop is the preheader node. +/// from outside of the loop and it is legal to hoist instructions into the +/// predecessor. If this is the case, the block branching to the header of the +/// loop is the preheader node. /// /// This method returns null if there is no preheader for the loop. /// @@ -102,6 +103,10 @@ BlockT *LoopBase::getLoopPreheader() const { BlockT *Out = getLoopPredecessor(); if (!Out) return nullptr; + // Make sure we are allowed to hoist instructions into the predecessor. + if (!Out->isLegalToHoistInto()) + return nullptr; + // Make sure there is only one exit out of the preheader. typedef GraphTraits BlockTraits; typename BlockTraits::ChildIteratorType SI = BlockTraits::child_begin(Out); diff --git a/contrib/llvm/include/llvm/Analysis/ScalarEvolution.h b/contrib/llvm/include/llvm/Analysis/ScalarEvolution.h index 2a4b768256d1..002a3174fd19 100644 --- a/contrib/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/contrib/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -784,7 +784,9 @@ class ScalarEvolution { } /// Determine the range for a particular SCEV. - ConstantRange getRange(const SCEV *S, RangeSignHint Hint); + /// NOTE: This returns a reference to an entry in a cache. It must be + /// copied if its needed for longer. + const ConstantRange &getRangeRef(const SCEV *S, RangeSignHint Hint); /// Determines the range for the affine SCEVAddRecExpr {\p Start,+,\p Stop}. /// Helper for \c getRange. @@ -1464,15 +1466,35 @@ class ScalarEvolution { uint32_t GetMinTrailingZeros(const SCEV *S); /// Determine the unsigned range for a particular SCEV. - /// + /// NOTE: This returns a copy of the reference returned by getRangeRef. ConstantRange getUnsignedRange(const SCEV *S) { - return getRange(S, HINT_RANGE_UNSIGNED); + return getRangeRef(S, HINT_RANGE_UNSIGNED); + } + + /// Determine the min of the unsigned range for a particular SCEV. + APInt getUnsignedRangeMin(const SCEV *S) { + return getRangeRef(S, HINT_RANGE_UNSIGNED).getUnsignedMin(); + } + + /// Determine the max of the unsigned range for a particular SCEV. + APInt getUnsignedRangeMax(const SCEV *S) { + return getRangeRef(S, HINT_RANGE_UNSIGNED).getUnsignedMax(); } /// Determine the signed range for a particular SCEV. - /// + /// NOTE: This returns a copy of the reference returned by getRangeRef. ConstantRange getSignedRange(const SCEV *S) { - return getRange(S, HINT_RANGE_SIGNED); + return getRangeRef(S, HINT_RANGE_SIGNED); + } + + /// Determine the min of the signed range for a particular SCEV. + APInt getSignedRangeMin(const SCEV *S) { + return getRangeRef(S, HINT_RANGE_SIGNED).getSignedMin(); + } + + /// Determine the max of the signed range for a particular SCEV. + APInt getSignedRangeMax(const SCEV *S) { + return getRangeRef(S, HINT_RANGE_SIGNED).getSignedMax(); } /// Test if the given expression is known to be negative. diff --git a/contrib/llvm/include/llvm/BinaryFormat/COFF.h b/contrib/llvm/include/llvm/BinaryFormat/COFF.h index 5171c72b9e67..df173a80e09b 100644 --- a/contrib/llvm/include/llvm/BinaryFormat/COFF.h +++ b/contrib/llvm/include/llvm/BinaryFormat/COFF.h @@ -46,6 +46,12 @@ static const char ClGlObjMagic[] = { '\xac', '\x9b', '\xd6', '\xb6', '\x22', '\x26', '\x53', '\xc2', }; +// The signature bytes that start a .res file. +static const char WinResMagic[] = { + '\x00', '\x00', '\x00', '\x00', '\x20', '\x00', '\x00', '\x00', + '\xff', '\xff', '\x00', '\x00', '\xff', '\xff', '\x00', '\x00', +}; + // Sizes in bytes of various things in the COFF format. enum { Header16Size = 20, diff --git a/contrib/llvm/include/llvm/BinaryFormat/Dwarf.h b/contrib/llvm/include/llvm/BinaryFormat/Dwarf.h index b7a056b18119..ab927565d05d 100644 --- a/contrib/llvm/include/llvm/BinaryFormat/Dwarf.h +++ b/contrib/llvm/include/llvm/BinaryFormat/Dwarf.h @@ -484,7 +484,7 @@ struct PubIndexEntryDescriptor { }; /// Constants that define the DWARF format as 32 or 64 bit. -enum DwarfFormat { DWARF32, DWARF64 }; +enum DwarfFormat : uint8_t { DWARF32, DWARF64 }; } // End of namespace dwarf diff --git a/contrib/llvm/include/llvm/BinaryFormat/MachO.h b/contrib/llvm/include/llvm/BinaryFormat/MachO.h index 8ab6dde800c2..3529c72acd9d 100644 --- a/contrib/llvm/include/llvm/BinaryFormat/MachO.h +++ b/contrib/llvm/include/llvm/BinaryFormat/MachO.h @@ -78,7 +78,8 @@ enum { MH_DEAD_STRIPPABLE_DYLIB = 0x00400000u, MH_HAS_TLV_DESCRIPTORS = 0x00800000u, MH_NO_HEAP_EXECUTION = 0x01000000u, - MH_APP_EXTENSION_SAFE = 0x02000000u + MH_APP_EXTENSION_SAFE = 0x02000000u, + MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000u }; enum : uint32_t { diff --git a/contrib/llvm/include/llvm/BinaryFormat/Wasm.h b/contrib/llvm/include/llvm/BinaryFormat/Wasm.h index fcd8ad957040..470c20ddc7d9 100644 --- a/contrib/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/contrib/llvm/include/llvm/BinaryFormat/Wasm.h @@ -176,6 +176,11 @@ enum class ValType { // Linking metadata kinds. enum : unsigned { WASM_STACK_POINTER = 0x1, + WASM_SYMBOL_INFO = 0x2, +}; + +enum : unsigned { + WASM_SYMBOL_FLAG_WEAK = 0x1, }; #define WASM_RELOC(name, value) name = value, diff --git a/contrib/llvm/include/llvm/CodeGen/DIE.h b/contrib/llvm/include/llvm/CodeGen/DIE.h index 5ed5faa2c415..f809fc97fe59 100644 --- a/contrib/llvm/include/llvm/CodeGen/DIE.h +++ b/contrib/llvm/include/llvm/CodeGen/DIE.h @@ -121,8 +121,8 @@ class DIEAbbrev : public FoldingSetNode { /// Print the abbreviation using the specified asm printer. void Emit(const AsmPrinter *AP) const; - void print(raw_ostream &O); - void dump(); + void print(raw_ostream &O) const; + void dump() const; }; //===--------------------------------------------------------------------===// @@ -780,7 +780,7 @@ class DIE : IntrusiveBackListNode, public DIEValueList { DIEValue findAttribute(dwarf::Attribute Attribute) const; void print(raw_ostream &O, unsigned IndentCount = 0) const; - void dump(); + void dump() const; }; //===--------------------------------------------------------------------===// diff --git a/contrib/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h b/contrib/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h index 1a865c3f0dce..b3ef7c2dc185 100644 --- a/contrib/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ b/contrib/llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -29,6 +29,7 @@ class MachineOperand; class MachineRegisterInfo; class RegisterBankInfo; class TargetInstrInfo; +class TargetRegisterClass; class TargetRegisterInfo; /// Container class for CodeGen predicate results. @@ -79,6 +80,16 @@ class InstructionSelector { InstructionSelector(); + /// Constrain a register operand of an instruction \p I to a specified + /// register class. This could involve inserting COPYs before (for uses) or + /// after (for defs) and may replace the operand of \p I. + /// \returns whether operand regclass constraining succeeded. + bool constrainOperandRegToRegClass(MachineInstr &I, unsigned OpIdx, + const TargetRegisterClass &RC, + const TargetInstrInfo &TII, + const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) const; + /// Mutate the newly-selected instruction \p I to constrain its (possibly /// generic) virtual register operands to the instruction's register class. /// This could involve inserting COPYs before (for uses) or after (for defs). diff --git a/contrib/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h b/contrib/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h index bed7230cc013..9b9b8b563a30 100644 --- a/contrib/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h +++ b/contrib/llvm/include/llvm/CodeGen/GlobalISel/Legalizer.h @@ -59,7 +59,7 @@ class Legalizer : public MachineFunctionPass { const TargetInstrInfo &TII); bool combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI, - const TargetInstrInfo &TII); + const TargetInstrInfo &TII, MachineIRBuilder &MIRBuilder); bool runOnMachineFunction(MachineFunction &MF) override; }; diff --git a/contrib/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h b/contrib/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h index 4e7b8350038b..c9327d50432e 100644 --- a/contrib/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h +++ b/contrib/llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h @@ -471,10 +471,12 @@ class MachineIRBuilder { /// Build and insert \p Res = IMPLICIT_DEF. MachineInstrBuilder buildUndef(unsigned Dst); - /// Build and insert \p Res = G_SEQUENCE \p Op0, \p Idx0... + /// Build and insert instructions to put \p Ops together at the specified p + /// Indices to form a larger register. /// - /// G_SEQUENCE inserts each element of Ops into an IMPLICIT_DEF register, - /// where each entry starts at the bit-index specified by \p Indices. + /// If the types of the input registers are uniform and cover the entirity of + /// \p Res then a G_MERGE_VALUES will be produced. Otherwise an IMPLICIT_DEF + /// followed by a sequence of G_INSERT instructions. /// /// \pre setBasicBlock or setMI must have been called. /// \pre The final element of the sequence must not extend past the end of the @@ -482,11 +484,8 @@ class MachineIRBuilder { /// \pre The bits defined by each Op (derived from index and scalar size) must /// not overlap. /// \pre \p Indices must be in ascending order of bit position. - /// - /// \return a MachineInstrBuilder for the newly created instruction. - MachineInstrBuilder buildSequence(unsigned Res, - ArrayRef Ops, - ArrayRef Indices); + void buildSequence(unsigned Res, ArrayRef Ops, + ArrayRef Indices); /// Build and insert \p Res = G_MERGE_VALUES \p Op0, ... /// @@ -513,24 +512,6 @@ class MachineIRBuilder { /// \return a MachineInstrBuilder for the newly created instruction. MachineInstrBuilder buildUnmerge(ArrayRef Res, unsigned Op); - void addUsesWithIndices(MachineInstrBuilder MIB) {} - - template - void addUsesWithIndices(MachineInstrBuilder MIB, unsigned Reg, - unsigned BitIndex, ArgTys... Args) { - MIB.addUse(Reg).addImm(BitIndex); - addUsesWithIndices(MIB, Args...); - } - - template - MachineInstrBuilder buildSequence(unsigned Res, unsigned Op, - unsigned Index, ArgTys... Args) { - MachineInstrBuilder MIB = - buildInstr(TargetOpcode::G_SEQUENCE).addDef(Res); - addUsesWithIndices(MIB, Op, Index, Args...); - return MIB; - } - MachineInstrBuilder buildInsert(unsigned Res, unsigned Src, unsigned Op, unsigned Index); diff --git a/contrib/llvm/include/llvm/CodeGen/GlobalISel/Utils.h b/contrib/llvm/include/llvm/CodeGen/GlobalISel/Utils.h index 69d507069808..50ddbeb9432a 100644 --- a/contrib/llvm/include/llvm/CodeGen/GlobalISel/Utils.h +++ b/contrib/llvm/include/llvm/CodeGen/GlobalISel/Utils.h @@ -29,13 +29,26 @@ class RegisterBankInfo; class TargetInstrInfo; class TargetPassConfig; class TargetRegisterInfo; +class TargetRegisterClass; class Twine; class ConstantFP; +/// Try to constrain Reg to the specified register class. If this fails, +/// create a new virtual register in the correct class and insert a COPY before +/// \p InsertPt. The debug location of \p InsertPt is used for the new copy. +/// +/// \return The virtual register constrained to the right register class. +unsigned constrainRegToClass(MachineRegisterInfo &MRI, + const TargetInstrInfo &TII, + const RegisterBankInfo &RBI, + MachineInstr &InsertPt, unsigned Reg, + const TargetRegisterClass &RegClass); + /// Try to constrain Reg so that it is usable by argument OpIdx of the /// provided MCInstrDesc \p II. If this fails, create a new virtual /// register in the correct class and insert a COPY before \p InsertPt. -/// The debug location of \p InsertPt is used for the new copy. +/// This is equivalent to constrainRegToClass() with RegClass obtained from the +/// MCInstrDesc. The debug location of \p InsertPt is used for the new copy. /// /// \return The virtual register constrained to the right register class. unsigned constrainOperandRegClass(const MachineFunction &MF, diff --git a/contrib/llvm/include/llvm/CodeGen/LexicalScopes.h b/contrib/llvm/include/llvm/CodeGen/LexicalScopes.h index 79fa12ec2fbb..3ba503487823 100644 --- a/contrib/llvm/include/llvm/CodeGen/LexicalScopes.h +++ b/contrib/llvm/include/llvm/CodeGen/LexicalScopes.h @@ -196,7 +196,7 @@ class LexicalScopes { } /// dump - Print data structures to dbgs(). - void dump(); + void dump() const; /// getOrCreateAbstractScope - Find or create an abstract lexical scope. LexicalScope *getOrCreateAbstractScope(const DILocalScope *Scope); diff --git a/contrib/llvm/include/llvm/CodeGen/MachineBasicBlock.h b/contrib/llvm/include/llvm/CodeGen/MachineBasicBlock.h index 051908c40df7..97a49ce4dc4f 100644 --- a/contrib/llvm/include/llvm/CodeGen/MachineBasicBlock.h +++ b/contrib/llvm/include/llvm/CodeGen/MachineBasicBlock.h @@ -376,6 +376,9 @@ class MachineBasicBlock /// Indicates if this is the entry block of a cleanup funclet. void setIsCleanupFuncletEntry(bool V = true) { IsCleanupFuncletEntry = V; } + /// Returns true if it is legal to hoist instructions into this block. + bool isLegalToHoistInto() const; + // Code Layout methods. /// Move 'this' block before or after the specified block. This only moves diff --git a/contrib/llvm/include/llvm/CodeGen/MachineMemOperand.h b/contrib/llvm/include/llvm/CodeGen/MachineMemOperand.h index 4d83f27eac3c..78adce507b8c 100644 --- a/contrib/llvm/include/llvm/CodeGen/MachineMemOperand.h +++ b/contrib/llvm/include/llvm/CodeGen/MachineMemOperand.h @@ -59,6 +59,11 @@ struct MachinePointerInfo { return MachinePointerInfo(V.get(), Offset+O); } + /// Return true if memory region [V, V+Offset+Size) is known to be + /// dereferenceable. + bool isDereferenceable(unsigned Size, LLVMContext &C, + const DataLayout &DL) const; + /// Return the LLVM IR address space number that this pointer points into. unsigned getAddrSpace() const; diff --git a/contrib/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h b/contrib/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h index 61cff3890b75..34b21ceddd43 100644 --- a/contrib/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h +++ b/contrib/llvm/include/llvm/CodeGen/MachineModuleInfoImpls.h @@ -77,33 +77,6 @@ class MachineModuleInfoELF : public MachineModuleInfoImpl { SymbolListTy GetGVStubList() { return getSortedStubs(GVStubs); } }; -/// MachineModuleInfoWasm - This is a MachineModuleInfoImpl implementation -/// for Wasm targets. -class MachineModuleInfoWasm : public MachineModuleInfoImpl { - /// WebAssembly global variables defined by CodeGen. - std::vector Globals; - - /// The WebAssembly global variable which is the stack pointer. - unsigned StackPointerGlobal; - - virtual void anchor(); // Out of line virtual method. -public: - MachineModuleInfoWasm(const MachineModuleInfo &) - : StackPointerGlobal(-1U) {} - - void addGlobal(const wasm::Global &G) { Globals.push_back(G); } - const std::vector &getGlobals() const { return Globals; } - - bool hasStackPointerGlobal() const { - return StackPointerGlobal != -1U; - } - unsigned getStackPointerGlobal() const { - assert(hasStackPointerGlobal() && "Stack ptr global hasn't been set"); - return StackPointerGlobal; - } - void setStackPointerGlobal(unsigned Global) { StackPointerGlobal = Global; } -}; - } // end namespace llvm #endif diff --git a/contrib/llvm/include/llvm/CodeGen/MachineScheduler.h b/contrib/llvm/include/llvm/CodeGen/MachineScheduler.h index 3b02ec400aba..34cbffa78203 100644 --- a/contrib/llvm/include/llvm/CodeGen/MachineScheduler.h +++ b/contrib/llvm/include/llvm/CodeGen/MachineScheduler.h @@ -203,7 +203,7 @@ class MachineSchedStrategy { MachineBasicBlock::iterator End, unsigned NumRegionInstrs) {} - virtual void dumpPolicy() {} + virtual void dumpPolicy() const {} /// Check if pressure tracking is needed before building the DAG and /// initializing this strategy. Called after initPolicy. @@ -555,7 +555,7 @@ class ReadyQueue { return Queue.begin() + idx; } - void dump(); + void dump() const; }; /// Summarize the unscheduled region. @@ -756,7 +756,7 @@ class SchedBoundary { SUnit *pickOnlyChoice(); #ifndef NDEBUG - void dumpScheduledState(); + void dumpScheduledState() const; #endif }; @@ -890,7 +890,7 @@ class GenericScheduler : public GenericSchedulerBase { MachineBasicBlock::iterator End, unsigned NumRegionInstrs) override; - void dumpPolicy() override; + void dumpPolicy() const override; bool shouldTrackPressure() const override { return RegionPolicy.ShouldTrackPressure; diff --git a/contrib/llvm/include/llvm/CodeGen/MacroFusion.h b/contrib/llvm/include/llvm/CodeGen/MacroFusion.h new file mode 100644 index 000000000000..473784bc5841 --- /dev/null +++ b/contrib/llvm/include/llvm/CodeGen/MacroFusion.h @@ -0,0 +1,41 @@ +//===- MacroFusion.h - Macro Fusion ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file contains the definition of the DAG scheduling mutation to +/// pair instructions back to back. +// +//===----------------------------------------------------------------------===// + +#include +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/CodeGen/MachineScheduler.h" + +namespace llvm { + +/// \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 ShouldSchedulePredTy; + +/// \brief Create a DAG scheduling mutation to pair instructions back to back +/// for instructions that benefit according to the target-specific +/// shouldScheduleAdjacent predicate function. +std::unique_ptr +createMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent); + +/// \brief Create a DAG scheduling mutation to pair branch instructions with one +/// of their predecessors back to back for instructions that benefit according +/// to the target-specific shouldScheduleAdjacent predicate function. +std::unique_ptr +createBranchMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent); + +} // end namespace llvm diff --git a/contrib/llvm/include/llvm/CodeGen/RegisterScavenging.h b/contrib/llvm/include/llvm/CodeGen/RegisterScavenging.h index ad1efe18c72d..489c72b81a98 100644 --- a/contrib/llvm/include/llvm/CodeGen/RegisterScavenging.h +++ b/contrib/llvm/include/llvm/CodeGen/RegisterScavenging.h @@ -156,12 +156,24 @@ class RegScavenger { /// available and do the appropriate bookkeeping. SPAdj is the stack /// adjustment due to call frame, it's passed along to eliminateFrameIndex(). /// Returns the scavenged register. + /// This is deprecated as it depends on the quality of the kill flags being + /// present; Use scavengeRegisterBackwards() instead! unsigned scavengeRegister(const TargetRegisterClass *RegClass, MachineBasicBlock::iterator I, int SPAdj); unsigned scavengeRegister(const TargetRegisterClass *RegClass, int SPAdj) { return scavengeRegister(RegClass, MBBI, SPAdj); } + /// Make a register of the specific register class available from the current + /// position backwards to the place before \p To. If \p RestoreAfter is true + /// this includes the instruction following the current position. + /// SPAdj is the stack adjustment due to call frame, it's passed along to + /// eliminateFrameIndex(). + /// Returns the scavenged register. + unsigned scavengeRegisterBackwards(const TargetRegisterClass &RC, + MachineBasicBlock::iterator To, + bool RestoreAfter, int SPAdj); + /// Tell the scavenger a register is used. void setRegUsed(unsigned Reg, LaneBitmask LaneMask = LaneBitmask::getAll()); @@ -202,6 +214,12 @@ class RegScavenger { /// Mark live-in registers of basic block as used. void setLiveInsUsed(const MachineBasicBlock &MBB); + + /// Spill a register after position \p After and reload it before position + /// \p UseMI. + ScavengedInfo &spill(unsigned Reg, const TargetRegisterClass &RC, int SPAdj, + MachineBasicBlock::iterator After, + MachineBasicBlock::iterator &UseMI); }; /// Replaces all frame index virtual registers with physical registers. Uses the diff --git a/contrib/llvm/include/llvm/CodeGen/SelectionDAGAddressAnalysis.h b/contrib/llvm/include/llvm/CodeGen/SelectionDAGAddressAnalysis.h new file mode 100644 index 000000000000..d82ab7d647e7 --- /dev/null +++ b/contrib/llvm/include/llvm/CodeGen/SelectionDAGAddressAnalysis.h @@ -0,0 +1,64 @@ +//===-- llvm/CodeGen/SelectionDAGAddressAnalysis.h ------- DAG Address Analysis +//---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// + +#ifndef LLVM_CODEGEN_SELECTIONDAGADDRESSANALYSIS_H +#define LLVM_CODEGEN_SELECTIONDAGADDRESSANALYSIS_H + +#include "llvm/CodeGen/ISDOpcodes.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" + +namespace llvm { +/// Helper struct to parse and store a memory address as base + index + offset. +/// We ignore sign extensions when it is safe to do so. +/// The following two expressions are not equivalent. To differentiate we need +/// to store whether there was a sign extension involved in the index +/// computation. +/// (load (i64 add (i64 copyfromreg %c) +/// (i64 signextend (add (i8 load %index) +/// (i8 1)))) +/// vs +/// +/// (load (i64 add (i64 copyfromreg %c) +/// (i64 signextend (i32 add (i32 signextend (i8 load %index)) +/// (i32 1))))) +class BaseIndexOffset { +private: + SDValue Base; + SDValue Index; + int64_t Offset; + bool IsIndexSignExt; + +public: + BaseIndexOffset() : Offset(0), IsIndexSignExt(false) {} + + BaseIndexOffset(SDValue Base, SDValue Index, int64_t Offset, + bool IsIndexSignExt) + : Base(Base), Index(Index), Offset(Offset), + IsIndexSignExt(IsIndexSignExt) {} + + SDValue getBase() { return Base; } + SDValue getIndex() { return Index; } + + bool equalBaseIndex(BaseIndexOffset &Other, const SelectionDAG &DAG) { + int64_t Off; + return equalBaseIndex(Other, DAG, Off); + } + + bool equalBaseIndex(BaseIndexOffset &Other, const SelectionDAG &DAG, + int64_t &Off); + + /// Parses tree in Ptr for base, index, offset addresses. + static BaseIndexOffset match(SDValue Ptr); +}; +} // namespace llvm + +#endif diff --git a/contrib/llvm/include/llvm/CodeGen/SelectionDAGNodes.h b/contrib/llvm/include/llvm/CodeGen/SelectionDAGNodes.h index 0cd26d35a482..af418d3050e4 100644 --- a/contrib/llvm/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/contrib/llvm/include/llvm/CodeGen/SelectionDAGNodes.h @@ -2107,7 +2107,7 @@ class MaskedGatherScatterSDNode : public MemSDNode { public: friend class SelectionDAG; - MaskedGatherScatterSDNode(ISD::NodeType NodeTy, unsigned Order, + MaskedGatherScatterSDNode(unsigned NodeTy, unsigned Order, const DebugLoc &dl, SDVTList VTs, EVT MemVT, MachineMemOperand *MMO) : MemSDNode(NodeTy, Order, dl, VTs, MemVT, MMO) {} diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/CVRecord.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/CVRecord.h index 4c6bbedc6bbd..44040e04388a 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/CVRecord.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -27,9 +27,12 @@ namespace codeview { template class CVRecord { public: - CVRecord() = default; + CVRecord() : Type(static_cast(0)) {} + CVRecord(Kind K, ArrayRef Data) : Type(K), RecordData(Data) {} + bool valid() const { return Type != static_cast(0); } + uint32_t length() const { return RecordData.size(); } Kind kind() const { return Type; } ArrayRef data() const { return RecordData; } diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/CodeView.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/CodeView.h index 6820e26b754c..b7a7e33abadf 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/CodeView.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/CodeView.h @@ -402,6 +402,16 @@ enum class LocalSymFlags : uint16_t { }; CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(LocalSymFlags) +/// Corresponds to the CV_PUBSYMFLAGS bitfield. +enum class PublicSymFlags : uint32_t { + None = 0, + Code = 1 << 0, + Function = 1 << 1, + Managed = 1 << 2, + MSIL = 1 << 3, +}; +CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(PublicSymFlags) + /// Corresponds to the CV_PROCFLAGS bitfield. enum class ProcSymFlags : uint8_t { None = 0, diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h index 694731742064..ee17b47d8e63 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h @@ -51,11 +51,23 @@ class DebugSubsectionRecordBuilder { public: DebugSubsectionRecordBuilder(std::shared_ptr Subsection, CodeViewContainer Container); + + /// Use this to copy existing subsections directly from source to destination. + /// For example, line table subsections in an object file only need to be + /// relocated before being copied into the PDB. + DebugSubsectionRecordBuilder(const DebugSubsectionRecord &Contents, + CodeViewContainer Container); + uint32_t calculateSerializedLength(); Error commit(BinaryStreamWriter &Writer) const; private: + /// The subsection to build. Will be null if Contents is non-empty. std::shared_ptr Subsection; + + /// The bytes of the subsection. Only non-empty if Subsection is null. + DebugSubsectionRecord Contents; + CodeViewContainer Container; }; diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h index 013e440613fc..5d54bb4cca84 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/EnumTables.h @@ -22,6 +22,7 @@ namespace codeview { ArrayRef> getSymbolTypeNames(); ArrayRef> getTypeLeafNames(); ArrayRef> getRegisterNames(); +ArrayRef> getPublicSymFlagNames(); ArrayRef> getProcSymFlagNames(); ArrayRef> getLocalFlagNames(); ArrayRef> getFrameCookieKindNames(); diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h index 0d056e42b45f..8b1540abf903 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h @@ -11,18 +11,15 @@ #define LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H #include "llvm/DebugInfo/CodeView/TypeCollection.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/Support/Allocator.h" #include "llvm/Support/Error.h" +#include "llvm/Support/StringSaver.h" namespace llvm { namespace codeview { -class TypeDatabase; -class TypeVisitorCallbacks; - /// \brief Provides amortized O(1) random access to a CodeView type stream. /// Normally to access a type from a type stream, you must know its byte /// offset into the type stream, because type records are variable-lengthed. @@ -47,6 +44,11 @@ class TypeVisitorCallbacks; /// of O(N/M) and an amortized time of O(1). class LazyRandomTypeCollection : public TypeCollection { typedef FixedStreamArray PartialOffsetArray; + struct CacheEntry { + CVType Type; + uint32_t Offset; + StringRef Name; + }; public: explicit LazyRandomTypeCollection(uint32_t RecordCountHint); @@ -56,8 +58,10 @@ class LazyRandomTypeCollection : public TypeCollection { PartialOffsetArray PartialOffsets); LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t RecordCountHint); - void reset(ArrayRef Data); - void reset(StringRef Data); + void reset(ArrayRef Data, uint32_t RecordCountHint); + void reset(StringRef Data, uint32_t RecordCountHint); + + uint32_t getOffsetOfType(TypeIndex Index); CVType getType(TypeIndex Index) override; StringRef getTypeName(TypeIndex Index) override; @@ -68,27 +72,26 @@ class LazyRandomTypeCollection : public TypeCollection { Optional getNext(TypeIndex Prev) override; private: - const TypeDatabase &database() const { return Database; } Error ensureTypeExists(TypeIndex Index); + void ensureCapacityFor(TypeIndex Index); Error visitRangeForType(TypeIndex TI); Error fullScanForType(TypeIndex TI); - Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End); - Error visitOneRecord(TypeIndex TI, uint32_t Offset, CVType &Record); + void visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End); - /// Visited records get automatically added to the type database. - TypeDatabase Database; + /// Number of actual records. + uint32_t Count = 0; + + /// The largest type index which we've visited. + TypeIndex LargestTypeIndex = TypeIndex::None(); + + BumpPtrAllocator Allocator; + StringSaver NameStorage; /// The type array to allow random access visitation of. CVTypeArray Types; - /// The database visitor which adds new records to the database. - TypeDatabaseVisitor DatabaseVisitor; - - /// A vector mapping type indices to type offset. For every record that has - /// been visited, contains the absolute offset of that record in the record - /// array. - std::vector KnownOffsets; + std::vector Records; /// An array of index offsets for the given type stream, allowing log(N) /// lookups of a type record by index. Similar to KnownOffsets but only diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h index 5f85ed28cb3a..1cf77fcdecbe 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -363,7 +363,7 @@ class PublicSym32 : public SymbolRecord { : SymbolRecord(SymbolRecordKind::PublicSym32), RecordOffset(RecordOffset) {} - TypeIndex Index; + PublicSymFlags Flags; uint32_t Offset; uint16_t Segment; StringRef Name; diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h deleted file mode 100644 index a743e7f70855..000000000000 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeDatabase.h +++ /dev/null @@ -1,84 +0,0 @@ -//===- TypeDatabase.h - A collection of CodeView type records ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASE_H -#define LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASE_H - -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/SmallVector.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/StringSaver.h" - -namespace llvm { -namespace codeview { -class TypeDatabase : public TypeCollection { - friend class RandomAccessTypeVisitor; - -public: - explicit TypeDatabase(uint32_t Capacity); - - /// Records the name of a type, and reserves its type index. - TypeIndex appendType(StringRef Name, const CVType &Data); - - /// Records the name of a type, and reserves its type index. - void recordType(StringRef Name, TypeIndex Index, const CVType &Data); - - /// Saves the name in a StringSet and creates a stable StringRef. - StringRef saveTypeName(StringRef TypeName); - - StringRef getTypeName(TypeIndex Index) const; - - const CVType &getTypeRecord(TypeIndex Index) const; - CVType &getTypeRecord(TypeIndex Index); - - bool contains(TypeIndex Index) const; - uint32_t size() const; - uint32_t capacity() const; - bool empty() const; - - CVType getType(TypeIndex Index) override; - StringRef getTypeName(TypeIndex Index) override; - bool contains(TypeIndex Index) override; - uint32_t size() override; - uint32_t capacity() override; - - Optional getFirst() override; - Optional getNext(TypeIndex Prev) override; - - Optional largestTypeIndexLessThan(TypeIndex TI) const; - -private: - TypeIndex getAppendIndex() const; - - void grow(); - void grow(TypeIndex Index); - - BumpPtrAllocator Allocator; - - uint32_t Count = 0; - TypeIndex LargestTypeIndex; - - /// All user defined type records in .debug$T live in here. Type indices - /// greater than 0x1000 are user defined. Subtract 0x1000 from the index to - /// index into this vector. - SmallVector CVUDTNames; - SmallVector TypeRecords; - - StringSaver TypeNameStorage; - - BitVector ValidRecords; -}; -} -} - -#endif \ No newline at end of file diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h deleted file mode 100644 index 77dbc91a7d38..000000000000 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h +++ /dev/null @@ -1,62 +0,0 @@ -//===-- TypeDatabaseVisitor.h -----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASEVISITOR_H -#define LLVM_DEBUGINFO_CODEVIEW_TYPEDATABASEVISITOR_H - -#include "llvm/ADT/PointerUnion.h" - -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" - -namespace llvm { -namespace codeview { - -/// Dumper for CodeView type streams found in COFF object files and PDB files. -class TypeDatabaseVisitor : public TypeVisitorCallbacks { -public: - explicit TypeDatabaseVisitor(TypeDatabase &TypeDB) : TypeDB(&TypeDB) {} - - /// Paired begin/end actions for all types. Receives all record data, - /// including the fixed-length record prefix. - Error visitTypeBegin(CVType &Record) override; - Error visitTypeBegin(CVType &Record, TypeIndex Index) override; - Error visitTypeEnd(CVType &Record) override; - Error visitMemberBegin(CVMemberRecord &Record) override; - Error visitMemberEnd(CVMemberRecord &Record) override; - -#define TYPE_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override; -#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" - -private: - StringRef getTypeName(TypeIndex Index) const; - StringRef saveTypeName(StringRef Name); - - bool IsInFieldList = false; - - /// Name of the current type. Only valid before visitTypeEnd. - StringRef Name; - /// Current type index. Only valid before visitTypeEnd, and if we are - /// visiting a random access type database. - Optional CurrentTypeIndex; - - TypeDatabase *TypeDB; -}; - -} // end namespace codeview -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h index 82ceb5038316..c393b42cd27c 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeIndexDiscovery.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_CODEVIEW_TYPEINDEXDISCOVERY_H #include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/Error.h" @@ -27,6 +28,11 @@ void discoverTypeIndices(ArrayRef RecordData, SmallVectorImpl &Refs); void discoverTypeIndices(const CVType &Type, SmallVectorImpl &Refs); + +/// Discover type indices in symbol records. Returns false if this is an unknown +/// record. +bool discoverTypeIndices(const CVSymbol &Symbol, + SmallVectorImpl &Refs); } } diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeName.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeName.h new file mode 100644 index 000000000000..a987b4afd283 --- /dev/null +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeName.h @@ -0,0 +1,22 @@ +//===- TypeName.h --------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPENAME_H +#define LLVM_DEBUGINFO_CODEVIEW_TYPENAME_H + +#include "llvm/DebugInfo/CodeView/TypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeIndex.h" + +namespace llvm { +namespace codeview { +std::string computeTypeName(TypeCollection &Types, TypeIndex Index); +} +} // namespace llvm + +#endif diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h index 6156223b2560..cbe8d6066bb9 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h @@ -25,6 +25,7 @@ class TypeRecordMapping : public TypeVisitorCallbacks { explicit TypeRecordMapping(BinaryStreamReader &Reader) : IO(Reader) {} explicit TypeRecordMapping(BinaryStreamWriter &Writer) : IO(Writer) {} + using TypeVisitorCallbacks::visitTypeBegin; Error visitTypeBegin(CVType &Record) override; Error visitTypeEnd(CVType &Record) override; diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h index f785d4509547..988a2d4aa834 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h @@ -93,6 +93,7 @@ class TypeSerializer : public TypeVisitorCallbacks { TypeIndex insertRecord(const RemappedType &Record); Expected visitTypeEndGetIndex(CVType &Record); + using TypeVisitorCallbacks::visitTypeBegin; Error visitTypeBegin(CVType &Record) override; Error visitTypeEnd(CVType &Record) override; Error visitMemberBegin(CVMemberRecord &Record) override; diff --git a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeTableCollection.h b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeTableCollection.h index 42b62ba2b6ce..80326a0ffd39 100644 --- a/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeTableCollection.h +++ b/contrib/llvm/include/llvm/DebugInfo/CodeView/TypeTableCollection.h @@ -11,7 +11,9 @@ #define LLVM_DEBUGINFO_CODEVIEW_TYPETABLECOLLECTION_H #include "llvm/DebugInfo/CodeView/TypeCollection.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/Support/StringSaver.h" + +#include namespace llvm { namespace codeview { @@ -30,11 +32,10 @@ class TypeTableCollection : public TypeCollection { uint32_t capacity() override; private: - bool hasCapacityFor(TypeIndex Index) const; - void ensureTypeExists(TypeIndex Index); - + BumpPtrAllocator Allocator; + StringSaver NameStorage; + std::vector Names; ArrayRef> Records; - TypeDatabase Database; }; } } diff --git a/contrib/llvm/include/llvm/DebugInfo/DIContext.h b/contrib/llvm/include/llvm/DebugInfo/DIContext.h index 2e82a774cc23..4126e245ff13 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DIContext.h +++ b/contrib/llvm/include/llvm/DebugInfo/DIContext.h @@ -57,7 +57,7 @@ struct DILineInfo { } }; -typedef SmallVector, 16> DILineInfoTable; +using DILineInfoTable = SmallVector, 16>; /// DIInliningInfo - a format-neutral container for inlined code description. class DIInliningInfo { @@ -102,7 +102,7 @@ enum class DINameKind { None, ShortName, LinkageName }; /// should be filled with data. struct DILineInfoSpecifier { enum class FileLineInfoKind { None, Default, AbsoluteFilePath }; - typedef DINameKind FunctionNameKind; + using FunctionNameKind = DINameKind; FileLineInfoKind FLIKind; FunctionNameKind FNKind; @@ -174,6 +174,7 @@ class DIContext { // No verifier? Just say things went well. return true; } + virtual DILineInfo getLineInfoForAddress(uint64_t Address, DILineInfoSpecifier Specifier = DILineInfoSpecifier()) = 0; virtual DILineInfoTable getLineInfoForAddressRange(uint64_t Address, diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h index e363cff15803..190a69b75739 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h @@ -33,6 +33,7 @@ class DWARFAbbreviationDeclaration { dwarf::Attribute Attr; dwarf::Form Form; + /// The following field is used for ByteSize for non-implicit_const /// attributes and as value for implicit_const ones, indicated by /// Form == DW_FORM_implicit_const. @@ -58,7 +59,7 @@ class DWARFAbbreviationDeclaration { /// the ByteSize member. Optional getByteSize(const DWARFUnit &U) const; }; - typedef SmallVector AttributeSpecVector; + using AttributeSpecVector = SmallVector; DWARFAbbreviationDeclaration(); @@ -67,8 +68,8 @@ class DWARFAbbreviationDeclaration { dwarf::Tag getTag() const { return Tag; } bool hasChildren() const { return HasChildren; } - typedef iterator_range - attr_iterator_range; + using attr_iterator_range = + iterator_range; attr_iterator_range attributes() const { return attr_iterator_range(AttributeSpecs.begin(), AttributeSpecs.end()); diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h index 3012b39dcc52..8bde63efe188 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h @@ -32,8 +32,9 @@ class DWARFAcceleratorTable { }; struct HeaderData { - typedef uint16_t AtomType; - typedef dwarf::Form Form; + using AtomType = uint16_t; + using Form = dwarf::Form; + uint32_t DIEOffsetBase; SmallVector, 3> Atoms; }; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h index c72604a12bfd..4bf34d52bcba 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h @@ -10,7 +10,6 @@ #ifndef LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H #define LLVM_DEBUGINFO_DWARF_DWARFCONTEXT_H -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -25,21 +24,24 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" +#include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" +#include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Host.h" #include #include #include #include -#include namespace llvm { +class DataExtractor; class MemoryBuffer; class raw_ostream; @@ -73,7 +75,7 @@ class DWARFContext : public DIContext { std::unique_ptr LocDWO; /// The maximum DWARF version of all units. - unsigned MaxVersion; + unsigned MaxVersion = 0; struct DWOFile { object::OwningBinary File; @@ -100,7 +102,7 @@ class DWARFContext : public DIContext { void parseDWOTypeUnits(); public: - DWARFContext() : DIContext(CK_DWARF), MaxVersion(0) {} + DWARFContext() : DIContext(CK_DWARF) {} DWARFContext(DWARFContext &) = delete; DWARFContext &operator=(DWARFContext &) = delete; @@ -112,9 +114,9 @@ class DWARFContext : public DIContext { bool verify(raw_ostream &OS, DIDumpType DumpType = DIDT_All) override; - typedef DWARFUnitSection::iterator_range cu_iterator_range; - typedef DWARFUnitSection::iterator_range tu_iterator_range; - typedef iterator_range tu_section_iterator_range; + using cu_iterator_range = DWARFUnitSection::iterator_range; + using tu_iterator_range = DWARFUnitSection::iterator_range; + using tu_section_iterator_range = iterator_range; /// Get compile units in this context. cu_iterator_range compile_units() { @@ -230,8 +232,10 @@ class DWARFContext : public DIContext { virtual bool isLittleEndian() const = 0; virtual uint8_t getAddressSize() const = 0; virtual const DWARFSection &getInfoSection() = 0; - typedef MapVector> TypeSectionMap; + + using TypeSectionMap = MapVector>; + virtual const TypeSectionMap &getTypesSections() = 0; virtual StringRef getAbbrevSection() = 0; virtual const DWARFSection &getLocSection() = 0; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h index 9f86fe508389..65571598d743 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h @@ -18,6 +18,8 @@ namespace llvm { +class raw_ostream; + class DWARFAbbreviationDeclarationSet { uint32_t Offset; /// Code of the first abbreviation, if all abbreviations in the set have @@ -25,8 +27,8 @@ class DWARFAbbreviationDeclarationSet { uint32_t FirstAbbrCode; std::vector Decls; - typedef std::vector::const_iterator - const_iterator; + using const_iterator = + std::vector::const_iterator; public: DWARFAbbreviationDeclarationSet(); @@ -51,8 +53,8 @@ class DWARFAbbreviationDeclarationSet { }; class DWARFDebugAbbrev { - typedef std::map - DWARFAbbreviationDeclarationSetMap; + using DWARFAbbreviationDeclarationSetMap = + std::map; DWARFAbbreviationDeclarationSetMap AbbrDeclSets; mutable DWARFAbbreviationDeclarationSetMap::const_iterator PrevAbbrOffsetPos; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h index 2d82104ea098..dfbbb95076e8 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h @@ -46,8 +46,8 @@ class DWARFDebugArangeSet { }; private: - typedef std::vector DescriptorColl; - typedef iterator_range desc_iterator_range; + using DescriptorColl = std::vector; + using desc_iterator_range = iterator_range; uint32_t Offset; Header HeaderData; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h index 2237aa361d18..ea71a50f3270 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugAranges.h @@ -76,8 +76,8 @@ class DWARFDebugAranges { } }; - typedef std::vector RangeColl; - typedef RangeColl::const_iterator RangeCollIterator; + using RangeColl = std::vector; + using RangeCollIterator = RangeColl::const_iterator; std::vector Endpoints; RangeColl Aranges; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h index 39a7ef71de97..4d624812f186 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h @@ -10,7 +10,9 @@ #ifndef LLVM_DEBUGINFO_DWARFDEBUGLINE_H #define LLVM_DEBUGINFO_DWARFDEBUGLINE_H +#include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/DataExtractor.h" #include @@ -42,10 +44,10 @@ class DWARFDebugLine { /// The size in bytes of the statement information for this compilation unit /// (not including the total_length field itself). uint64_t TotalLength; - /// Version identifier for the statement information format. - uint16_t Version; - /// In v5, size in bytes of an address (or segment offset). - uint8_t AddressSize; + /// Version, address size (starting in v5), and DWARF32/64 format; these + /// parameters affect interpretation of forms (used in the directory and + /// file tables starting with v5). + DWARFFormParams FormParams; /// In v5, size in bytes of a segment selector. uint8_t SegSelectorSize; /// The number of bytes following the prologue_length field to the beginning @@ -70,15 +72,18 @@ class DWARFDebugLine { std::vector IncludeDirectories; std::vector FileNames; - bool IsDWARF64; + const DWARFFormParams getFormParams() const { return FormParams; } + uint16_t getVersion() const { return FormParams.Version; } + uint8_t getAddressSize() const { return FormParams.AddrSize; } + bool isDWARF64() const { return FormParams.Format == dwarf::DWARF64; } - uint32_t sizeofTotalLength() const { return IsDWARF64 ? 12 : 4; } + uint32_t sizeofTotalLength() const { return isDWARF64() ? 12 : 4; } - uint32_t sizeofPrologueLength() const { return IsDWARF64 ? 8 : 4; } + uint32_t sizeofPrologueLength() const { return isDWARF64() ? 8 : 4; } /// Length of the prologue in bytes. uint32_t getLength() const { - return PrologueLength + sizeofTotalLength() + sizeof(Version) + + return PrologueLength + sizeofTotalLength() + sizeof(getVersion()) + sizeofPrologueLength(); } @@ -104,7 +109,9 @@ class DWARFDebugLine { void postAppend(); void reset(bool DefaultIsStmt); void dump(raw_ostream &OS) const; + static void dumpTableHeader(raw_ostream &OS); + static bool orderByAddress(const Row &LHS, const Row &RHS) { return LHS.Address < RHS.Address; } @@ -216,11 +223,12 @@ class DWARFDebugLine { bool parse(DataExtractor DebugLineData, const RelocAddrMap *RMap, uint32_t *OffsetPtr); + using RowVector = std::vector; + using RowIter = RowVector::const_iterator; + using SequenceVector = std::vector; + using SequenceIter = SequenceVector::const_iterator; + struct Prologue Prologue; - typedef std::vector RowVector; - typedef RowVector::const_iterator RowIter; - typedef std::vector SequenceVector; - typedef SequenceVector::const_iterator SequenceIter; RowVector Rows; SequenceVector Sequences; @@ -244,14 +252,14 @@ class DWARFDebugLine { struct LineTable *LineTable; /// The row number that starts at zero for the prologue, and increases for /// each row added to the matrix. - unsigned RowNumber; + unsigned RowNumber = 0; struct Row Row; struct Sequence Sequence; }; - typedef std::map LineTableMapTy; - typedef LineTableMapTy::iterator LineTableIter; - typedef LineTableMapTy::const_iterator LineTableConstIter; + using LineTableMapTy = std::map; + using LineTableIter = LineTableMapTy::iterator; + using LineTableConstIter = LineTableMapTy::const_iterator; const RelocAddrMap *RelocMap; LineTableMapTy LineTableMap; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h index 6d4cd8d1b5a3..821da8f9b536 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLoc.h @@ -39,7 +39,7 @@ class DWARFDebugLoc { SmallVector Entries; }; - typedef SmallVector LocationLists; + using LocationLists = SmallVector; /// A list of all the variables in the debug_loc section, each one describing /// the locations in which the variable is stored. @@ -71,7 +71,7 @@ class DWARFDebugLocDWO { SmallVector Entries; }; - typedef SmallVector LocationLists; + using LocationLists = SmallVector; LocationLists Locations; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h index 85d98b45afcd..135c50761e36 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugMacro.h @@ -40,7 +40,7 @@ class DWARFDebugMacro { }; }; - typedef SmallVector MacroList; + using MacroList = SmallVector; /// A list of all the macro entries in the debug_macinfo section. MacroList Macros; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h index 437060bc8fec..49beec92ecc6 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -12,10 +12,8 @@ #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/Support/DataExtractor.h" - #include #include -#include #include namespace llvm { @@ -29,7 +27,7 @@ struct DWARFAddressRange { }; /// DWARFAddressRangesVector - represents a set of absolute address ranges. -typedef std::vector DWARFAddressRangesVector; +using DWARFAddressRangesVector = std::vector; class DWARFDebugRangeList { public: diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h index d6a3b52f2fe1..78fa6639db08 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFFormValue.h @@ -22,6 +22,35 @@ namespace llvm { class DWARFUnit; class raw_ostream; +/// A helper struct for DWARFFormValue methods, providing information that +/// allows it to know the byte size of DW_FORM values that vary in size +/// depending on the DWARF version, address byte size, or DWARF32/DWARF64. +struct DWARFFormParams { + uint16_t Version; + uint8_t AddrSize; + dwarf::DwarfFormat Format; + + /// The definition of the size of form DW_FORM_ref_addr depends on the + /// version. In DWARF v2 it's the size of an address; after that, it's the + /// size of a reference. + uint8_t getRefAddrByteSize() const { + if (Version == 2) + return AddrSize; + return getDwarfOffsetByteSize(); + } + + /// The size of a reference is determined by the DWARF 32/64-bit format. + uint8_t getDwarfOffsetByteSize() const { + switch (Format) { + case dwarf::DwarfFormat::DWARF32: + return 4; + case dwarf::DwarfFormat::DWARF64: + return 8; + } + llvm_unreachable("Invalid Format value"); + } +}; + class DWARFFormValue { public: enum FormClass { @@ -104,79 +133,43 @@ class DWARFFormValue { /// Get the fixed byte size for a given form. /// - /// If the form always has a fixed valid byte size that doesn't depend on a - /// DWARFUnit, then an Optional with a value will be returned. If the form - /// can vary in size depending on the DWARFUnit (DWARF version, address byte - /// size, or DWARF 32/64) and the DWARFUnit is valid, then an Optional with a - /// valid value is returned. If the form is always encoded using a variable - /// length storage format (ULEB or SLEB numbers or blocks) or the size - /// depends on a DWARFUnit and the DWARFUnit is NULL, then None will be - /// returned. - /// \param Form The DWARF form to get the fixed byte size for - /// \param U The DWARFUnit that can be used to help determine the byte size. + /// If the form has a fixed byte size, then an Optional with a value will be + /// returned. If the form is always encoded using a variable length storage + /// format (ULEB or SLEB numbers or blocks) then None will be returned. /// - /// \returns Optional value with the fixed byte size or None if - /// \p Form doesn't have a fixed byte size or a DWARFUnit wasn't supplied - /// and was needed to calculate the byte size. - static Optional getFixedByteSize(dwarf::Form Form, - const DWARFUnit *U = nullptr); - - /// Get the fixed byte size for a given form. - /// - /// If the form has a fixed byte size given a valid DWARF version and address - /// byte size, then an Optional with a valid value is returned. If the form - /// is always encoded using a variable length storage format (ULEB or SLEB - /// numbers or blocks) then None will be returned. - /// - /// \param Form DWARF form to get the fixed byte size for - /// \param Version DWARF version number. - /// \param AddrSize size of an address in bytes. - /// \param Format enum value from llvm::dwarf::DwarfFormat. + /// \param Form DWARF form to get the fixed byte size for. + /// \param FormParams DWARF parameters to help interpret forms. /// \returns Optional value with the fixed byte size or None if /// \p Form doesn't have a fixed byte size. - static Optional getFixedByteSize(dwarf::Form Form, uint16_t Version, - uint8_t AddrSize, - llvm::dwarf::DwarfFormat Format); + static Optional getFixedByteSize(dwarf::Form Form, + const DWARFFormParams FormParams); - /// Skip a form in \p DebugInfoData at offset specified by \p OffsetPtr. + /// Skip a form's value in \p DebugInfoData at the offset specified by + /// \p OffsetPtr. /// - /// Skips the bytes for this form in the debug info and updates the offset. + /// Skips the bytes for the current form and updates the offset. /// - /// \param DebugInfoData the .debug_info data to use to skip the value. - /// \param OffsetPtr a reference to the offset that will be updated. - /// \param U the DWARFUnit to use when skipping the form in case the form - /// size differs according to data in the DWARFUnit. + /// \param DebugInfoData The data where we want to skip the value. + /// \param OffsetPtr A reference to the offset that will be updated. + /// \param Params DWARF parameters to help interpret forms. /// \returns true on success, false if the form was not skipped. bool skipValue(DataExtractor DebugInfoData, uint32_t *OffsetPtr, - const DWARFUnit *U) const; + const DWARFFormParams Params) const { + return DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, Params); + } - /// Skip a form in \p DebugInfoData at offset specified by \p OffsetPtr. + /// Skip a form's value in \p DebugInfoData at the offset specified by + /// \p OffsetPtr. /// - /// Skips the bytes for this form in the debug info and updates the offset. + /// Skips the bytes for the specified form and updates the offset. /// - /// \param Form the DW_FORM enumeration that indicates the form to skip. - /// \param DebugInfoData the .debug_info data to use to skip the value. - /// \param OffsetPtr a reference to the offset that will be updated. - /// \param U the DWARFUnit to use when skipping the form in case the form - /// size differs according to data in the DWARFUnit. + /// \param Form The DW_FORM enumeration that indicates the form to skip. + /// \param DebugInfoData The data where we want to skip the value. + /// \param OffsetPtr A reference to the offset that will be updated. + /// \param FormParams DWARF parameters to help interpret forms. /// \returns true on success, false if the form was not skipped. static bool skipValue(dwarf::Form Form, DataExtractor DebugInfoData, - uint32_t *OffsetPtr, const DWARFUnit *U); - - /// Skip a form in \p DebugInfoData at offset specified by \p OffsetPtr. - /// - /// Skips the bytes for this form in the debug info and updates the offset. - /// - /// \param Form the DW_FORM enumeration that indicates the form to skip. - /// \param DebugInfoData the .debug_info data to use to skip the value. - /// \param OffsetPtr a reference to the offset that will be updated. - /// \param Version DWARF version number. - /// \param AddrSize size of an address in bytes. - /// \param Format enum value from llvm::dwarf::DwarfFormat. - /// \returns true on success, false if the form was not skipped. - static bool skipValue(dwarf::Form Form, DataExtractor DebugInfoData, - uint32_t *OffsetPtr, uint16_t Version, uint8_t AddrSize, - llvm::dwarf::DwarfFormat Format); + uint32_t *OffsetPtr, const DWARFFormParams FormParams); private: void dumpString(raw_ostream &OS) const; diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h index f143de334737..f51838424614 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFRelocMap.h @@ -12,7 +12,6 @@ #include "llvm/ADT/DenseMap.h" #include -#include namespace llvm { @@ -28,7 +27,7 @@ struct RelocAddrEntry { /// dwarf where we expect relocated values. This adds a bit of complexity to the /// dwarf parsing/extraction at the benefit of not allocating memory for the /// entire size of the debug info sections. -typedef DenseMap RelocAddrMap; +using RelocAddrMap = DenseMap; } // end namespace llvm diff --git a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h index 945b8999ff22..d7ccaf82bc9a 100644 --- a/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ b/contrib/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -19,11 +19,10 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" #include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" #include "llvm/DebugInfo/DWARF/DWARFRelocMap.h" #include "llvm/DebugInfo/DWARF/DWARFSection.h" #include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h" -#include "llvm/Object/Binary.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/Support/DataExtractor.h" #include #include @@ -31,6 +30,7 @@ #include #include #include +#include #include namespace llvm { @@ -72,9 +72,9 @@ class DWARFUnitSection final : public SmallVector, 1>, bool Parsed = false; public: - typedef SmallVectorImpl> UnitVector; - typedef typename UnitVector::iterator iterator; - typedef llvm::iterator_range iterator_range; + using UnitVector = SmallVectorImpl>; + using iterator = typename UnitVector::iterator; + using iterator_range = llvm::iterator_range; UnitType *getUnitForOffset(uint32_t Offset) const override { auto *CU = std::upper_bound( @@ -128,12 +128,13 @@ class DWARFUnit { bool isDWO; const DWARFUnitSectionBase &UnitSection; + // Version, address size, and DWARF format. + DWARFFormParams FormParams; + uint32_t Offset; uint32_t Length; const DWARFAbbreviationDeclarationSet *Abbrevs; - uint16_t Version; uint8_t UnitType; - uint8_t AddrSize; uint64_t BaseAddr; /// The compile unit debug information entry items. std::vector DieArray; @@ -142,8 +143,9 @@ class DWARFUnit { /// IntervalMap does not support range removal, as a result, we use the /// std::map::upper_bound for address range lookup. std::map> AddrDieMap; - typedef iterator_range::iterator> - die_iterator_range; + + using die_iterator_range = + iterator_range::iterator>; std::shared_ptr DWO; @@ -159,7 +161,7 @@ class DWARFUnit { virtual bool extractImpl(DataExtractor debug_info, uint32_t *offset_ptr); /// Size in bytes of the unit header. - virtual uint32_t getHeaderSize() const { return Version <= 4 ? 11 : 12; } + virtual uint32_t getHeaderSize() const { return getVersion() <= 4 ? 11 : 12; } public: DWARFUnit(DWARFContext &Context, const DWARFSection &Section, @@ -197,7 +199,8 @@ class DWARFUnit { uint64_t getStringOffsetSectionRelocation(uint32_t Index) const; DataExtractor getDebugInfoExtractor() const { - return DataExtractor(InfoSection.Data, isLittleEndian, AddrSize); + return DataExtractor(InfoSection.Data, isLittleEndian, + getAddressByteSize()); } DataExtractor getStringExtractor() const { @@ -220,10 +223,14 @@ class DWARFUnit { uint32_t getOffset() const { return Offset; } uint32_t getNextUnitOffset() const { return Offset + Length + 4; } uint32_t getLength() const { return Length; } - uint16_t getVersion() const { return Version; } - dwarf::DwarfFormat getFormat() const { - return dwarf::DwarfFormat::DWARF32; // FIXME: Support DWARF64. + const DWARFFormParams &getFormParams() const { return FormParams; } + uint16_t getVersion() const { return FormParams.Version; } + dwarf::DwarfFormat getFormat() const { return FormParams.Format; } + uint8_t getAddressByteSize() const { return FormParams.AddrSize; } + uint8_t getRefAddrByteSize() const { return FormParams.getRefAddrByteSize(); } + uint8_t getDwarfOffsetByteSize() const { + return FormParams.getDwarfOffsetByteSize(); } const DWARFAbbreviationDeclarationSet *getAbbreviations() const { @@ -231,19 +238,6 @@ class DWARFUnit { } uint8_t getUnitType() const { return UnitType; } - uint8_t getAddressByteSize() const { return AddrSize; } - - uint8_t getRefAddrByteSize() const { - if (Version == 2) - return AddrSize; - return getDwarfOffsetByteSize(); - } - - uint8_t getDwarfOffsetByteSize() const { - if (getFormat() == dwarf::DwarfFormat::DWARF64) - return 8; - return 4; - } uint64_t getBaseAddress() const { return BaseAddr; } diff --git a/contrib/llvm/include/llvm/DebugInfo/MSF/MSFBuilder.h b/contrib/llvm/include/llvm/DebugInfo/MSF/MSFBuilder.h index 6d067cc1c238..b2c8f2d1c20d 100644 --- a/contrib/llvm/include/llvm/DebugInfo/MSF/MSFBuilder.h +++ b/contrib/llvm/include/llvm/DebugInfo/MSF/MSFBuilder.h @@ -12,18 +12,16 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" - #include "llvm/DebugInfo/MSF/MSFCommon.h" - #include "llvm/Support/Allocator.h" -#include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" - +#include #include #include namespace llvm { namespace msf { + class MSFBuilder { public: /// \brief Create a new `MSFBuilder`. @@ -122,7 +120,7 @@ class MSFBuilder { Error allocateBlocks(uint32_t NumBlocks, MutableArrayRef Blocks); uint32_t computeDirectoryByteSize() const; - typedef std::vector BlockList; + using BlockList = std::vector; BumpPtrAllocator &Allocator; @@ -136,7 +134,8 @@ class MSFBuilder { std::vector DirectoryBlocks; std::vector> StreamData; }; -} // namespace msf -} // namespace llvm + +} // end namespace msf +} // end namespace llvm #endif // LLVM_DEBUGINFO_MSF_MSFBUILDER_H diff --git a/contrib/llvm/include/llvm/DebugInfo/MSF/MSFCommon.h b/contrib/llvm/include/llvm/DebugInfo/MSF/MSFCommon.h index 93a9c808b736..eca1b8b89ebd 100644 --- a/contrib/llvm/include/llvm/DebugInfo/MSF/MSFCommon.h +++ b/contrib/llvm/include/llvm/DebugInfo/MSF/MSFCommon.h @@ -12,15 +12,15 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" - #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" - +#include #include namespace llvm { namespace msf { + static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f', 't', ' ', 'C', '/', 'C', '+', '+', ' ', 'M', 'S', 'F', ' ', '7', '.', '0', '0', @@ -50,8 +50,9 @@ struct SuperBlock { }; struct MSFLayout { - MSFLayout() : SB(nullptr) {} - const SuperBlock *SB; + MSFLayout() = default; + + const SuperBlock *SB = nullptr; BitVector FreePageMap; ArrayRef DirectoryBlocks; ArrayRef StreamSizes; @@ -90,15 +91,16 @@ inline uint32_t getFpmIntervalLength(const MSFLayout &L) { inline uint32_t getNumFpmIntervals(const MSFLayout &L) { uint32_t Length = getFpmIntervalLength(L); - return llvm::alignTo(L.SB->NumBlocks, Length) / Length; + return alignTo(L.SB->NumBlocks, Length) / Length; } inline uint32_t getFullFpmByteSize(const MSFLayout &L) { - return llvm::alignTo(L.SB->NumBlocks, 8) / 8; + return alignTo(L.SB->NumBlocks, 8) / 8; } Error validateSuperBlock(const SuperBlock &SB); -} // namespace msf -} // namespace llvm + +} // end namespace msf +} // end namespace llvm #endif // LLVM_DEBUGINFO_MSF_MSFCOMMON_H diff --git a/contrib/llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h b/contrib/llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h index 02f3cb09b004..6d88d2be85c9 100644 --- a/contrib/llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h +++ b/contrib/llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h @@ -1,5 +1,4 @@ -//===- MappedBlockStream.h - Discontiguous stream data in an MSF -*- C++ -//-*-===// +//==- MappedBlockStream.h - Discontiguous stream data in an MSF --*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -13,7 +12,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/BinaryStream.h" @@ -21,6 +19,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include +#include #include namespace llvm { @@ -40,6 +39,7 @@ struct MSFLayout; /// of bytes. class MappedBlockStream : public BinaryStream { friend class WritableMappedBlockStream; + public: static std::unique_ptr createStream(uint32_t BlockSize, const MSFStreamLayout &Layout, @@ -57,8 +57,8 @@ class MappedBlockStream : public BinaryStream { createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData, BumpPtrAllocator &Allocator); - llvm::support::endianness getEndian() const override { - return llvm::support::little; + support::endianness getEndian() const override { + return support::little; } Error readBytes(uint32_t Offset, uint32_t Size, @@ -68,7 +68,7 @@ class MappedBlockStream : public BinaryStream { uint32_t getLength() override; - llvm::BumpPtrAllocator &getAllocator() { return Allocator; } + BumpPtrAllocator &getAllocator() { return Allocator; } void invalidateCache(); @@ -92,7 +92,7 @@ class MappedBlockStream : public BinaryStream { const MSFStreamLayout StreamLayout; BinaryStreamRef MsfData; - typedef MutableArrayRef CacheEntry; + using CacheEntry = MutableArrayRef; // We just store the allocator by reference. We use this to allocate // contiguous memory for things like arrays or strings that cross a block @@ -124,8 +124,8 @@ class WritableMappedBlockStream : public WritableBinaryStream { createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator); - llvm::support::endianness getEndian() const override { - return llvm::support::little; + support::endianness getEndian() const override { + return support::little; } Error readBytes(uint32_t Offset, uint32_t Size, @@ -141,6 +141,7 @@ class WritableMappedBlockStream : public WritableBinaryStream { const MSFStreamLayout &getStreamLayout() const { return ReadInterface.getStreamLayout(); } + uint32_t getBlockSize() const { return ReadInterface.getBlockSize(); } uint32_t getNumBlocks() const { return ReadInterface.getNumBlocks(); } uint32_t getStreamLength() const { return ReadInterface.getStreamLength(); } @@ -153,7 +154,6 @@ class WritableMappedBlockStream : public WritableBinaryStream { private: MappedBlockStream ReadInterface; - WritableBinaryStreamRef WriteInterface; }; diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/DIA/DIASession.h b/contrib/llvm/include/llvm/DebugInfo/PDB/DIA/DIASession.h index 3f5818631e7b..350442556bef 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -31,7 +31,7 @@ class DIASession : public IPDBSession { uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; - std::unique_ptr getGlobalScope() const override; + std::unique_ptr getGlobalScope() override; std::unique_ptr getSymbolById(uint32_t SymbolId) const override; std::unique_ptr diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/IPDBSession.h b/contrib/llvm/include/llvm/DebugInfo/PDB/IPDBSession.h index 85d9fe124859..cf195095c8d2 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/IPDBSession.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/IPDBSession.h @@ -29,7 +29,7 @@ class IPDBSession { virtual uint64_t getLoadAddress() const = 0; virtual void setLoadAddress(uint64_t Address) = 0; - virtual std::unique_ptr getGlobalScope() const = 0; + virtual std::unique_ptr getGlobalScope() = 0; virtual std::unique_ptr getSymbolById(uint32_t SymbolId) const = 0; template diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h index a89e26ae943c..e4cb1b24e30d 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" #include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/Support/Error.h" @@ -52,6 +53,9 @@ class DbiModuleDescriptorBuilder { void addDebugSubsection(std::shared_ptr Subsection); + void + addDebugSubsection(const codeview::DebugSubsectionRecord &SubsectionContents); + uint16_t getStreamIndex() const; StringRef getModuleName() const { return ModuleName; } StringRef getObjFileName() const { return ObjFileName; } diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h index 7123e88cd642..3bf790726656 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h @@ -63,6 +63,13 @@ class DbiStream { PDB_Machine getMachineType() const; + BinarySubstreamRef getSectionContributionData() const; + BinarySubstreamRef getSecMapSubstreamData() const; + BinarySubstreamRef getModiSubstreamData() const; + BinarySubstreamRef getFileInfoSubstreamData() const; + BinarySubstreamRef getTypeServerMapSubstreamData() const; + BinarySubstreamRef getECSubstreamData() const; + /// If the given stream type is present, returns its stream index. If it is /// not present, returns InvalidStreamIndex. uint32_t getDebugStreamIndex(DbgHeaderType Type) const; @@ -87,10 +94,12 @@ class DbiStream { PDBStringTable ECNames; - BinaryStreamRef SecContrSubstream; - BinaryStreamRef SecMapSubstream; - BinaryStreamRef TypeServerMapSubstream; - BinaryStreamRef ECSubstream; + BinarySubstreamRef SecContrSubstream; + BinarySubstreamRef SecMapSubstream; + BinarySubstreamRef ModiSubstream; + BinarySubstreamRef FileInfoSubstream; + BinarySubstreamRef TypeServerMapSubstream; + BinarySubstreamRef ECSubstream; DbiModuleList Modules; diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h index aeb2e2ab026a..744411854181 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -58,6 +58,7 @@ class DbiStreamBuilder { Expected addModuleInfo(StringRef ModuleName); Error addModuleSourceFile(StringRef Module, StringRef File); + Error addModuleSourceFile(DbiModuleDescriptorBuilder &Module, StringRef File); Expected getSourceFileNameIndex(StringRef FileName); Error finalizeMsfLayout(); diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h index fc91fc7097bd..37bf5f3b573c 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/InfoStream.h @@ -47,6 +47,8 @@ class InfoStream { const NamedStreamMap &getNamedStreams() const; + BinarySubstreamRef getNamedStreamsBuffer() const; + uint32_t getNamedStreamIndex(llvm::StringRef Name) const; iterator_range> named_streams() const; @@ -71,6 +73,8 @@ class InfoStream { // universally unique. PDB_UniqueId Guid; + BinarySubstreamRef SubNamedStreams; + std::vector FeatureSignatures; PdbRaw_Features Features = PdbFeatureNone; diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h index c744696ae250..5565cd5582bc 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h @@ -41,9 +41,12 @@ class ModuleDebugStreamRef { iterator_range symbols(bool *HadError) const; - const codeview::CVSymbolArray &getSymbolArray() const { - return SymbolsSubstream; - } + const codeview::CVSymbolArray &getSymbolArray() const { return SymbolArray; } + + BinarySubstreamRef getSymbolsSubstream() const; + BinarySubstreamRef getC11LinesSubstream() const; + BinarySubstreamRef getC13LinesSubstream() const; + BinarySubstreamRef getGlobalRefsSubstream() const; ModuleDebugStreamRef &operator=(ModuleDebugStreamRef &&Other) = default; @@ -63,10 +66,12 @@ class ModuleDebugStreamRef { std::shared_ptr Stream; - codeview::CVSymbolArray SymbolsSubstream; - BinaryStreamRef C11LinesSubstream; - BinaryStreamRef C13LinesSubstream; - BinaryStreamRef GlobalRefsSubstream; + codeview::CVSymbolArray SymbolArray; + + BinarySubstreamRef SymbolsSubstream; + BinarySubstreamRef C11LinesSubstream; + BinarySubstreamRef C13LinesSubstream; + BinarySubstreamRef GlobalRefsSubstream; codeview::DebugSubsectionArray Subsections; }; diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h index 22ed61910d94..1687737f0e7f 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h @@ -18,7 +18,11 @@ namespace pdb { class NativeCompilandSymbol : public NativeRawSymbol { public: - NativeCompilandSymbol(NativeSession &Session, DbiModuleDescriptor MI); + NativeCompilandSymbol(NativeSession &Session, uint32_t SymbolId, + DbiModuleDescriptor MI); + + std::unique_ptr clone() const override; + PDB_SymType getSymTag() const override; bool isEditAndContinueEnabled() const override; uint32_t getLexicalParentId() const override; diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeExeSymbol.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeExeSymbol.h index 9516810539b6..15bac78df191 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeExeSymbol.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeExeSymbol.h @@ -18,7 +18,9 @@ namespace pdb { class NativeExeSymbol : public NativeRawSymbol { public: - NativeExeSymbol(NativeSession &Session); + NativeExeSymbol(NativeSession &Session, uint32_t SymbolId); + + std::unique_ptr clone() const override; std::unique_ptr findChildren(PDB_SymType Type) const override; diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h index e1e78035ff38..5e4aaafff1a9 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeRawSymbol.h @@ -19,7 +19,9 @@ class NativeSession; class NativeRawSymbol : public IPDBRawSymbol { public: - explicit NativeRawSymbol(NativeSession &PDBSession); + NativeRawSymbol(NativeSession &PDBSession, uint32_t SymbolId); + + virtual std::unique_ptr clone() const = 0; void dump(raw_ostream &OS, int Indent) const override; @@ -201,6 +203,7 @@ class NativeRawSymbol : public IPDBRawSymbol { protected: NativeSession &Session; + uint32_t SymbolId; }; } diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h index e6da266f796d..bbe207738e02 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/NativeSession.h @@ -32,7 +32,7 @@ class NativeSession : public IPDBSession { uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; - std::unique_ptr getGlobalScope() const override; + std::unique_ptr getGlobalScope() override; std::unique_ptr getSymbolById(uint32_t SymbolId) const override; std::unique_ptr diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h index 4d3c569c3cdf..4f6ad115e7df 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h @@ -13,6 +13,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/DebugInfo/MSF/IMSFFile.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MSFStreamLayout.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" @@ -85,6 +86,8 @@ class PDBFile : public msf::IMSFFile { ArrayRef getDirectoryBlockArray() const; + msf::MSFStreamLayout getStreamLayout(uint32_t StreamIdx) const; + Error parseFileHeaders(); Error parseStreamData(); diff --git a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h index 0ee697696ca5..d3475205a6c2 100644 --- a/contrib/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h +++ b/contrib/llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h @@ -16,6 +16,7 @@ #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Error.h" @@ -57,6 +58,8 @@ class TpiStream { codeview::LazyRandomTypeCollection &typeCollection() { return *Types; } + BinarySubstreamRef getTypeRecordsSubstream() const; + Error commit(); private: @@ -65,6 +68,8 @@ class TpiStream { std::unique_ptr Types; + BinarySubstreamRef TypeRecordsSubstream; + codeview::CVTypeArray TypeRecords; std::unique_ptr HashStream; diff --git a/contrib/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h b/contrib/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h index e0bec6f6cf85..e576a91e887c 100644 --- a/contrib/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h +++ b/contrib/llvm/include/llvm/DebugInfo/Symbolize/SymbolizableModule.h @@ -1,4 +1,4 @@ -//===-- SymbolizableModule.h ------------------------------------ C++ -----===// +//===- SymbolizableModule.h -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,12 +14,7 @@ #define LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEMODULE_H #include "llvm/DebugInfo/DIContext.h" - -namespace llvm { -namespace object { -class ObjectFile; -} -} +#include namespace llvm { namespace symbolize { @@ -28,7 +23,8 @@ using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind; class SymbolizableModule { public: - virtual ~SymbolizableModule() {} + virtual ~SymbolizableModule() = default; + virtual DILineInfo symbolizeCode(uint64_t ModuleOffset, FunctionNameKind FNKind, bool UseSymbolTable) const = 0; @@ -45,7 +41,7 @@ class SymbolizableModule { virtual uint64_t getModulePreferredBase() const = 0; }; -} // namespace symbolize -} // namespace llvm +} // end namespace symbolize +} // end namespace llvm #endif // LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEMODULE_H diff --git a/contrib/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h b/contrib/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h index 5103cc03a6bd..d98d49b24bca 100644 --- a/contrib/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h +++ b/contrib/llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h @@ -1,4 +1,4 @@ -//===-- Symbolize.h --------------------------------------------- C++ -----===// +//===- Symbolize.h ----------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -10,21 +10,27 @@ // Header for LLVM symbolization library. // //===----------------------------------------------------------------------===// + #ifndef LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H #define LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" +#include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Error.h" +#include +#include #include #include #include #include +#include namespace llvm { namespace symbolize { using namespace object; + using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind; class LLVMSymbolizer { @@ -36,6 +42,7 @@ class LLVMSymbolizer { bool RelativeAddresses : 1; std::string DefaultArch; std::vector DsymHints; + Options(FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName, bool UseSymbolTable = true, bool Demangle = true, bool RelativeAddresses = false, std::string DefaultArch = "") @@ -45,6 +52,7 @@ class LLVMSymbolizer { }; LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {} + ~LLVMSymbolizer() { flush(); } @@ -56,6 +64,7 @@ class LLVMSymbolizer { Expected symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset); void flush(); + static std::string DemangleName(const std::string &Name, const SymbolizableModule *DbiModuleDescriptor); @@ -63,7 +72,7 @@ class LLVMSymbolizer { private: // Bundles together object file with code/data and object file with // corresponding debug info. These objects can be the same. - typedef std::pair ObjectPair; + using ObjectPair = std::pair; /// Returns a SymbolizableModule or an error if loading debug info failed. /// Only one attempt is made to load a module, and errors during loading are @@ -106,7 +115,7 @@ class LLVMSymbolizer { Options Opts; }; -} // namespace symbolize -} // namespace llvm +} // end namespace symbolize +} // end namespace llvm -#endif +#endif // LLVM_DEBUGINFO_SYMBOLIZE_SYMBOLIZE_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h b/contrib/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h index 1586f7b80669..2830a2628753 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -15,54 +15,58 @@ #ifndef LLVM_EXECUTIONENGINE_EXECUTIONENGINE_H #define LLVM_EXECUTIONENGINE_EXECUTIONENGINE_H -#include "RuntimeDyld.h" #include "llvm-c/ExecutionEngine.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/Module.h" -#include "llvm/IR/ValueHandle.h" -#include "llvm/IR/ValueMap.h" #include "llvm/Object/Binary.h" +#include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Mutex.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" +#include +#include #include #include +#include #include #include namespace llvm { -struct GenericValue; class Constant; -class DataLayout; -class ExecutionEngine; class Function; -class GlobalVariable; +struct GenericValue; class GlobalValue; +class GlobalVariable; class JITEventListener; -class MachineCodeInfo; class MCJITMemoryManager; -class MutexGuard; class ObjectCache; class RTDyldMemoryManager; class Triple; class Type; namespace object { - class Archive; - class ObjectFile; -} + +class Archive; +class ObjectFile; + +} // end namespace object /// \brief Helper class for helping synchronize access to the global address map /// table. Access to this class should be serialized under a mutex. class ExecutionEngineState { public: - typedef StringMap GlobalAddressMapTy; + using GlobalAddressMapTy = StringMap; private: - /// GlobalAddressMap - A mapping between LLVM global symbol names values and /// their actualized version... GlobalAddressMapTy GlobalAddressMap; @@ -74,7 +78,6 @@ class ExecutionEngineState { std::map GlobalAddressReverseMap; public: - GlobalAddressMapTy &getGlobalAddressMap() { return GlobalAddressMap; } @@ -509,13 +512,15 @@ class ExecutionEngine { }; namespace EngineKind { + // These are actually bitmasks that get or-ed together. enum Kind { JIT = 0x1, Interpreter = 0x2 }; const static Kind Either = (Kind)(JIT | Interpreter); -} + +} // end namespace EngineKind /// Builder class for ExecutionEngines. Use this by stack-allocating a builder, /// chaining the various set* methods, and terminating it with a .create() @@ -655,6 +660,6 @@ class EngineBuilder { // Create wrappers for C Binding types (see CBindingWrapping.h). DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ExecutionEngine, LLVMExecutionEngineRef) -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_EXECUTIONENGINE_EXECUTIONENGINE_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/GenericValue.h b/contrib/llvm/include/llvm/ExecutionEngine/GenericValue.h index 537745519ddb..504e30a018b6 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/GenericValue.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/GenericValue.h @@ -1,4 +1,4 @@ -//===-- GenericValue.h - Represent any type of LLVM value -------*- C++ -*-===// +//===- GenericValue.h - Represent any type of LLVM value --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,18 +11,15 @@ // //===----------------------------------------------------------------------===// - #ifndef LLVM_EXECUTIONENGINE_GENERICVALUE_H #define LLVM_EXECUTIONENGINE_GENERICVALUE_H #include "llvm/ADT/APInt.h" -#include "llvm/Support/DataTypes.h" #include namespace llvm { -typedef void* PointerTy; -class APInt; +using PointerTy = void *; struct GenericValue { struct IntPair { @@ -30,25 +27,29 @@ struct GenericValue { unsigned int second; }; union { - double DoubleVal; - float FloatVal; - PointerTy PointerVal; - struct IntPair UIntPairVal; - unsigned char Untyped[8]; + double DoubleVal; + float FloatVal; + PointerTy PointerVal; + struct IntPair UIntPairVal; + unsigned char Untyped[8]; }; - APInt IntVal; // also used for long doubles. + APInt IntVal; // also used for long doubles. // For aggregate data types. std::vector AggregateVal; // to make code faster, set GenericValue to zero could be omitted, but it is // potentially can cause problems, since GenericValue to store garbage // instead of zero. - GenericValue() : IntVal(1,0) {UIntPairVal.first = 0; UIntPairVal.second = 0;} - explicit GenericValue(void *V) : PointerVal(V), IntVal(1,0) { } + GenericValue() : IntVal(1, 0) { + UIntPairVal.first = 0; + UIntPairVal.second = 0; + } + explicit GenericValue(void *V) : PointerVal(V), IntVal(1, 0) {} }; inline GenericValue PTOGV(void *P) { return GenericValue(P); } -inline void* GVTOP(const GenericValue &GV) { return GV.PointerVal; } +inline void *GVTOP(const GenericValue &GV) { return GV.PointerVal; } -} // End llvm namespace. -#endif +} // end namespace llvm + +#endif // LLVM_EXECUTIONENGINE_GENERICVALUE_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/JITEventListener.h b/contrib/llvm/include/llvm/ExecutionEngine/JITEventListener.h index 94ec4e36a199..ff7840f00a44 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/JITEventListener.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/JITEventListener.h @@ -15,8 +15,8 @@ #ifndef LLVM_EXECUTIONENGINE_JITEVENTLISTENER_H #define LLVM_EXECUTIONENGINE_JITEVENTLISTENER_H -#include "RuntimeDyld.h" #include "llvm/Config/llvm-config.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/DebugLoc.h" #include #include @@ -28,7 +28,9 @@ class MachineFunction; class OProfileWrapper; namespace object { - class ObjectFile; + +class ObjectFile; + } // end namespace object /// JITEvent_EmittedFunctionDetails - Helper struct for containing information @@ -57,7 +59,7 @@ struct JITEvent_EmittedFunctionDetails { /// The default implementation of each method does nothing. class JITEventListener { public: - typedef JITEvent_EmittedFunctionDetails EmittedFunctionDetails; + using EmittedFunctionDetails = JITEvent_EmittedFunctionDetails; public: JITEventListener() = default; diff --git a/contrib/llvm/include/llvm/ExecutionEngine/JITSymbol.h b/contrib/llvm/include/llvm/ExecutionEngine/JITSymbol.h index 88929482ce76..f09e95fddb97 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/JITSymbol.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/JITSymbol.h @@ -1,4 +1,4 @@ -//===----------- JITSymbol.h - JIT symbol abstraction -----------*- C++ -*-===// +//===- JITSymbol.h - JIT symbol abstraction ---------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -26,16 +26,18 @@ namespace llvm { class GlobalValue; namespace object { - class BasicSymbolRef; + +class BasicSymbolRef; + } // end namespace object /// @brief Represents an address in the target process's address space. -typedef uint64_t JITTargetAddress; +using JITTargetAddress = uint64_t; /// @brief Flags for symbols in the JIT. class JITSymbolFlags { public: - typedef uint8_t UnderlyingType; + using UnderlyingType = uint8_t; enum FlagNames : UnderlyingType { None = 0, @@ -46,7 +48,7 @@ class JITSymbolFlags { }; /// @brief Default-construct a JITSymbolFlags instance. - JITSymbolFlags() : Flags(None) {} + JITSymbolFlags() = default; /// @brief Construct a JITSymbolFlags instance from the given flags. JITSymbolFlags(FlagNames Flags) : Flags(Flags) {} @@ -81,15 +83,14 @@ class JITSymbolFlags { static JITSymbolFlags fromObjectSymbol(const object::BasicSymbolRef &Symbol); private: - UnderlyingType Flags; + UnderlyingType Flags = None; }; /// @brief Represents a symbol that has been evaluated to an address already. class JITEvaluatedSymbol { public: /// @brief Create a 'null' symbol. - JITEvaluatedSymbol(std::nullptr_t) - : Address(0) {} + JITEvaluatedSymbol(std::nullptr_t) {} /// @brief Create a symbol for the given address and flags. JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags) @@ -105,19 +106,18 @@ class JITEvaluatedSymbol { JITSymbolFlags getFlags() const { return Flags; } private: - JITTargetAddress Address; + JITTargetAddress Address = 0; JITSymbolFlags Flags; }; /// @brief Represents a symbol in the JIT. class JITSymbol { public: - typedef std::function GetAddressFtor; + using GetAddressFtor = std::function; /// @brief Create a 'null' symbol that represents failure to find a symbol /// definition. - JITSymbol(std::nullptr_t) - : CachedAddr(0) {} + JITSymbol(std::nullptr_t) {} /// @brief Create a symbol for a definition with a known address. JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags) @@ -137,7 +137,7 @@ class JITSymbol { /// user can materialize the definition at any time by calling the getAddress /// method. JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags) - : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {} + : GetAddress(std::move(GetAddress)), Flags(Flags) {} /// @brief Returns true if the symbol exists, false otherwise. explicit operator bool() const { return CachedAddr || GetAddress; } @@ -157,7 +157,7 @@ class JITSymbol { private: GetAddressFtor GetAddress; - JITTargetAddress CachedAddr; + JITTargetAddress CachedAddr = 0; JITSymbolFlags Flags; }; diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h index 2fccf8a0f625..8ac1b6bca0a7 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h @@ -24,16 +24,20 @@ #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/IR/Attributes.h" +#include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/ValueMapper.h" #include #include #include @@ -46,6 +50,9 @@ #include namespace llvm { + +class Value; + namespace orc { /// @brief Compile-on-demand layer. @@ -77,15 +84,15 @@ class CompileOnDemandLayer { return LambdaMaterializer(std::move(M)); } - typedef typename BaseLayerT::ModuleSetHandleT BaseLayerModuleSetHandleT; + using BaseLayerModuleHandleT = typename BaseLayerT::ModuleHandleT; // Provide type-erasure for the Modules and MemoryManagers. template class ResourceOwner { public: ResourceOwner() = default; - ResourceOwner(const ResourceOwner&) = delete; - ResourceOwner& operator=(const ResourceOwner&) = delete; + ResourceOwner(const ResourceOwner &) = delete; + ResourceOwner &operator=(const ResourceOwner &) = delete; virtual ~ResourceOwner() = default; virtual ResourceT& getResource() const = 0; @@ -106,7 +113,7 @@ class CompileOnDemandLayer { template std::unique_ptr> wrapOwnership(ResourcePtrT ResourcePtr) { - typedef ResourceOwnerImpl RO; + using RO = ResourceOwnerImpl; return llvm::make_unique(std::move(ResourcePtr)); } @@ -130,21 +137,21 @@ class CompileOnDemandLayer { }; struct LogicalDylib { - typedef std::function SymbolResolverFtor; + using SymbolResolverFtor = std::function; - typedef std::function, - std::unique_ptr)> - ModuleAdderFtor; + using ModuleAdderFtor = + std::function, + std::unique_ptr)>; struct SourceModuleEntry { std::unique_ptr> SourceMod; std::set StubsToClone; }; - typedef std::vector SourceModulesList; - typedef typename SourceModulesList::size_type SourceModuleHandle; + using SourceModulesList = std::vector; + using SourceModuleHandle = typename SourceModulesList::size_type; SourceModuleHandle addSourceModule(std::unique_ptr> M) { @@ -174,7 +181,7 @@ class CompileOnDemandLayer { void removeModulesFromBaseLayer(BaseLayerT &BaseLayer) { for (auto &BLH : BaseLayerHandles) - BaseLayer.removeModuleSet(BLH); + BaseLayer.removeModule(BLH); } std::unique_ptr ExternalSymbolResolver; @@ -183,21 +190,21 @@ class CompileOnDemandLayer { StaticGlobalRenamer StaticRenamer; ModuleAdderFtor ModuleAdder; SourceModulesList SourceModules; - std::vector BaseLayerHandles; + std::vector BaseLayerHandles; }; - typedef std::list LogicalDylibList; + using LogicalDylibList = std::list; public: - /// @brief Handle to a set of loaded modules. - typedef typename LogicalDylibList::iterator ModuleSetHandleT; + /// @brief Handle to loaded module. + using ModuleHandleT = typename LogicalDylibList::iterator; /// @brief Module partitioning functor. - typedef std::function(Function&)> PartitioningFtor; + using PartitioningFtor = std::function(Function&)>; /// @brief Builder for IndirectStubsManagers. - typedef std::function()> - IndirectStubsManagerBuilderT; + using IndirectStubsManagerBuilderT = + std::function()>; /// @brief Construct a compile-on-demand layer instance. CompileOnDemandLayer(BaseLayerT &BaseLayer, PartitioningFtor Partition, @@ -211,15 +218,14 @@ class CompileOnDemandLayer { ~CompileOnDemandLayer() { while (!LogicalDylibs.empty()) - removeModuleSet(LogicalDylibs.begin()); + removeModule(LogicalDylibs.begin()); } - + /// @brief Add a module to the compile-on-demand layer. - template - ModuleSetHandleT addModuleSet(ModuleSetT Ms, - MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { + template + ModuleHandleT addModule(std::shared_ptr M, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { LogicalDylibs.push_back(LogicalDylib()); auto &LD = LogicalDylibs.back(); @@ -232,23 +238,25 @@ class CompileOnDemandLayer { LD.ModuleAdder = [&MemMgrRef](BaseLayerT &B, std::unique_ptr M, std::unique_ptr R) { - std::vector> Ms; - Ms.push_back(std::move(M)); - return B.addModuleSet(std::move(Ms), &MemMgrRef, std::move(R)); + return B.addModule(std::move(M), &MemMgrRef, std::move(R)); }; // Process each of the modules in this module set. - for (auto &M : Ms) - addLogicalModule(LogicalDylibs.back(), std::move(M)); + addLogicalModule(LogicalDylibs.back(), std::move(M)); return std::prev(LogicalDylibs.end()); } + /// @brief Add extra modules to an existing logical module. + void addExtraModule(ModuleHandleT H, std::shared_ptr M) { + addLogicalModule(*H, std::move(M)); + } + /// @brief Remove the module represented by the given handle. /// /// This will remove all modules in the layers below that were derived from /// the module represented by H. - void removeModuleSet(ModuleSetHandleT H) { + void removeModule(ModuleHandleT H) { H->removeModulesFromBaseLayer(BaseLayer); LogicalDylibs.erase(H); } @@ -270,7 +278,7 @@ class CompileOnDemandLayer { /// @brief Get the address of a symbol provided by this layer, or some layer /// below this one. - JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, + JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name, bool ExportedSymbolsOnly) { return H->findSymbol(BaseLayer, Name, ExportedSymbolsOnly); } @@ -303,7 +311,6 @@ class CompileOnDemandLayer { private: template void addLogicalModule(LogicalDylib &LD, ModulePtrT SrcMPtr) { - // Rename all static functions / globals to $static.X : // This will unique the names across all modules in the logical dylib, // simplifying symbol lookup. @@ -495,7 +502,7 @@ class CompileOnDemandLayer { } template - BaseLayerModuleSetHandleT + BaseLayerModuleHandleT emitPartition(LogicalDylib &LD, typename LogicalDylib::SourceModuleHandle LMId, const PartitionT &Part) { @@ -581,6 +588,7 @@ class CompileOnDemandLayer { }; } // end namespace orc + } // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEONDEMANDLAYER_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h index ce0864fbd9c9..b9f7d6accc30 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h @@ -1,4 +1,4 @@ -//===-- CompileUtils.h - Utilities for compiling IR in the JIT --*- C++ -*-===// +//===- CompileUtils.h - Utilities for compiling IR in the JIT ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,24 +14,47 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H #define LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H +#include "llvm/ADT/SmallVector.h" +#include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/ExecutionEngine/ObjectMemoryBuffer.h" #include "llvm/IR/LegacyPassManager.h" -#include "llvm/MC/MCContext.h" +#include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" +#include +#include namespace llvm { + +class MCContext; +class Module; + namespace orc { /// @brief Simple compile functor: Takes a single IR module and returns an /// ObjectFile. class SimpleCompiler { public: + + using CompileResult = object::OwningBinary; + /// @brief Construct a simple compile functor with the given target. - SimpleCompiler(TargetMachine &TM) : TM(TM) {} + SimpleCompiler(TargetMachine &TM, ObjectCache *ObjCache = nullptr) + : TM(TM), ObjCache(ObjCache) {} + + /// @brief Set an ObjectCache to query before compiling. + void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; } /// @brief Compile a Module to an ObjectFile. - object::OwningBinary operator()(Module &M) const { + CompileResult operator()(Module &M) { + CompileResult CachedObject = tryToLoadFromObjectCache(M); + if (CachedObject.getBinary()) + return CachedObject; + SmallVector ObjBufferSV; raw_svector_ostream ObjStream(ObjBufferSV); @@ -44,19 +67,47 @@ class SimpleCompiler { new ObjectMemoryBuffer(std::move(ObjBufferSV))); Expected> Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); - typedef object::OwningBinary OwningObj; - if (Obj) - return OwningObj(std::move(*Obj), std::move(ObjBuffer)); + if (Obj) { + notifyObjectCompiled(M, *ObjBuffer); + return CompileResult(std::move(*Obj), std::move(ObjBuffer)); + } // TODO: Actually report errors helpfully. consumeError(Obj.takeError()); - return OwningObj(nullptr, nullptr); + return CompileResult(nullptr, nullptr); } private: + + CompileResult tryToLoadFromObjectCache(const Module &M) { + if (!ObjCache) + return CompileResult(); + + std::unique_ptr ObjBuffer = ObjCache->getObject(&M); + if (!ObjBuffer) + return CompileResult(); + + Expected> Obj = + object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); + if (!Obj) { + // TODO: Actually report errors helpfully. + consumeError(Obj.takeError()); + return CompileResult(); + } + + return CompileResult(std::move(*Obj), std::move(ObjBuffer)); + } + + void notifyObjectCompiled(const Module &M, const MemoryBuffer &ObjBuffer) { + if (ObjCache) + ObjCache->notifyObjectCompiled(&M, ObjBuffer.getMemBufferRef()); + } + TargetMachine &TM; + ObjectCache *ObjCache = nullptr; }; -} // End namespace orc. -} // End namespace llvm. +} // end namespace orc + +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h index 71d847c06264..bf8cca406844 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/ExecutionUtils.h @@ -1,4 +1,4 @@ -//===-- ExecutionUtils.h - Utilities for executing code in Orc --*- C++ -*-===// +//===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,8 +17,11 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include +#include +#include #include +#include namespace llvm { @@ -37,7 +40,6 @@ namespace orc { /// getConstructors/getDestructors functions. class CtorDtorIterator { public: - /// @brief Accessor for an element of the global_ctors/global_dtors array. /// /// This class provides a read-only view of the element with any casts on @@ -89,17 +91,16 @@ iterator_range getDestructors(const Module &M); template class CtorDtorRunner { public: - /// @brief Construct a CtorDtorRunner for the given range using the given /// name mangling function. CtorDtorRunner(std::vector CtorDtorNames, - typename JITLayerT::ModuleSetHandleT H) + typename JITLayerT::ModuleHandleT H) : CtorDtorNames(std::move(CtorDtorNames)), H(H) {} /// @brief Run the recorded constructors/destructors through the given JIT /// layer. bool runViaLayer(JITLayerT &JITLayer) const { - typedef void (*CtorDtorTy)(); + using CtorDtorTy = void (*)(); bool Error = false; for (const auto &CtorDtorName : CtorDtorNames) @@ -115,7 +116,7 @@ class CtorDtorRunner { private: std::vector CtorDtorNames; - typename JITLayerT::ModuleSetHandleT H; + typename JITLayerT::ModuleHandleT H; }; /// @brief Support class for static dtor execution. For hosted (in-process) JITs @@ -135,7 +136,6 @@ class CtorDtorRunner { /// called. class LocalCXXRuntimeOverrides { public: - /// Create a runtime-overrides class. template LocalCXXRuntimeOverrides(const MangleFtorT &Mangle) { @@ -156,7 +156,6 @@ class LocalCXXRuntimeOverrides { void runDestructors(); private: - template JITTargetAddress toTargetAddress(PtrTy* P) { return static_cast(reinterpret_cast(P)); @@ -168,15 +167,16 @@ class LocalCXXRuntimeOverrides { StringMap CXXRuntimeOverrides; - typedef void (*DestructorPtr)(void*); - typedef std::pair CXXDestructorDataPair; - typedef std::vector CXXDestructorDataPairList; + using DestructorPtr = void (*)(void *); + using CXXDestructorDataPair = std::pair; + using CXXDestructorDataPairList = std::vector; CXXDestructorDataPairList DSOHandleOverride; static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg, void *DSOHandle); }; -} // End namespace orc. -} // End namespace llvm. +} // end namespace orc + +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h index 634d1480ae4c..d582e9a33241 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/GlobalMappingLayer.h @@ -1,4 +1,4 @@ -//===---- GlobalMappingLayer.h - Run all IR through a functor ---*- C++ -*-===// +//===- GlobalMappingLayer.h - Run all IR through a functor ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,6 +17,7 @@ #include "llvm/ExecutionEngine/JITSymbol.h" #include +#include namespace llvm { namespace orc { @@ -32,7 +33,7 @@ template class GlobalMappingLayer { public: /// @brief Handle to a set of added modules. - typedef typename BaseLayerT::ModuleSetHandleT ModuleSetHandleT; + using ModuleSetHandleT = typename BaseLayerT::ModuleSetHandleT; /// @brief Construct an GlobalMappingLayer with the given BaseLayer GlobalMappingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {} @@ -102,7 +103,7 @@ class GlobalMappingLayer { std::map SymbolTable; }; -} // End namespace orc. -} // End namespace llvm. +} // end namespace orc +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_GLOBALMAPPINGLAYER_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h index f81d054440fc..99ccd4d221a5 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h @@ -1,4 +1,4 @@ -//===------ IRCompileLayer.h -- Eagerly compile IR for JIT ------*- C++ -*-===// +//===- IRCompileLayer.h -- Eagerly compile IR for JIT -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,79 +14,54 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_IRCOMPILELAYER_H #define LLVM_EXECUTIONENGINE_ORC_IRCOMPILELAYER_H +#include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" #include +#include namespace llvm { + +class Module; + namespace orc { /// @brief Eager IR compiling layer. /// -/// This layer accepts sets of LLVM IR Modules (via addModuleSet). It -/// immediately compiles each IR module to an object file (each IR Module is -/// compiled separately). The resulting set of object files is then added to -/// the layer below, which must implement the object layer concept. -template class IRCompileLayer { +/// This layer immediately compiles each IR module added via addModule to an +/// object file and adds this module file to the layer below, which must +/// implement the object layer concept. +template +class IRCompileLayer { public: - typedef std::function(Module &)> - CompileFtor; -private: - typedef typename BaseLayerT::ObjSetHandleT ObjSetHandleT; - -public: - /// @brief Handle to a set of compiled modules. - typedef ObjSetHandleT ModuleSetHandleT; + /// @brief Handle to a compiled module. + using ModuleHandleT = typename BaseLayerT::ObjHandleT; /// @brief Construct an IRCompileLayer with the given BaseLayer, which must /// implement the ObjectLayer concept. IRCompileLayer(BaseLayerT &BaseLayer, CompileFtor Compile) - : BaseLayer(BaseLayer), Compile(std::move(Compile)), ObjCache(nullptr) {} + : BaseLayer(BaseLayer), Compile(std::move(Compile)) {} - /// @brief Set an ObjectCache to query before compiling. - void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; } + /// @brief Get a reference to the compiler functor. + CompileFtor& getCompiler() { return Compile; } - /// @brief Compile each module in the given module set, then add the resulting - /// set of objects to the base layer along with the memory manager and - /// symbol resolver. + /// @brief Compile the module, and add the resulting object to the base layer + /// along with the given memory manager and symbol resolver. /// - /// @return A handle for the added modules. - template - ModuleSetHandleT addModuleSet(ModuleSetT Ms, - MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { - std::vector>> - Objects; - - for (const auto &M : Ms) { - auto Object = - llvm::make_unique>(); - - if (ObjCache) - *Object = tryToLoadFromObjectCache(*M); - - if (!Object->getBinary()) { - *Object = Compile(*M); - if (ObjCache) - ObjCache->notifyObjectCompiled(&*M, - Object->getBinary()->getMemoryBufferRef()); - } - - Objects.push_back(std::move(Object)); - } - - ModuleSetHandleT H = - BaseLayer.addObjectSet(std::move(Objects), std::move(MemMgr), - std::move(Resolver)); - - return H; + /// @return A handle for the added module. + template + ModuleHandleT addModule(std::shared_ptr M, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + using CompileResult = decltype(Compile(*M)); + auto Obj = std::make_shared(Compile(*M)); + return BaseLayer.addObject(std::move(Obj), std::move(MemMgr), + std::move(Resolver)); } - /// @brief Remove the module set associated with the handle H. - void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeObjectSet(H); } + /// @brief Remove the module associated with the handle H. + void removeModule(ModuleHandleT H) { BaseLayer.removeObject(H); } /// @brief Search for the given named symbol. /// @param Name The name of the symbol to search for. @@ -96,51 +71,33 @@ template class IRCompileLayer { return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); } - /// @brief Get the address of the given symbol in the context of the set of - /// compiled modules represented by the handle H. This call is - /// forwarded to the base layer's implementation. - /// @param H The handle for the module set to search in. + /// @brief Get the address of the given symbol in compiled module represented + /// by the handle H. This call is forwarded to the base layer's + /// implementation. + /// @param H The handle for the module to search in. /// @param Name The name of the symbol to search for. /// @param ExportedSymbolsOnly If true, search only for exported symbols. /// @return A handle for the given named symbol, if it is found in the - /// given module set. - JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, + /// given module. + JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name, bool ExportedSymbolsOnly) { return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly); } - /// @brief Immediately emit and finalize the moduleOB set represented by the - /// given handle. - /// @param H Handle for module set to emit/finalize. - void emitAndFinalize(ModuleSetHandleT H) { + /// @brief Immediately emit and finalize the module represented by the given + /// handle. + /// @param H Handle for module to emit/finalize. + void emitAndFinalize(ModuleHandleT H) { BaseLayer.emitAndFinalize(H); } private: - object::OwningBinary - tryToLoadFromObjectCache(const Module &M) { - std::unique_ptr ObjBuffer = ObjCache->getObject(&M); - if (!ObjBuffer) - return object::OwningBinary(); - - Expected> Obj = - object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef()); - if (!Obj) { - // TODO: Actually report errors helpfully. - consumeError(Obj.takeError()); - return object::OwningBinary(); - } - - return object::OwningBinary(std::move(*Obj), - std::move(ObjBuffer)); - } - BaseLayerT &BaseLayer; CompileFtor Compile; - ObjectCache *ObjCache; }; -} // End namespace orc. -} // End namespace llvm. +} // end namespace orc + +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_IRCOMPILINGLAYER_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h index c67297b111b9..8e9be6b6f4fe 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/IRTransformLayer.h @@ -1,4 +1,4 @@ -//===----- IRTransformLayer.h - Run all IR through a functor ----*- C++ -*-===// +//===- IRTransformLayer.h - Run all IR through a functor --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,46 +15,41 @@ #define LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H #include "llvm/ExecutionEngine/JITSymbol.h" +#include namespace llvm { namespace orc { /// @brief IR mutating layer. /// -/// This layer accepts sets of LLVM IR Modules (via addModuleSet). It -/// immediately applies the user supplied functor to each module, then adds -/// the set of transformed modules to the layer below. +/// This layer applies a user supplied transform to each module that is added, +/// then adds the transformed module to the layer below. template class IRTransformLayer { public: + /// @brief Handle to a set of added modules. - typedef typename BaseLayerT::ModuleSetHandleT ModuleSetHandleT; + using ModuleHandleT = typename BaseLayerT::ModuleHandleT; /// @brief Construct an IRTransformLayer with the given BaseLayer IRTransformLayer(BaseLayerT &BaseLayer, TransformFtor Transform = TransformFtor()) : BaseLayer(BaseLayer), Transform(std::move(Transform)) {} - /// @brief Apply the transform functor to each module in the module set, then - /// add the resulting set of modules to the base layer, along with the - /// memory manager and symbol resolver. + /// @brief Apply the transform functor to the module, then add the module to + /// the layer below, along with the memory manager and symbol resolver. /// /// @return A handle for the added modules. - template - ModuleSetHandleT addModuleSet(ModuleSetT Ms, - MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { - - for (auto I = Ms.begin(), E = Ms.end(); I != E; ++I) - *I = Transform(std::move(*I)); - - return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr), - std::move(Resolver)); + template + ModuleHandleT addModule(std::shared_ptr M, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + return BaseLayer.addModule(Transform(std::move(M)), std::move(MemMgr), + std::move(Resolver)); } - /// @brief Remove the module set associated with the handle H. - void removeModuleSet(ModuleSetHandleT H) { BaseLayer.removeModuleSet(H); } + /// @brief Remove the module associated with the handle H. + void removeModule(ModuleHandleT H) { BaseLayer.removeModule(H); } /// @brief Search for the given named symbol. /// @param Name The name of the symbol to search for. @@ -64,23 +59,23 @@ class IRTransformLayer { return BaseLayer.findSymbol(Name, ExportedSymbolsOnly); } - /// @brief Get the address of the given symbol in the context of the set of - /// modules represented by the handle H. This call is forwarded to the - /// base layer's implementation. - /// @param H The handle for the module set to search in. + /// @brief Get the address of the given symbol in the context of the module + /// represented by the handle H. This call is forwarded to the base + /// layer's implementation. + /// @param H The handle for the module to search in. /// @param Name The name of the symbol to search for. /// @param ExportedSymbolsOnly If true, search only for exported symbols. /// @return A handle for the given named symbol, if it is found in the - /// given module set. - JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, + /// given module. + JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name, bool ExportedSymbolsOnly) { return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly); } - /// @brief Immediately emit and finalize the module set represented by the - /// given handle. - /// @param H Handle for module set to emit/finalize. - void emitAndFinalize(ModuleSetHandleT H) { + /// @brief Immediately emit and finalize the module represented by the given + /// handle. + /// @param H Handle for module to emit/finalize. + void emitAndFinalize(ModuleHandleT H) { BaseLayer.emitAndFinalize(H); } @@ -95,7 +90,7 @@ class IRTransformLayer { TransformFtor Transform; }; -} // End namespace orc. -} // End namespace llvm. +} // end namespace orc +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_IRTRANSFORMLAYER_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h index 07bbd921dad6..e038093d7628 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/IndirectionUtils.h @@ -1,4 +1,4 @@ -//===-- IndirectionUtils.h - Utilities for adding indirections --*- C++ -*-===// +//===- IndirectionUtils.h - Utilities for adding indirections ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,9 +18,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Mangler.h" -#include "llvm/IR/Module.h" #include "llvm/Support/Error.h" #include "llvm/Support/Memory.h" #include "llvm/Support/Process.h" @@ -36,12 +33,23 @@ #include namespace llvm { + +class Constant; +class Function; +class FunctionType; +class GlobalAlias; +class GlobalVariable; +class Module; +class PointerType; +class Triple; +class Value; + namespace orc { /// @brief Target-independent base class for compile callback management. class JITCompileCallbackManager { public: - typedef std::function CompileFtor; + using CompileFtor = std::function; /// @brief Handle to a newly created compile callback. Can be used to get an /// IR constant representing the address of the trampoline, and to set @@ -125,7 +133,7 @@ class JITCompileCallbackManager { protected: JITTargetAddress ErrorHandlerAddress; - typedef std::map TrampolineMapT; + using TrampolineMapT = std::map; TrampolineMapT ActiveTrampolines; std::vector AvailableTrampolines; @@ -155,7 +163,6 @@ class LocalJITCompileCallbackManager : public JITCompileCallbackManager { /// process to be used if a compile callback fails. LocalJITCompileCallbackManager(JITTargetAddress ErrorHandlerAddress) : JITCompileCallbackManager(ErrorHandlerAddress) { - /// Set up the resolver block. std::error_code EC; ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory( @@ -220,7 +227,7 @@ class LocalJITCompileCallbackManager : public JITCompileCallbackManager { class IndirectStubsManager { public: /// @brief Map type for initializing the manager. See init. - typedef StringMap> StubInitsMap; + using StubInitsMap = StringMap>; virtual ~IndirectStubsManager() = default; @@ -336,7 +343,7 @@ class LocalIndirectStubsManager : public IndirectStubsManager { } std::vector IndirectStubsInfos; - typedef std::pair StubKey; + using StubKey = std::pair; std::vector FreeStubs; StringMap> StubIndexes; }; @@ -432,6 +439,7 @@ void cloneModuleFlagsMetadata(Module &Dst, const Module &Src, ValueToValueMapTy &VMap); } // end namespace orc + } // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_INDIRECTIONUTILS_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h index cbe2a80edf1c..6868640d38e8 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/LambdaResolver.h @@ -1,4 +1,4 @@ -//===-- LambdaResolverMM - Redirect symbol lookup via a functor -*- C++ -*-===// +//===- LambdaResolverMM - Redirect symbol lookup via a functor --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,7 +16,7 @@ #define LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H #include "llvm/ADT/STLExtras.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/JITSymbol.h" #include namespace llvm { @@ -25,7 +25,6 @@ namespace orc { template class LambdaResolver : public JITSymbolResolver { public: - LambdaResolver(DylibLookupFtorT DylibLookupFtor, ExternalLookupFtorT ExternalLookupFtor) : DylibLookupFtor(DylibLookupFtor), @@ -49,12 +48,12 @@ template > createLambdaResolver(DylibLookupFtorT DylibLookupFtor, ExternalLookupFtorT ExternalLookupFtor) { - typedef LambdaResolver LR; + using LR = LambdaResolver; return make_unique(std::move(DylibLookupFtor), std::move(ExternalLookupFtor)); } -} // End namespace orc. -} // End namespace llvm. +} // end namespace orc +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_LAMBDARESOLVER_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h index 53d4c0cfe5d4..38769aac12af 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/LazyEmittingLayer.h @@ -34,19 +34,20 @@ namespace orc { /// @brief Lazy-emitting IR layer. /// -/// This layer accepts sets of LLVM IR Modules (via addModuleSet), but does -/// not immediately emit them the layer below. Instead, emissing to the base -/// layer is deferred until the first time the client requests the address -/// (via JITSymbol::getAddress) for a symbol contained in this layer. +/// This layer accepts LLVM IR Modules (via addModule), but does not +/// immediately emit them the layer below. Instead, emissing to the base layer +/// is deferred until the first time the client requests the address (via +/// JITSymbol::getAddress) for a symbol contained in this layer. template class LazyEmittingLayer { public: - typedef typename BaseLayerT::ModuleSetHandleT BaseLayerHandleT; + + using BaseLayerHandleT = typename BaseLayerT::ModuleHandleT; private: - class EmissionDeferredSet { + class EmissionDeferredModule { public: - EmissionDeferredSet() = default; - virtual ~EmissionDeferredSet() = default; + EmissionDeferredModule() = default; + virtual ~EmissionDeferredModule() = default; JITSymbol find(StringRef Name, bool ExportedSymbolsOnly, BaseLayerT &B) { switch (EmitState) { @@ -84,9 +85,9 @@ template class LazyEmittingLayer { llvm_unreachable("Invalid emit-state."); } - void removeModulesFromBaseLayer(BaseLayerT &BaseLayer) { + void removeModuleFromBaseLayer(BaseLayerT &BaseLayer) { if (EmitState != NotEmitted) - BaseLayer.removeModuleSet(Handle); + BaseLayer.removeModule(Handle); } void emitAndFinalize(BaseLayerT &BaseLayer) { @@ -100,10 +101,9 @@ template class LazyEmittingLayer { BaseLayer.emitAndFinalize(Handle); } - template - static std::unique_ptr - create(BaseLayerT &B, ModuleSetT Ms, MemoryManagerPtrT MemMgr, + template + static std::unique_ptr + create(BaseLayerT &B, std::shared_ptr M, MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver); protected: @@ -116,14 +116,13 @@ template class LazyEmittingLayer { BaseLayerHandleT Handle; }; - template - class EmissionDeferredSetImpl : public EmissionDeferredSet { + template + class EmissionDeferredModuleImpl : public EmissionDeferredModule { public: - EmissionDeferredSetImpl(ModuleSetT Ms, - MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) - : Ms(std::move(Ms)), MemMgr(std::move(MemMgr)), + EmissionDeferredModuleImpl(std::shared_ptr M, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) + : M(std::move(M)), MemMgr(std::move(MemMgr)), Resolver(std::move(Resolver)) {} protected: @@ -154,8 +153,8 @@ template class LazyEmittingLayer { // We don't need the mangled names set any more: Once we've emitted this // to the base layer we'll just look for symbols there. MangledSymbols.reset(); - return BaseLayer.addModuleSet(std::move(Ms), std::move(MemMgr), - std::move(Resolver)); + return BaseLayer.addModule(std::move(M), std::move(MemMgr), + std::move(Resolver)); } private: @@ -197,56 +196,54 @@ template class LazyEmittingLayer { auto Symbols = llvm::make_unique>(); - for (const auto &M : Ms) { - Mangler Mang; + Mangler Mang; - for (const auto &GO : M->global_objects()) + for (const auto &GO : M->global_objects()) if (auto GV = addGlobalValue(*Symbols, GO, Mang, SearchName, ExportedSymbolsOnly)) return GV; - } MangledSymbols = std::move(Symbols); return nullptr; } - ModuleSetT Ms; + std::shared_ptr M; MemoryManagerPtrT MemMgr; SymbolResolverPtrT Resolver; mutable std::unique_ptr> MangledSymbols; }; - typedef std::list> ModuleSetListT; + using ModuleListT = std::list>; BaseLayerT &BaseLayer; - ModuleSetListT ModuleSetList; + ModuleListT ModuleList; public: - /// @brief Handle to a set of loaded modules. - typedef typename ModuleSetListT::iterator ModuleSetHandleT; + /// @brief Handle to a loaded module. + using ModuleHandleT = typename ModuleListT::iterator; /// @brief Construct a lazy emitting layer. LazyEmittingLayer(BaseLayerT &BaseLayer) : BaseLayer(BaseLayer) {} - /// @brief Add the given set of modules to the lazy emitting layer. - template - ModuleSetHandleT addModuleSet(ModuleSetT Ms, - MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { - return ModuleSetList.insert( - ModuleSetList.end(), - EmissionDeferredSet::create(BaseLayer, std::move(Ms), std::move(MemMgr), - std::move(Resolver))); + /// @brief Add the given module to the lazy emitting layer. + template + ModuleHandleT addModule(std::shared_ptr M, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + return ModuleList.insert( + ModuleList.end(), + EmissionDeferredModule::create(BaseLayer, std::move(M), + std::move(MemMgr), + std::move(Resolver))); } - /// @brief Remove the module set represented by the given handle. + /// @brief Remove the module represented by the given handle. /// - /// This method will free the memory associated with the given module set, - /// both in this layer, and the base layer. - void removeModuleSet(ModuleSetHandleT H) { - (*H)->removeModulesFromBaseLayer(BaseLayer); - ModuleSetList.erase(H); + /// This method will free the memory associated with the given module, both + /// in this layer, and the base layer. + void removeModule(ModuleHandleT H) { + (*H)->removeModuleFromBaseLayer(BaseLayer); + ModuleList.erase(H); } /// @brief Search for the given named symbol. @@ -258,42 +255,40 @@ template class LazyEmittingLayer { if (auto Symbol = BaseLayer.findSymbol(Name, ExportedSymbolsOnly)) return Symbol; - // If not found then search the deferred sets. If any of these contain a + // If not found then search the deferred modules. If any of these contain a // definition of 'Name' then they will return a JITSymbol that will emit // the corresponding module when the symbol address is requested. - for (auto &DeferredSet : ModuleSetList) - if (auto Symbol = DeferredSet->find(Name, ExportedSymbolsOnly, BaseLayer)) + for (auto &DeferredMod : ModuleList) + if (auto Symbol = DeferredMod->find(Name, ExportedSymbolsOnly, BaseLayer)) return Symbol; // If no definition found anywhere return a null symbol. return nullptr; } - /// @brief Get the address of the given symbol in the context of the set of + /// @brief Get the address of the given symbol in the context of the of /// compiled modules represented by the handle H. - JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name, + JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name, bool ExportedSymbolsOnly) { return (*H)->find(Name, ExportedSymbolsOnly, BaseLayer); } - /// @brief Immediately emit and finalize the moduleOB set represented by the - /// given handle. - /// @param H Handle for module set to emit/finalize. - void emitAndFinalize(ModuleSetHandleT H) { + /// @brief Immediately emit and finalize the module represented by the given + /// handle. + /// @param H Handle for module to emit/finalize. + void emitAndFinalize(ModuleHandleT H) { (*H)->emitAndFinalize(BaseLayer); } }; template -template -std::unique_ptr::EmissionDeferredSet> -LazyEmittingLayer::EmissionDeferredSet::create( - BaseLayerT &B, ModuleSetT Ms, MemoryManagerPtrT MemMgr, +template +std::unique_ptr::EmissionDeferredModule> +LazyEmittingLayer::EmissionDeferredModule::create( + BaseLayerT &B, std::shared_ptr M, MemoryManagerPtrT MemMgr, SymbolResolverPtrT Resolver) { - typedef EmissionDeferredSetImpl - EDS; - return llvm::make_unique(std::move(Ms), std::move(MemMgr), + using EDS = EmissionDeferredModuleImpl; + return llvm::make_unique(std::move(M), std::move(MemMgr), std::move(Resolver)); } diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h index 173c106cd3ec..c41c1233c0d9 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/ObjectTransformLayer.h @@ -15,20 +15,22 @@ #define LLVM_EXECUTIONENGINE_ORC_OBJECTTRANSFORMLAYER_H #include "llvm/ExecutionEngine/JITSymbol.h" +#include +#include namespace llvm { namespace orc { /// @brief Object mutating layer. /// -/// This layer accepts sets of ObjectFiles (via addObjectSet). It +/// This layer accepts sets of ObjectFiles (via addObject). It /// immediately applies the user supplied functor to each object, then adds /// the set of transformed objects to the layer below. template class ObjectTransformLayer { public: /// @brief Handle to a set of added objects. - typedef typename BaseLayerT::ObjSetHandleT ObjSetHandleT; + using ObjHandleT = typename BaseLayerT::ObjHandleT; /// @brief Construct an ObjectTransformLayer with the given BaseLayer ObjectTransformLayer(BaseLayerT &BaseLayer, @@ -40,20 +42,16 @@ class ObjectTransformLayer { /// memory manager and symbol resolver. /// /// @return A handle for the added objects. - template - ObjSetHandleT addObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { - - for (auto I = Objects.begin(), E = Objects.end(); I != E; ++I) - *I = Transform(std::move(*I)); - - return BaseLayer.addObjectSet(std::move(Objects), std::move(MemMgr), - std::move(Resolver)); + ObjHandleT addObject(ObjPtrT Obj, MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { + return BaseLayer.addObject(Transform(std::move(Obj)), std::move(MemMgr), + std::move(Resolver)); } /// @brief Remove the object set associated with the handle H. - void removeObjectSet(ObjSetHandleT H) { BaseLayer.removeObjectSet(H); } + void removeObject(ObjHandleT H) { BaseLayer.removeObject(H); } /// @brief Search for the given named symbol. /// @param Name The name of the symbol to search for. @@ -71,7 +69,7 @@ class ObjectTransformLayer { /// @param ExportedSymbolsOnly If true, search only for exported symbols. /// @return A handle for the given named symbol, if it is found in the /// given object set. - JITSymbol findSymbolIn(ObjSetHandleT H, const std::string &Name, + JITSymbol findSymbolIn(ObjHandleT H, const std::string &Name, bool ExportedSymbolsOnly) { return BaseLayer.findSymbolIn(H, Name, ExportedSymbolsOnly); } @@ -79,10 +77,10 @@ class ObjectTransformLayer { /// @brief Immediately emit and finalize the object set represented by the /// given handle. /// @param H Handle for object set to emit/finalize. - void emitAndFinalize(ObjSetHandleT H) { BaseLayer.emitAndFinalize(H); } + void emitAndFinalize(ObjHandleT H) { BaseLayer.emitAndFinalize(H); } /// @brief Map section addresses for the objects associated with the handle H. - void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress, + void mapSectionAddress(ObjHandleT H, const void *LocalAddress, JITTargetAddress TargetAddr) { BaseLayer.mapSectionAddress(H, LocalAddress, TargetAddr); } @@ -98,7 +96,7 @@ class ObjectTransformLayer { TransformFtor Transform; }; -} // End namespace orc. -} // End namespace llvm. +} // end namespace orc +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_OBJECTTRANSFORMLAYER_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcABISupport.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcABISupport.h index fa236b0de88a..e1b55649b9f2 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcABISupport.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcABISupport.h @@ -1,4 +1,4 @@ -//===-------------- OrcABISupport.h - ABI support code ---------*- C++ -*-===// +//===- OrcABISupport.h - ABI support code -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,9 +18,12 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H #define LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H -#include "IndirectionUtils.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Memory.h" -#include "llvm/Support/Process.h" +#include +#include namespace llvm { namespace orc { @@ -37,8 +40,8 @@ class OrcGenericABI { static const unsigned TrampolineSize = 1; static const unsigned ResolverCodeSize = 1; - typedef JITTargetAddress (*JITReentryFn)(void *CallbackMgr, - void *TrampolineId); + using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr, + void *TrampolineId); static void writeResolverCode(uint8_t *ResolveMem, JITReentryFn Reentry, void *CallbackMgr) { @@ -55,6 +58,7 @@ class OrcGenericABI { class IndirectStubsInfo { public: const static unsigned StubSize = 1; + unsigned getNumStubs() const { llvm_unreachable("Not supported"); } void *getStub(unsigned Idx) const { llvm_unreachable("Not supported"); } void **getPtr(unsigned Idx) const { llvm_unreachable("Not supported"); } @@ -73,13 +77,14 @@ template class GenericIndirectStubsInfo { public: const static unsigned StubSize = StubSizeVal; - GenericIndirectStubsInfo() : NumStubs(0) {} + GenericIndirectStubsInfo() = default; GenericIndirectStubsInfo(unsigned NumStubs, sys::OwningMemoryBlock StubsMem) : NumStubs(NumStubs), StubsMem(std::move(StubsMem)) {} GenericIndirectStubsInfo(GenericIndirectStubsInfo &&Other) : NumStubs(Other.NumStubs), StubsMem(std::move(Other.StubsMem)) { Other.NumStubs = 0; } + GenericIndirectStubsInfo &operator=(GenericIndirectStubsInfo &&Other) { NumStubs = Other.NumStubs; Other.NumStubs = 0; @@ -104,7 +109,7 @@ template class GenericIndirectStubsInfo { } private: - unsigned NumStubs; + unsigned NumStubs = 0; sys::OwningMemoryBlock StubsMem; }; @@ -114,10 +119,10 @@ class OrcAArch64 { static const unsigned TrampolineSize = 12; static const unsigned ResolverCodeSize = 0x120; - typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; + using IndirectStubsInfo = GenericIndirectStubsInfo<8>; - typedef JITTargetAddress (*JITReentryFn)(void *CallbackMgr, - void *TrampolineId); + using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr, + void *TrampolineId); /// @brief Write the resolver code into the given memory. The user is be /// responsible for allocating the memory and setting permissions. @@ -148,7 +153,7 @@ class OrcX86_64_Base { static const unsigned PointerSize = 8; static const unsigned TrampolineSize = 8; - typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; + using IndirectStubsInfo = GenericIndirectStubsInfo<8>; /// @brief Write the requsted number of trampolines into the given memory, /// which must be big enough to hold 1 pointer, plus NumTrampolines @@ -172,8 +177,9 @@ class OrcX86_64_Base { class OrcX86_64_SysV : public OrcX86_64_Base { public: static const unsigned ResolverCodeSize = 0x6C; - typedef JITTargetAddress (*JITReentryFn)(void *CallbackMgr, - void *TrampolineId); + + using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr, + void *TrampolineId); /// @brief Write the resolver code into the given memory. The user is be /// responsible for allocating the memory and setting permissions. @@ -187,8 +193,9 @@ class OrcX86_64_SysV : public OrcX86_64_Base { class OrcX86_64_Win32 : public OrcX86_64_Base { public: static const unsigned ResolverCodeSize = 0x74; - typedef JITTargetAddress (*JITReentryFn)(void *CallbackMgr, - void *TrampolineId); + + using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr, + void *TrampolineId); /// @brief Write the resolver code into the given memory. The user is be /// responsible for allocating the memory and setting permissions. @@ -205,10 +212,10 @@ class OrcI386 { static const unsigned TrampolineSize = 8; static const unsigned ResolverCodeSize = 0x4a; - typedef GenericIndirectStubsInfo<8> IndirectStubsInfo; + using IndirectStubsInfo = GenericIndirectStubsInfo<8>; - typedef JITTargetAddress (*JITReentryFn)(void *CallbackMgr, - void *TrampolineId); + using JITReentryFn = JITTargetAddress (*)(void *CallbackMgr, + void *TrampolineId); /// @brief Write the resolver code into the given memory. The user is be /// responsible for allocating the memory and setting permissions. @@ -231,7 +238,7 @@ class OrcI386 { unsigned MinStubs, void *InitialPtrVal); }; -} // End namespace orc. -} // End namespace llvm. +} // end namespace orc +} // end namespace llvm #endif // LLVM_EXECUTIONENGINE_ORC_ORCABISUPPORT_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h index a19c30631c57..da02250ba169 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetClient.h @@ -1,4 +1,4 @@ -//===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- C++ -*-===// +//===- OrcRemoteTargetClient.h - Orc Remote-target Client -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,10 +16,29 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H -#include "IndirectionUtils.h" -#include "OrcRemoteTargetRPCAPI.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" +#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" -#include +#include "llvm/Support/Debug.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Memory.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include +#include +#include #define DEBUG_TYPE "orc-remote" @@ -207,7 +226,6 @@ class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI { DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n"); for (auto &ObjAllocs : Unfinalized) { - for (auto &Alloc : ObjAllocs.CodeAllocs) { DEBUG(dbgs() << " copying code: " << static_cast(Alloc.getLocalAddress()) << " -> " @@ -469,7 +487,7 @@ class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI { OrcRemoteTargetClient &Remote; ResourceIdMgr::ResourceId Id; std::vector RemoteIndirectStubsInfos; - typedef std::pair StubKey; + using StubKey = std::pair; std::vector FreeStubs; StringMap> StubIndexes; @@ -710,7 +728,6 @@ class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI { Expected reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size, uint32_t Align) { - // Check for an 'out-of-band' error, e.g. from an MM destructor. if (ExistingError) return std::move(ExistingError); diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h index 3086ef0cdf80..07ae7f04d1a0 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h @@ -1,4 +1,4 @@ -//===--- OrcRemoteTargetRPCAPI.h - Orc Remote-target RPC API ----*- C++ -*-===// +//===- OrcRemoteTargetRPCAPI.h - Orc Remote-target RPC API ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -16,12 +16,13 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H -#include "RPCUtils.h" -#include "RawByteChannel.h" #include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/ExecutionEngine/Orc/RPCUtils.h" +#include "llvm/ExecutionEngine/Orc/RawByteChannel.h" namespace llvm { namespace orc { + namespace remote { class DirectBufferWriter { @@ -72,7 +73,7 @@ class SerializationTraits< return EC; char *Addr = reinterpret_cast(static_cast(Dst)); - DBW = remote::DirectBufferWriter(0, Dst, Size); + DBW = remote::DirectBufferWriter(nullptr, Dst, Size); return C.readBytes(Addr, Size); } @@ -87,7 +88,7 @@ class OrcRemoteTargetRPCAPI protected: class ResourceIdMgr { public: - typedef uint64_t ResourceId; + using ResourceId = uint64_t; static const ResourceId InvalidId = ~0U; ResourceId getNext() { @@ -98,6 +99,7 @@ class OrcRemoteTargetRPCAPI } return NextId++; } + void release(ResourceId I) { FreeIds.push_back(I); } private: @@ -261,7 +263,8 @@ class OrcRemoteTargetRPCAPI }; } // end namespace remote + } // end namespace orc } // end namespace llvm -#endif +#endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h index a61ff102be0b..e7b6d64931b6 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/OrcRemoteTargetServer.h @@ -1,4 +1,4 @@ -//===---- OrcRemoteTargetServer.h - Orc Remote-target Server ----*- C++ -*-===// +//===- OrcRemoteTargetServer.h - Orc Remote-target Server -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,10 +15,9 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H -#include "OrcRemoteTargetRPCAPI.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/OrcError.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" @@ -48,20 +47,18 @@ namespace remote { template class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { public: - typedef std::function - SymbolLookupFtor; + using SymbolLookupFtor = + std::function; - typedef std::function - EHFrameRegistrationFtor; + using EHFrameRegistrationFtor = + std::function; OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup, EHFrameRegistrationFtor EHFramesRegister, EHFrameRegistrationFtor EHFramesDeregister) : OrcRemoteTargetRPCAPI(Channel), SymbolLookup(std::move(SymbolLookup)), EHFramesRegister(std::move(EHFramesRegister)), - EHFramesDeregister(std::move(EHFramesDeregister)), - TerminateFlag(false) { - + EHFramesDeregister(std::move(EHFramesDeregister)) { using ThisT = typename std::remove_reference::type; addHandler(*this, &ThisT::handleCallIntVoid); addHandler(*this, &ThisT::handleCallMain); @@ -106,6 +103,7 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { struct Allocator { Allocator() = default; Allocator(Allocator &&Other) : Allocs(std::move(Other.Allocs)) {} + Allocator &operator=(Allocator &&Other) { Allocs = std::move(Other.Allocs); return *this; @@ -153,7 +151,8 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { } Expected handleCallIntVoid(JITTargetAddress Addr) { - typedef int (*IntVoidFnTy)(); + using IntVoidFnTy = int (*)(); + IntVoidFnTy Fn = reinterpret_cast(static_cast(Addr)); @@ -166,7 +165,7 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { Expected handleCallMain(JITTargetAddress Addr, std::vector Args) { - typedef int (*MainFnTy)(int, const char *[]); + using MainFnTy = int (*)(int, const char *[]); MainFnTy Fn = reinterpret_cast(static_cast(Addr)); int ArgC = Args.size() + 1; @@ -175,6 +174,12 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { ArgV[0] = ""; for (auto &Arg : Args) ArgV[Idx++] = Arg.c_str(); + ArgV[ArgC] = 0; + DEBUG( + for (int Idx = 0; Idx < ArgC; ++Idx) { + llvm::dbgs() << "Arg " << Idx << ": " << ArgV[Idx] << "\n"; + } + ); DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n"); int Result = Fn(ArgC, ArgV.get()); @@ -184,7 +189,8 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { } Error handleCallVoidVoid(JITTargetAddress Addr) { - typedef void (*VoidVoidFnTy)(); + using VoidVoidFnTy = void (*)(); + VoidVoidFnTy Fn = reinterpret_cast(static_cast(Addr)); @@ -420,11 +426,11 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { SymbolLookupFtor SymbolLookup; EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister; std::map Allocators; - typedef std::vector ISBlockOwnerList; + using ISBlockOwnerList = std::vector; std::map IndirectStubsOwners; sys::OwningMemoryBlock ResolverBlock; std::vector TrampolineBlocks; - bool TerminateFlag; + bool TerminateFlag = false; }; } // end namespace remote @@ -433,4 +439,4 @@ class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI { #undef DEBUG_TYPE -#endif +#endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h index aabb44eef99d..66ad36be01c8 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h @@ -1,4 +1,4 @@ -//===-- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking --*- C++ -*-===// +//===- RTDyldObjectLinkingLayer.h - RTDyld-based jit linking ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,10 +17,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Error.h" #include @@ -36,20 +34,26 @@ namespace llvm { namespace orc { class RTDyldObjectLinkingLayerBase { +public: + + using ObjectPtr = + std::shared_ptr>; + protected: + /// @brief Holds a set of objects to be allocated/linked as a unit in the JIT. /// /// An instance of this class will be created for each set of objects added - /// via JITObjectLayer::addObjectSet. Deleting the instance (via - /// removeObjectSet) frees its memory, removing all symbol definitions that + /// via JITObjectLayer::addObject. Deleting the instance (via + /// removeObject) frees its memory, removing all symbol definitions that /// had been provided by this instance. Higher level layers are responsible /// for taking any action required to handle the missing symbols. - class LinkedObjectSet { + class LinkedObject { public: - LinkedObjectSet() = default; - LinkedObjectSet(const LinkedObjectSet&) = delete; - void operator=(const LinkedObjectSet&) = delete; - virtual ~LinkedObjectSet() = default; + LinkedObject() = default; + LinkedObject(const LinkedObject&) = delete; + void operator=(const LinkedObject&) = delete; + virtual ~LinkedObject() = default; virtual void finalize() = 0; @@ -76,19 +80,11 @@ class RTDyldObjectLinkingLayerBase { bool Finalized = false; }; - typedef std::list> LinkedObjectSetListT; + using LinkedObjectListT = std::list>; public: /// @brief Handle to a set of loaded objects. - typedef LinkedObjectSetListT::iterator ObjSetHandleT; -}; - -/// @brief Default (no-op) action to perform when loading objects. -class DoNothingOnNotifyLoaded { -public: - template - void operator()(RTDyldObjectLinkingLayerBase::ObjSetHandleT, const ObjSetT &, - const LoadResult &) {} + using ObjHandleT = LinkedObjectListT::iterator; }; /// @brief Bare bones object linking layer. @@ -97,46 +93,54 @@ class DoNothingOnNotifyLoaded { /// object files to be loaded into memory, linked, and the addresses of their /// symbols queried. All objects added to this layer can see each other's /// symbols. -template class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { public: + + using RTDyldObjectLinkingLayerBase::ObjectPtr; + + /// @brief Functor for receiving object-loaded notifications. + using NotifyLoadedFtor = std::function; + /// @brief Functor for receiving finalization notifications. - typedef std::function NotifyFinalizedFtor; + using NotifyFinalizedFtor = std::function; private: - template - class ConcreteLinkedObjectSet : public LinkedObjectSet { + + + template + class ConcreteLinkedObject : public LinkedObject { public: - ConcreteLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver, - FinalizerFtor Finalizer, - bool ProcessAllSections) + ConcreteLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver, + FinalizerFtor Finalizer, + bool ProcessAllSections) : MemMgr(std::move(MemMgr)), - PFC(llvm::make_unique(std::move(Objects), + PFC(llvm::make_unique(std::move(Obj), std::move(Resolver), std::move(Finalizer), ProcessAllSections)) { - buildInitialSymbolTable(PFC->Objects); + buildInitialSymbolTable(PFC->Obj); } - ~ConcreteLinkedObjectSet() override { + ~ConcreteLinkedObject() override { MemMgr->deregisterEHFrames(); } - - void setHandle(ObjSetHandleT H) { + + void setHandle(ObjHandleT H) { PFC->Handle = H; } void finalize() override { - assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet"); + assert(PFC && "mapSectionAddress called on finalized LinkedObject"); RuntimeDyld RTDyld(*MemMgr, *PFC->Resolver); RTDyld.setProcessAllSections(PFC->ProcessAllSections); PFC->RTDyld = &RTDyld; this->Finalized = true; - PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Objects), + PFC->Finalizer(PFC->Handle, RTDyld, std::move(PFC->Obj), [&]() { this->updateSymbolTable(RTDyld); }); @@ -158,27 +162,27 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { void mapSectionAddress(const void *LocalAddress, JITTargetAddress TargetAddr) const override { - assert(PFC && "mapSectionAddress called on finalized LinkedObjectSet"); - assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObjectSet"); + assert(PFC && "mapSectionAddress called on finalized LinkedObject"); + assert(PFC->RTDyld && "mapSectionAddress called on raw LinkedObject"); PFC->RTDyld->mapSectionAddress(LocalAddress, TargetAddr); } private: - void buildInitialSymbolTable(const ObjSetT &Objects) { - for (const auto &Obj : Objects) - for (auto &Symbol : getObject(*Obj).symbols()) { - if (Symbol.getFlags() & object::SymbolRef::SF_Undefined) - continue; - Expected SymbolName = Symbol.getName(); - // FIXME: Raise an error for bad symbols. - if (!SymbolName) { - consumeError(SymbolName.takeError()); - continue; - } - auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol); - SymbolTable.insert( - std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags))); + + void buildInitialSymbolTable(const ObjectPtr &Obj) { + for (auto &Symbol : Obj->getBinary()->symbols()) { + if (Symbol.getFlags() & object::SymbolRef::SF_Undefined) + continue; + Expected SymbolName = Symbol.getName(); + // FIXME: Raise an error for bad symbols. + if (!SymbolName) { + consumeError(SymbolName.takeError()); + continue; } + auto Flags = JITSymbolFlags::fromObjectSymbol(Symbol); + SymbolTable.insert( + std::make_pair(*SymbolName, JITEvaluatedSymbol(0, Flags))); + } } void updateSymbolTable(const RuntimeDyld &RTDyld) { @@ -189,17 +193,17 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { // Contains the information needed prior to finalization: the object files, // memory manager, resolver, and flags needed for RuntimeDyld. struct PreFinalizeContents { - PreFinalizeContents(ObjSetT Objects, SymbolResolverPtrT Resolver, + PreFinalizeContents(ObjectPtr Obj, SymbolResolverPtrT Resolver, FinalizerFtor Finalizer, bool ProcessAllSections) - : Objects(std::move(Objects)), Resolver(std::move(Resolver)), + : Obj(std::move(Obj)), Resolver(std::move(Resolver)), Finalizer(std::move(Finalizer)), ProcessAllSections(ProcessAllSections) {} - ObjSetT Objects; + ObjectPtr Obj; SymbolResolverPtrT Resolver; FinalizerFtor Finalizer; bool ProcessAllSections; - ObjSetHandleT Handle; + ObjHandleT Handle; RuntimeDyld *RTDyld; }; @@ -207,27 +211,22 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { std::unique_ptr PFC; }; - template + template std::unique_ptr< - ConcreteLinkedObjectSet> - createLinkedObjectSet(ObjSetT Objects, MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver, - FinalizerFtor Finalizer, - bool ProcessAllSections) { - typedef ConcreteLinkedObjectSet LOS; - return llvm::make_unique(std::move(Objects), std::move(MemMgr), + ConcreteLinkedObject> + createLinkedObject(ObjectPtr Obj, MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver, + FinalizerFtor Finalizer, + bool ProcessAllSections) { + using LOS = ConcreteLinkedObject; + return llvm::make_unique(std::move(Obj), std::move(MemMgr), std::move(Resolver), std::move(Finalizer), ProcessAllSections); } public: - /// @brief LoadedObjectInfo list. Contains a list of owning pointers to - /// RuntimeDyld::LoadedObjectInfo instances. - typedef std::vector> - LoadedObjInfoList; /// @brief Construct an ObjectLinkingLayer with the given NotifyLoaded, /// and NotifyFinalized functors. @@ -235,8 +234,7 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { NotifyLoadedFtor NotifyLoaded = NotifyLoadedFtor(), NotifyFinalizedFtor NotifyFinalized = NotifyFinalizedFtor()) : NotifyLoaded(std::move(NotifyLoaded)), - NotifyFinalized(std::move(NotifyFinalized)), - ProcessAllSections(false) {} + NotifyFinalized(std::move(NotifyFinalized)) {} /// @brief Set the 'ProcessAllSections' flag. /// @@ -253,23 +251,22 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { /// /// @return A handle that can be used to refer to the loaded objects (for /// symbol searching, finalization, freeing memory, etc.). - template - ObjSetHandleT addObjectSet(ObjSetT Objects, - MemoryManagerPtrT MemMgr, - SymbolResolverPtrT Resolver) { - auto Finalizer = [&](ObjSetHandleT H, RuntimeDyld &RTDyld, - const ObjSetT &Objs, - std::function LOSHandleLoad) { - LoadedObjInfoList LoadedObjInfos; + ObjHandleT addObject(ObjectPtr Obj, + MemoryManagerPtrT MemMgr, + SymbolResolverPtrT Resolver) { - for (auto &Obj : Objs) - LoadedObjInfos.push_back(RTDyld.loadObject(this->getObject(*Obj))); + auto Finalizer = [&](ObjHandleT H, RuntimeDyld &RTDyld, + const ObjectPtr &ObjToLoad, + std::function LOSHandleLoad) { + std::unique_ptr Info = + RTDyld.loadObject(*ObjToLoad->getBinary()); LOSHandleLoad(); - this->NotifyLoaded(H, Objs, LoadedObjInfos); + if (this->NotifyLoaded) + this->NotifyLoaded(H, ObjToLoad, *Info); RTDyld.finalizeWithMemoryManagerLocking(); @@ -277,17 +274,15 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { this->NotifyFinalized(H); }; - auto LOS = - createLinkedObjectSet(std::move(Objects), std::move(MemMgr), - std::move(Resolver), std::move(Finalizer), - ProcessAllSections); + auto LO = + createLinkedObject(std::move(Obj), std::move(MemMgr), std::move(Resolver), + std::move(Finalizer), ProcessAllSections); // LOS is an owning-ptr. Keep a non-owning one so that we can set the handle // below. - auto *LOSPtr = LOS.get(); + auto *LOPtr = LO.get(); - ObjSetHandleT Handle = LinkedObjSetList.insert(LinkedObjSetList.end(), - std::move(LOS)); - LOSPtr->setHandle(Handle); + ObjHandleT Handle = LinkedObjList.insert(LinkedObjList.end(), std::move(LO)); + LOPtr->setHandle(Handle); return Handle; } @@ -300,9 +295,9 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { /// indirectly) will result in undefined behavior. If dependence tracking is /// required to detect or resolve such issues it should be added at a higher /// layer. - void removeObjectSet(ObjSetHandleT H) { + void removeObject(ObjHandleT H) { // How do we invalidate the symbols in H? - LinkedObjSetList.erase(H); + LinkedObjList.erase(H); } /// @brief Search for the given named symbol. @@ -310,7 +305,7 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { /// @param ExportedSymbolsOnly If true, search only for exported symbols. /// @return A handle for the given named symbol, if it exists. JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) { - for (auto I = LinkedObjSetList.begin(), E = LinkedObjSetList.end(); I != E; + for (auto I = LinkedObjList.begin(), E = LinkedObjList.end(); I != E; ++I) if (auto Symbol = findSymbolIn(I, Name, ExportedSymbolsOnly)) return Symbol; @@ -325,13 +320,13 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { /// @param ExportedSymbolsOnly If true, search only for exported symbols. /// @return A handle for the given named symbol, if it is found in the /// given object set. - JITSymbol findSymbolIn(ObjSetHandleT H, StringRef Name, + JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) { return (*H)->getSymbol(Name, ExportedSymbolsOnly); } /// @brief Map section addresses for the objects associated with the handle H. - void mapSectionAddress(ObjSetHandleT H, const void *LocalAddress, + void mapSectionAddress(ObjHandleT H, const void *LocalAddress, JITTargetAddress TargetAddr) { (*H)->mapSectionAddress(LocalAddress, TargetAddr); } @@ -339,25 +334,16 @@ class RTDyldObjectLinkingLayer : public RTDyldObjectLinkingLayerBase { /// @brief Immediately emit and finalize the object set represented by the /// given handle. /// @param H Handle for object set to emit/finalize. - void emitAndFinalize(ObjSetHandleT H) { + void emitAndFinalize(ObjHandleT H) { (*H)->finalize(); } private: - static const object::ObjectFile& getObject(const object::ObjectFile &Obj) { - return Obj; - } - template - static const object::ObjectFile& - getObject(const object::OwningBinary &Obj) { - return *Obj.getBinary(); - } - - LinkedObjectSetListT LinkedObjSetList; + LinkedObjectListT LinkedObjList; NotifyLoadedFtor NotifyLoaded; NotifyFinalizedFtor NotifyFinalized; - bool ProcessAllSections; + bool ProcessAllSections = false; }; } // end namespace orc diff --git a/contrib/llvm/include/llvm/ExecutionEngine/Orc/RawByteChannel.h b/contrib/llvm/include/llvm/ExecutionEngine/Orc/RawByteChannel.h index 52a546f7c6eb..db810f4ef2e5 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/Orc/RawByteChannel.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/Orc/RawByteChannel.h @@ -10,20 +10,14 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_RAWBYTECHANNEL_H #define LLVM_EXECUTIONENGINE_ORC_RAWBYTECHANNEL_H -#include "OrcError.h" -#include "RPCSerialization.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/Orc/RPCSerialization.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" -#include #include #include #include -#include #include -#include namespace llvm { namespace orc { @@ -32,7 +26,7 @@ namespace rpc { /// Interface for byte-streams to be used with RPC. class RawByteChannel { public: - virtual ~RawByteChannel() {} + virtual ~RawByteChannel() = default; /// Read Size bytes from the stream into *Dst. virtual Error readBytes(char *Dst, unsigned Size) = 0; diff --git a/contrib/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h b/contrib/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h index 9470866dc0d6..1925489f7952 100644 --- a/contrib/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/contrib/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -1,4 +1,4 @@ -//===-- RuntimeDyld.h - Run-time dynamic linker for MC-JIT ------*- C++ -*-===// +//===- RuntimeDyld.h - Run-time dynamic linker for MC-JIT -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -32,7 +32,9 @@ namespace llvm { namespace object { - template class OwningBinary; + +template class OwningBinary; + } // end namespace object /// Base class for errors originating in RuntimeDyld, e.g. missing relocation @@ -51,8 +53,8 @@ class RuntimeDyldError : public ErrorInfo { std::string ErrMsg; }; -class RuntimeDyldImpl; class RuntimeDyldCheckerImpl; +class RuntimeDyldImpl; class RuntimeDyld { friend class RuntimeDyldCheckerImpl; @@ -68,7 +70,7 @@ class RuntimeDyld { friend class RuntimeDyldImpl; public: - typedef std::map ObjSectionToIDMap; + using ObjSectionToIDMap = std::map; LoadedObjectInfo(RuntimeDyldImpl &RTDyld, ObjSectionToIDMap ObjSecToIDMap) : RTDyld(RTDyld), ObjSecToIDMap(std::move(ObjSecToIDMap)) {} @@ -186,7 +188,7 @@ class RuntimeDyld { /// \brief Construct a RuntimeDyld instance. RuntimeDyld(MemoryManager &MemMgr, JITSymbolResolver &Resolver); RuntimeDyld(const RuntimeDyld &) = delete; - void operator=(const RuntimeDyld &) = delete; + RuntimeDyld &operator=(const RuntimeDyld &) = delete; ~RuntimeDyld(); /// Add the referenced object file to the list of objects to be loaded and diff --git a/contrib/llvm/include/llvm/IR/Attributes.h b/contrib/llvm/include/llvm/IR/Attributes.h index 0e8adda82cbe..0cab8bbb8ead 100644 --- a/contrib/llvm/include/llvm/IR/Attributes.h +++ b/contrib/llvm/include/llvm/IR/Attributes.h @@ -622,7 +622,8 @@ class AttributeList { // AttributeList Introspection //===--------------------------------------------------------------------===// - typedef const AttributeSet *iterator; + using iterator = const AttributeSet *; + iterator begin() const; iterator end() const; @@ -830,8 +831,8 @@ bool areInlineCompatible(const Function &Caller, const Function &Callee); /// \brief Merge caller's and callee's attributes. void mergeAttributesForInlining(Function &Caller, const Function &Callee); -} // end AttributeFuncs namespace +} // end namespace AttributeFuncs -} // end llvm namespace +} // end namespace llvm #endif // LLVM_IR_ATTRIBUTES_H diff --git a/contrib/llvm/include/llvm/IR/Attributes.td b/contrib/llvm/include/llvm/IR/Attributes.td index 75867a6e5833..616387816bf8 100644 --- a/contrib/llvm/include/llvm/IR/Attributes.td +++ b/contrib/llvm/include/llvm/IR/Attributes.td @@ -214,3 +214,5 @@ def : MergeRule<"setAND">; def : MergeRule<"setOR">; def : MergeRule<"setOR">; def : MergeRule<"adjustCallerSSPLevel">; +def : MergeRule<"adjustCallerStackProbes">; +def : MergeRule<"adjustCallerStackProbeSize">; diff --git a/contrib/llvm/include/llvm/IR/BasicBlock.h b/contrib/llvm/include/llvm/IR/BasicBlock.h index 23f838b640e0..7a35afcbafc3 100644 --- a/contrib/llvm/include/llvm/IR/BasicBlock.h +++ b/contrib/llvm/include/llvm/IR/BasicBlock.h @@ -1,4 +1,4 @@ -//===-- llvm/BasicBlock.h - Represent a basic block in the VM ---*- C++ -*-===// +//===- llvm/BasicBlock.h - Represent a basic block in the VM ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -18,13 +18,17 @@ #include "llvm/ADT/Twine.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/SymbolTableListTraits.h" #include "llvm/IR/Value.h" #include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include #include +#include namespace llvm { @@ -294,9 +298,9 @@ class BasicBlock final : public Value, // Basic blocks are data objects also return *this; } }; - typedef phi_iterator_impl<> phi_iterator; - typedef phi_iterator_impl - const_phi_iterator; + using phi_iterator = phi_iterator_impl<>; + using const_phi_iterator = + phi_iterator_impl; /// Returns a range that iterates over the phis in the basic block. /// @@ -391,6 +395,9 @@ class BasicBlock final : public Value, // Basic blocks are data objects also static_cast(this)->getLandingPadInst()); } + /// \brief Return true if it is legal to hoist instructions into this block. + bool isLegalToHoistInto() const; + private: /// \brief Increment the internal refcount of the number of BlockAddresses /// referencing this BasicBlock by \p Amt. diff --git a/contrib/llvm/include/llvm/IR/ConstantRange.h b/contrib/llvm/include/llvm/IR/ConstantRange.h index 6a50a8801f86..ff6495e7f075 100644 --- a/contrib/llvm/include/llvm/IR/ConstantRange.h +++ b/contrib/llvm/include/llvm/IR/ConstantRange.h @@ -34,11 +34,14 @@ #include "llvm/ADT/APInt.h" #include "llvm/IR/InstrTypes.h" -#include "llvm/Support/DataTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/Support/Compiler.h" +#include namespace llvm { class MDNode; +class raw_ostream; /// This class represents a range of values. class LLVM_NODISCARD ConstantRange { @@ -330,6 +333,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const ConstantRange &CR) { /// E.g. if RangeMD is !{i32 0, i32 10, i32 15, i32 20} then return [0, 20). ConstantRange getConstantRangeFromMetadata(const MDNode &RangeMD); -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_IR_CONSTANTRANGE_H diff --git a/contrib/llvm/include/llvm/IR/DerivedUser.h b/contrib/llvm/include/llvm/IR/DerivedUser.h index 4d681e0db611..67c483d3c497 100644 --- a/contrib/llvm/include/llvm/IR/DerivedUser.h +++ b/contrib/llvm/include/llvm/IR/DerivedUser.h @@ -1,4 +1,4 @@ -//===-- DerivedUser.h - Base for non-IR Users -------------------*- C++ -*-===// +//===- DerivedUser.h - Base for non-IR Users --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,6 +14,9 @@ namespace llvm { +class Type; +class Use; + /// Extension point for the Value hierarchy. All classes outside of lib/IR /// that wish to inherit from User should instead inherit from DerivedUser /// instead. Inheriting from this class is discouraged. @@ -24,10 +27,11 @@ namespace llvm { /// its use/def list machinery. class DerivedUser : public User { protected: - typedef void (*DeleteValueTy)(DerivedUser *); + using DeleteValueTy = void (*)(DerivedUser *); private: - friend Value; + friend class Value; + DeleteValueTy DeleteValue; public: @@ -36,6 +40,6 @@ class DerivedUser : public User { : User(Ty, VK, U, NumOps), DeleteValue(DeleteValue) {} }; -} // namespace llvm +} // end namespace llvm #endif // LLVM_IR_DERIVEDUSER_H diff --git a/contrib/llvm/include/llvm/IR/InstrTypes.h b/contrib/llvm/include/llvm/IR/InstrTypes.h index b3c6644c7e81..76524b412456 100644 --- a/contrib/llvm/include/llvm/IR/InstrTypes.h +++ b/contrib/llvm/include/llvm/IR/InstrTypes.h @@ -322,14 +322,14 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(UnaryInstruction, Value) //===----------------------------------------------------------------------===// class BinaryOperator : public Instruction { + void AssertOK(); + protected: BinaryOperator(BinaryOps iType, Value *S1, Value *S2, Type *Ty, const Twine &Name, Instruction *InsertBefore); BinaryOperator(BinaryOps iType, Value *S1, Value *S2, Type *Ty, const Twine &Name, BasicBlock *InsertAtEnd); - void init(BinaryOps iType); - // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; diff --git a/contrib/llvm/include/llvm/IR/Instruction.h b/contrib/llvm/include/llvm/IR/Instruction.h index 00c431834e31..d8db29e15886 100644 --- a/contrib/llvm/include/llvm/IR/Instruction.h +++ b/contrib/llvm/include/llvm/IR/Instruction.h @@ -152,9 +152,14 @@ class Instruction : public User, return getOpcode() == AShr; } + /// Determine if the Opcode is and/or/xor. + static inline bool isBitwiseLogicOp(unsigned Opcode) { + return Opcode == And || Opcode == Or || Opcode == Xor; + } + /// Return true if this is and/or/xor. inline bool isBitwiseLogicOp() const { - return getOpcode() == And || getOpcode() == Or || getOpcode() == Xor; + return isBitwiseLogicOp(getOpcode()); } /// Determine if the OpCode is one of the CastInst instructions. diff --git a/contrib/llvm/include/llvm/IR/Instructions.h b/contrib/llvm/include/llvm/IR/Instructions.h index b3032f54aa42..e1620b3e7df5 100644 --- a/contrib/llvm/include/llvm/IR/Instructions.h +++ b/contrib/llvm/include/llvm/IR/Instructions.h @@ -1243,6 +1243,16 @@ class ICmpInst: public CmpInst { /// vectors of floating point values. The operands must be identical types. /// Represents a floating point comparison operator. class FCmpInst: public CmpInst { + void AssertOK() { + assert(getPredicate() <= FCmpInst::LAST_FCMP_PREDICATE && + "Invalid FCmp predicate value"); + assert(getOperand(0)->getType() == getOperand(1)->getType() && + "Both operands to FCmp instruction are not of the same type!"); + // Check that the operands are the right type + assert(getOperand(0)->getType()->isFPOrFPVectorTy() && + "Invalid operand types for FCmp instruction"); + } + protected: // Note: Instruction needs to be a friend here to call cloneImpl. friend class Instruction; @@ -1261,13 +1271,7 @@ class FCmpInst: public CmpInst { ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::FCmp, pred, LHS, RHS, NameStr, InsertBefore) { - assert(pred <= FCmpInst::LAST_FCMP_PREDICATE && - "Invalid FCmp predicate value"); - assert(getOperand(0)->getType() == getOperand(1)->getType() && - "Both operands to FCmp instruction are not of the same type!"); - // Check that the operands are the right type - assert(getOperand(0)->getType()->isFPOrFPVectorTy() && - "Invalid operand types for FCmp instruction"); + AssertOK(); } /// Constructor with insert-at-end semantics. @@ -1280,13 +1284,7 @@ class FCmpInst: public CmpInst { ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::FCmp, pred, LHS, RHS, NameStr, &InsertAtEnd) { - assert(pred <= FCmpInst::LAST_FCMP_PREDICATE && - "Invalid FCmp predicate value"); - assert(getOperand(0)->getType() == getOperand(1)->getType() && - "Both operands to FCmp instruction are not of the same type!"); - // Check that the operands are the right type - assert(getOperand(0)->getType()->isFPOrFPVectorTy() && - "Invalid operand types for FCmp instruction"); + AssertOK(); } /// Constructor with no-insertion semantics @@ -1297,13 +1295,7 @@ class FCmpInst: public CmpInst { const Twine &NameStr = "" ///< Name of the instruction ) : CmpInst(makeCmpResultType(LHS->getType()), Instruction::FCmp, pred, LHS, RHS, NameStr) { - assert(pred <= FCmpInst::LAST_FCMP_PREDICATE && - "Invalid FCmp predicate value"); - assert(getOperand(0)->getType() == getOperand(1)->getType() && - "Both operands to FCmp instruction are not of the same type!"); - // Check that the operands are the right type - assert(getOperand(0)->getType()->isFPOrFPVectorTy() && - "Invalid operand types for FCmp instruction"); + AssertOK(); } /// @returns true if the predicate of this instruction is EQ or NE. diff --git a/contrib/llvm/include/llvm/IR/IntrinsicsAMDGPU.td b/contrib/llvm/include/llvm/IR/IntrinsicsAMDGPU.td index 8017223c4ab0..4e0529a32d29 100644 --- a/contrib/llvm/include/llvm/IR/IntrinsicsAMDGPU.td +++ b/contrib/llvm/include/llvm/IR/IntrinsicsAMDGPU.td @@ -475,6 +475,33 @@ class AMDGPUBufferStore : Intrinsic < def int_amdgcn_buffer_store_format : AMDGPUBufferStore; def int_amdgcn_buffer_store : AMDGPUBufferStore; +def int_amdgcn_tbuffer_load : Intrinsic < + [llvm_any_ty], // overloaded for types f32/i32, v2f32/v2i32, v4f32/v4i32 + [llvm_v4i32_ty, // rsrc(SGPR) + llvm_i32_ty, // vindex(VGPR) + llvm_i32_ty, // voffset(VGPR) + llvm_i32_ty, // soffset(SGPR) + llvm_i32_ty, // offset(imm) + llvm_i32_ty, // dfmt(imm) + llvm_i32_ty, // nfmt(imm) + llvm_i1_ty, // glc(imm) + llvm_i1_ty], // slc(imm) + []>; + +def int_amdgcn_tbuffer_store : Intrinsic < + [], + [llvm_any_ty, // vdata(VGPR), overloaded for types f32/i32, v2f32/v2i32, v4f32/v4i32 + llvm_v4i32_ty, // rsrc(SGPR) + llvm_i32_ty, // vindex(VGPR) + llvm_i32_ty, // voffset(VGPR) + llvm_i32_ty, // soffset(SGPR) + llvm_i32_ty, // offset(imm) + llvm_i32_ty, // dfmt(imm) + llvm_i32_ty, // nfmt(imm) + llvm_i1_ty, // glc(imm) + llvm_i1_ty], // slc(imm) + []>; + class AMDGPUBufferAtomic : Intrinsic < [llvm_i32_ty], [llvm_i32_ty, // vdata(VGPR) diff --git a/contrib/llvm/include/llvm/IR/IntrinsicsX86.td b/contrib/llvm/include/llvm/IR/IntrinsicsX86.td index 1c466e73eb1b..80c528768dc7 100644 --- a/contrib/llvm/include/llvm/IR/IntrinsicsX86.td +++ b/contrib/llvm/include/llvm/IR/IntrinsicsX86.td @@ -5420,86 +5420,6 @@ let TargetPrefix = "x86" in { def int_x86_avx512_vcomi_ss : GCCBuiltin<"__builtin_ia32_vcomiss">, Intrinsic<[llvm_i32_ty], [llvm_v4f32_ty, llvm_v4f32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_cmp_b_512: - Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i32_ty, - llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_512: - Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty, - llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_512: - Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i32_ty, - llvm_i16_ty], [IntrNoMem ]>; - def int_x86_avx512_mask_cmp_q_512: - Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_ucmp_b_512: - Intrinsic<[llvm_i64_ty], [llvm_v64i8_ty, llvm_v64i8_ty, llvm_i32_ty, - llvm_i64_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_512: - Intrinsic<[llvm_i32_ty], [llvm_v32i16_ty, llvm_v32i16_ty, llvm_i32_ty, - llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_512: - Intrinsic<[llvm_i16_ty], [llvm_v16i32_ty, llvm_v16i32_ty, llvm_i32_ty, - llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_512: - Intrinsic<[llvm_i8_ty], [llvm_v8i64_ty, llvm_v8i64_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - - // 256-bit - def int_x86_avx512_mask_cmp_b_256: - Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty, - llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_256: - Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i32_ty, - llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_256: - Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_q_256: - Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_ucmp_b_256: - Intrinsic<[llvm_i32_ty], [llvm_v32i8_ty, llvm_v32i8_ty, llvm_i32_ty, - llvm_i32_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_256: - Intrinsic<[llvm_i16_ty], [llvm_v16i16_ty, llvm_v16i16_ty, llvm_i32_ty, - llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_256: - Intrinsic<[llvm_i8_ty], [llvm_v8i32_ty, llvm_v8i32_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_256: - Intrinsic<[llvm_i8_ty], [llvm_v4i64_ty, llvm_v4i64_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - - // 128-bit - def int_x86_avx512_mask_cmp_b_128: - Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty, - llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_w_128: - Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_d_128: - Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_cmp_q_128: - Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - - def int_x86_avx512_mask_ucmp_b_128: - Intrinsic<[llvm_i16_ty], [llvm_v16i8_ty, llvm_v16i8_ty, llvm_i32_ty, - llvm_i16_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_w_128: - Intrinsic<[llvm_i8_ty], [llvm_v8i16_ty, llvm_v8i16_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_d_128: - Intrinsic<[llvm_i8_ty], [llvm_v4i32_ty, llvm_v4i32_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; - def int_x86_avx512_mask_ucmp_q_128: - Intrinsic<[llvm_i8_ty], [llvm_v2i64_ty, llvm_v2i64_ty, llvm_i32_ty, - llvm_i8_ty], [IntrNoMem]>; } // Compress, Expand diff --git a/contrib/llvm/include/llvm/IR/Metadata.h b/contrib/llvm/include/llvm/IR/Metadata.h index d538c2595393..80ed44be43eb 100644 --- a/contrib/llvm/include/llvm/IR/Metadata.h +++ b/contrib/llvm/include/llvm/IR/Metadata.h @@ -45,6 +45,8 @@ namespace llvm { class Module; class ModuleSlotTracker; +class raw_ostream; +class Type; enum LLVMConstants : uint32_t { DEBUG_METADATA_VERSION = 3 // Current debug info version number. @@ -67,8 +69,8 @@ class Metadata { unsigned char Storage; // TODO: expose remaining bits to subclasses. - unsigned short SubclassData16; - unsigned SubclassData32; + unsigned short SubclassData16 = 0; + unsigned SubclassData32 = 0; public: enum MetadataKind { @@ -78,7 +80,7 @@ class Metadata { protected: Metadata(unsigned ID, StorageType Storage) - : SubclassID(ID), Storage(Storage), SubclassData16(0), SubclassData32(0) { + : SubclassID(ID), Storage(Storage) { static_assert(sizeof(*this) == 8, "Metadata fields poorly packed"); } @@ -183,6 +185,7 @@ class MetadataAsValue : public Value { static MetadataAsValue *get(LLVMContext &Context, Metadata *MD); static MetadataAsValue *getIfExists(LLVMContext &Context, Metadata *MD); + Metadata *getMetadata() const { return MD; } static bool classof(const Value *V) { @@ -257,7 +260,7 @@ class MetadataTracking { /// \brief Check whether metadata is replaceable. static bool isReplaceable(const Metadata &MD); - typedef PointerUnion OwnerTy; + using OwnerTy = PointerUnion; private: /// \brief Track a reference to metadata for an owner. @@ -275,7 +278,7 @@ class ReplaceableMetadataImpl { friend class MetadataTracking; public: - typedef MetadataTracking::OwnerTy OwnerTy; + using OwnerTy = MetadataTracking::OwnerTy; private: LLVMContext &Context; @@ -352,17 +355,21 @@ class ValueAsMetadata : public Metadata, ReplaceableMetadataImpl { public: static ValueAsMetadata *get(Value *V); + static ConstantAsMetadata *getConstant(Value *C) { return cast(get(C)); } + static LocalAsMetadata *getLocal(Value *Local) { return cast(get(Local)); } static ValueAsMetadata *getIfExists(Value *V); + static ConstantAsMetadata *getConstantIfExists(Value *C) { return cast_or_null(getIfExists(C)); } + static LocalAsMetadata *getLocalIfExists(Value *Local) { return cast_or_null(getIfExists(Local)); } @@ -491,8 +498,8 @@ namespace detail { template T &make(); template struct HasDereference { - typedef char Yes[1]; - typedef char No[2]; + using Yes = char[1]; + using No = char[2]; template struct SFINAE {}; template @@ -613,7 +620,7 @@ class MDString : public Metadata { unsigned getLength() const { return (unsigned)getString().size(); } - typedef StringRef::iterator iterator; + using iterator = StringRef::iterator; /// \brief Pointer to the first byte of the string. iterator begin() const { return getString().begin(); } @@ -730,12 +737,14 @@ class MDOperand { }; template <> struct simplify_type { - typedef Metadata *SimpleType; + using SimpleType = Metadata *; + static SimpleType getSimplifiedValue(MDOperand &MD) { return MD.get(); } }; template <> struct simplify_type { - typedef Metadata *SimpleType; + using SimpleType = Metadata *; + static SimpleType getSimplifiedValue(const MDOperand &MD) { return MD.get(); } }; @@ -817,7 +826,7 @@ struct TempMDNodeDeleter { }; #define HANDLE_MDNODE_LEAF(CLASS) \ - typedef std::unique_ptr Temp##CLASS; + using Temp##CLASS = std::unique_ptr; #define HANDLE_MDNODE_BRANCH(CLASS) HANDLE_MDNODE_LEAF(CLASS) #include "llvm/IR/Metadata.def" @@ -847,6 +856,10 @@ class MDNode : public Metadata { ContextAndReplaceableUses Context; protected: + MDNode(LLVMContext &Context, unsigned ID, StorageType Storage, + ArrayRef Ops1, ArrayRef Ops2 = None); + ~MDNode() = default; + void *operator new(size_t Size, unsigned NumOps); void operator delete(void *Mem); @@ -860,16 +873,13 @@ class MDNode : public Metadata { llvm_unreachable("Constructor throws?"); } - MDNode(LLVMContext &Context, unsigned ID, StorageType Storage, - ArrayRef Ops1, ArrayRef Ops2 = None); - ~MDNode() = default; - void dropAllReferences(); MDOperand *mutable_begin() { return mutable_end() - NumOperands; } MDOperand *mutable_end() { return reinterpret_cast(this); } - typedef iterator_range mutable_op_range; + using mutable_op_range = iterator_range; + mutable_op_range mutable_operands() { return mutable_op_range(mutable_begin(), mutable_end()); } @@ -1028,8 +1038,8 @@ class MDNode : public Metadata { static void dispatchResetHash(NodeTy *, std::false_type) {} public: - typedef const MDOperand *op_iterator; - typedef iterator_range op_range; + using op_iterator = const MDOperand *; + using op_range = iterator_range; op_iterator op_begin() const { return const_cast(this)->mutable_begin(); @@ -1227,13 +1237,14 @@ template class MDTupleTypedArrayWrapper { T *operator[](unsigned I) const { return cast_or_null(N->getOperand(I)); } // FIXME: Fix callers and remove condition on N. - typedef TypedMDOperandIterator iterator; + using iterator = TypedMDOperandIterator; + iterator begin() const { return N ? iterator(N->op_begin()) : iterator(); } iterator end() const { return N ? iterator(N->op_end()) : iterator(); } }; #define HANDLE_METADATA(CLASS) \ - typedef MDTupleTypedArrayWrapper CLASS##Array; + using CLASS##Array = MDTupleTypedArrayWrapper; #include "llvm/IR/Metadata.def" /// Placeholder metadata for operands of distinct MDNodes. @@ -1304,12 +1315,12 @@ class NamedMDNode : public ilist_node { template class op_iterator_impl : public std::iterator { + friend class NamedMDNode; + const NamedMDNode *Node = nullptr; unsigned Idx = 0; - op_iterator_impl(const NamedMDNode *N, unsigned i) : Node(N), Idx(i) { } - - friend class NamedMDNode; + op_iterator_impl(const NamedMDNode *N, unsigned i) : Node(N), Idx(i) {} public: op_iterator_impl() = default; @@ -1371,11 +1382,13 @@ class NamedMDNode : public ilist_node { // --------------------------------------------------------------------------- // Operand Iterator interface... // - typedef op_iterator_impl op_iterator; + using op_iterator = op_iterator_impl; + op_iterator op_begin() { return op_iterator(this, 0); } op_iterator op_end() { return op_iterator(this, getNumOperands()); } - typedef op_iterator_impl const_op_iterator; + using const_op_iterator = op_iterator_impl; + const_op_iterator op_begin() const { return const_op_iterator(this, 0); } const_op_iterator op_end() const { return const_op_iterator(this, getNumOperands()); } diff --git a/contrib/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h b/contrib/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h index 8950c527cc18..5d7b8b997d37 100644 --- a/contrib/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h +++ b/contrib/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h @@ -188,7 +188,7 @@ template <> struct MappingTraits { LLVM_YAML_IS_STRING_MAP(TypeIdSummary) LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummaryYaml) -LLVM_YAML_IS_SEQUENCE_VECTOR(std::string) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(std::string) namespace llvm { namespace yaml { diff --git a/contrib/llvm/include/llvm/IR/Operator.h b/contrib/llvm/include/llvm/IR/Operator.h index 6eb5998478c6..c7f4697e93e7 100644 --- a/contrib/llvm/include/llvm/IR/Operator.h +++ b/contrib/llvm/include/llvm/IR/Operator.h @@ -328,8 +328,15 @@ class FPMathOperator : public Operator { return I->getType()->isFPOrFPVectorTy() || I->getOpcode() == Instruction::FCmp; } + + static inline bool classof(const ConstantExpr *CE) { + return CE->getType()->isFPOrFPVectorTy() || + CE->getOpcode() == Instruction::FCmp; + } + static inline bool classof(const Value *V) { - return isa(V) && classof(cast(V)); + return (isa(V) && classof(cast(V))) || + (isa(V) && classof(cast(V))); } }; diff --git a/contrib/llvm/include/llvm/IR/PatternMatch.h b/contrib/llvm/include/llvm/IR/PatternMatch.h index 015a17e8e7ca..9e9c8ac75d2a 100644 --- a/contrib/llvm/include/llvm/IR/PatternMatch.h +++ b/contrib/llvm/include/llvm/IR/PatternMatch.h @@ -167,10 +167,8 @@ inline match_combine_or m_AnyZero() { struct match_nan { template bool match(ITy *V) { - if (const auto *C = dyn_cast(V)) { - const APFloat &APF = C->getValueAPF(); - return APF.isNaN(); - } + if (const auto *C = dyn_cast(V)) + return C->isNaN(); return false; } }; @@ -419,7 +417,8 @@ inline bind_const_intval_ty m_ConstantInt(uint64_t &V) { return V; } //===----------------------------------------------------------------------===// // Matcher for any binary operator. // -template struct AnyBinaryOp_match { +template +struct AnyBinaryOp_match { LHS_t L; RHS_t R; @@ -427,7 +426,9 @@ template struct AnyBinaryOp_match { template bool match(OpTy *V) { if (auto *I = dyn_cast(V)) - return L.match(I->getOperand(0)) && R.match(I->getOperand(1)); + return (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) || + (Commutable && R.match(I->getOperand(0)) && + L.match(I->getOperand(1))); return false; } }; @@ -441,7 +442,8 @@ inline AnyBinaryOp_match m_BinOp(const LHS &L, const RHS &R) { // Matchers for specific binary operators. // -template +template struct BinaryOp_match { LHS_t L; RHS_t R; @@ -451,11 +453,15 @@ struct BinaryOp_match { template bool match(OpTy *V) { if (V->getValueID() == Value::InstructionVal + Opcode) { auto *I = cast(V); - return L.match(I->getOperand(0)) && R.match(I->getOperand(1)); + return (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) || + (Commutable && R.match(I->getOperand(0)) && + L.match(I->getOperand(1))); } if (auto *CE = dyn_cast(V)) - return CE->getOpcode() == Opcode && L.match(CE->getOperand(0)) && - R.match(CE->getOperand(1)); + return CE->getOpcode() == Opcode && + ((L.match(CE->getOperand(0)) && R.match(CE->getOperand(1))) || + (Commutable && R.match(CE->getOperand(0)) && + L.match(CE->getOperand(1)))); return false; } }; @@ -660,47 +666,87 @@ m_NUWShl(const LHS &L, const RHS &R) { } //===----------------------------------------------------------------------===// -// Class that matches two different binary ops. +// Class that matches a group of binary opcodes. // -template -struct BinOp2_match { +template +struct BinOpPred_match : Predicate { LHS_t L; RHS_t R; - BinOp2_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} + BinOpPred_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template bool match(OpTy *V) { - if (V->getValueID() == Value::InstructionVal + Opc1 || - V->getValueID() == Value::InstructionVal + Opc2) { - auto *I = cast(V); - return L.match(I->getOperand(0)) && R.match(I->getOperand(1)); - } + if (auto *I = dyn_cast(V)) + return this->isOpType(I->getOpcode()) && L.match(I->getOperand(0)) && + R.match(I->getOperand(1)); if (auto *CE = dyn_cast(V)) - return (CE->getOpcode() == Opc1 || CE->getOpcode() == Opc2) && - L.match(CE->getOperand(0)) && R.match(CE->getOperand(1)); + return this->isOpType(CE->getOpcode()) && L.match(CE->getOperand(0)) && + R.match(CE->getOperand(1)); return false; } }; -/// \brief Matches LShr or AShr. +struct is_shift_op { + bool isOpType(unsigned Opcode) { return Instruction::isShift(Opcode); } +}; + +struct is_right_shift_op { + bool isOpType(unsigned Opcode) { + return Opcode == Instruction::LShr || Opcode == Instruction::AShr; + } +}; + +struct is_logical_shift_op { + bool isOpType(unsigned Opcode) { + return Opcode == Instruction::LShr || Opcode == Instruction::Shl; + } +}; + +struct is_bitwiselogic_op { + bool isOpType(unsigned Opcode) { + return Instruction::isBitwiseLogicOp(Opcode); + } +}; + +struct is_idiv_op { + bool isOpType(unsigned Opcode) { + return Opcode == Instruction::SDiv || Opcode == Instruction::UDiv; + } +}; + +/// \brief Matches shift operations. template -inline BinOp2_match -m_Shr(const LHS &L, const RHS &R) { - return BinOp2_match(L, R); +inline BinOpPred_match m_Shift(const LHS &L, + const RHS &R) { + return BinOpPred_match(L, R); } -/// \brief Matches LShr or Shl. +/// \brief Matches logical shift operations. template -inline BinOp2_match +inline BinOpPred_match m_Shr(const LHS &L, + const RHS &R) { + return BinOpPred_match(L, R); +} + +/// \brief Matches logical shift operations. +template +inline BinOpPred_match m_LogicalShift(const LHS &L, const RHS &R) { - return BinOp2_match(L, R); + return BinOpPred_match(L, R); } -/// \brief Matches UDiv and SDiv. +/// \brief Matches bitwise logic operations. template -inline BinOp2_match -m_IDiv(const LHS &L, const RHS &R) { - return BinOp2_match(L, R); +inline BinOpPred_match +m_BitwiseLogic(const LHS &L, const RHS &R) { + return BinOpPred_match(L, R); +} + +/// \brief Matches integer division operations. +template +inline BinOpPred_match m_IDiv(const LHS &L, + const RHS &R) { + return BinOpPred_match(L, R); } //===----------------------------------------------------------------------===// @@ -726,7 +772,8 @@ template inline Exact_match m_Exact(const T &SubPattern) { // Matchers for CmpInst classes // -template +template struct CmpClass_match { PredicateTy &Predicate; LHS_t L; @@ -737,7 +784,9 @@ struct CmpClass_match { template bool match(OpTy *V) { if (auto *I = dyn_cast(V)) - if (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) { + if ((L.match(I->getOperand(0)) && R.match(I->getOperand(1))) || + (Commutable && R.match(I->getOperand(0)) && + L.match(I->getOperand(1)))) { Predicate = I->getPredicate(); return true; } @@ -897,10 +946,7 @@ template struct not_match { private: bool isAllOnes(Value *V) { - return (isa(V) || isa(V) || - // FIXME: Remove CV. - isa(V)) && - cast(V)->isAllOnesValue(); + return isa(V) && cast(V)->isAllOnesValue(); } }; @@ -1002,7 +1048,8 @@ inline brc_match m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F) { // Matchers for max/min idioms, eg: "select (sgt x, y), x, y" -> smax(x,y). // -template +template struct MaxMin_match { LHS_t L; RHS_t R; @@ -1032,7 +1079,8 @@ struct MaxMin_match { if (!Pred_t::match(Pred)) return false; // It does! Bind the operands. - return L.match(LHS) && R.match(RHS); + return (L.match(LHS) && R.match(RHS)) || + (Commutable && R.match(LHS) && L.match(RHS)); } }; @@ -1376,89 +1424,78 @@ template inline Signum_match m_Signum(const Val_t &V) { // /// \brief Matches a BinaryOperator with LHS and RHS in either order. -template -inline match_combine_or, - AnyBinaryOp_match> -m_c_BinOp(const LHS &L, const RHS &R) { - return m_CombineOr(m_BinOp(L, R), m_BinOp(R, L)); +template +inline AnyBinaryOp_match m_c_BinOp(const LHS &L, const RHS &R) { + return AnyBinaryOp_match(L, R); } /// \brief Matches an ICmp with a predicate over LHS and RHS in either order. /// Does not swap the predicate. -template -inline match_combine_or, - CmpClass_match> +template +inline CmpClass_match m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) { - return m_CombineOr(m_ICmp(Pred, L, R), m_ICmp(Pred, R, L)); + return CmpClass_match(Pred, L, + R); } /// \brief Matches a Add with LHS and RHS in either order. -template -inline match_combine_or, - BinaryOp_match> -m_c_Add(const LHS &L, const RHS &R) { - return m_CombineOr(m_Add(L, R), m_Add(R, L)); +template +inline BinaryOp_match m_c_Add(const LHS &L, + const RHS &R) { + return BinaryOp_match(L, R); } /// \brief Matches a Mul with LHS and RHS in either order. -template -inline match_combine_or, - BinaryOp_match> -m_c_Mul(const LHS &L, const RHS &R) { - return m_CombineOr(m_Mul(L, R), m_Mul(R, L)); +template +inline BinaryOp_match m_c_Mul(const LHS &L, + const RHS &R) { + return BinaryOp_match(L, R); } /// \brief Matches an And with LHS and RHS in either order. -template -inline match_combine_or, - BinaryOp_match> -m_c_And(const LHS &L, const RHS &R) { - return m_CombineOr(m_And(L, R), m_And(R, L)); +template +inline BinaryOp_match m_c_And(const LHS &L, + const RHS &R) { + return BinaryOp_match(L, R); } /// \brief Matches an Or with LHS and RHS in either order. -template -inline match_combine_or, - BinaryOp_match> -m_c_Or(const LHS &L, const RHS &R) { - return m_CombineOr(m_Or(L, R), m_Or(R, L)); +template +inline BinaryOp_match m_c_Or(const LHS &L, + const RHS &R) { + return BinaryOp_match(L, R); } /// \brief Matches an Xor with LHS and RHS in either order. -template -inline match_combine_or, - BinaryOp_match> -m_c_Xor(const LHS &L, const RHS &R) { - return m_CombineOr(m_Xor(L, R), m_Xor(R, L)); +template +inline BinaryOp_match m_c_Xor(const LHS &L, + const RHS &R) { + return BinaryOp_match(L, R); } /// Matches an SMin with LHS and RHS in either order. template -inline match_combine_or, - MaxMin_match> +inline MaxMin_match m_c_SMin(const LHS &L, const RHS &R) { - return m_CombineOr(m_SMin(L, R), m_SMin(R, L)); + return MaxMin_match(L, R); } /// Matches an SMax with LHS and RHS in either order. template -inline match_combine_or, - MaxMin_match> +inline MaxMin_match m_c_SMax(const LHS &L, const RHS &R) { - return m_CombineOr(m_SMax(L, R), m_SMax(R, L)); + return MaxMin_match(L, R); } /// Matches a UMin with LHS and RHS in either order. template -inline match_combine_or, - MaxMin_match> +inline MaxMin_match m_c_UMin(const LHS &L, const RHS &R) { - return m_CombineOr(m_UMin(L, R), m_UMin(R, L)); + return MaxMin_match(L, R); } /// Matches a UMax with LHS and RHS in either order. template -inline match_combine_or, - MaxMin_match> +inline MaxMin_match m_c_UMax(const LHS &L, const RHS &R) { - return m_CombineOr(m_UMax(L, R), m_UMax(R, L)); + return MaxMin_match(L, R); } } // end namespace PatternMatch diff --git a/contrib/llvm/include/llvm/IR/Statepoint.h b/contrib/llvm/include/llvm/IR/Statepoint.h index 265e7eb348bf..630f30667272 100644 --- a/contrib/llvm/include/llvm/IR/Statepoint.h +++ b/contrib/llvm/include/llvm/IR/Statepoint.h @@ -62,7 +62,10 @@ bool isStatepoint(const Value *V); bool isStatepoint(const Value &V); bool isGCRelocate(ImmutableCallSite CS); +bool isGCRelocate(const Value *V); + bool isGCResult(ImmutableCallSite CS); +bool isGCResult(const Value *V); /// Analogous to CallSiteBase, this provides most of the actual /// functionality for Statepoint and ImmutableStatepoint. It is diff --git a/contrib/llvm/include/llvm/IR/Value.h b/contrib/llvm/include/llvm/IR/Value.h index ccd40e576584..9e4914973edf 100644 --- a/contrib/llvm/include/llvm/IR/Value.h +++ b/contrib/llvm/include/llvm/IR/Value.h @@ -49,8 +49,9 @@ template class StringMapEntry; class StringRef; class Twine; class Type; +class User; -using ValueName = StringMapEntry; +using ValueName = StringMapEntry; //===----------------------------------------------------------------------===// // Value Class @@ -212,7 +213,7 @@ class Value { public: Value(const Value &) = delete; - void operator=(const Value &) = delete; + Value &operator=(const Value &) = delete; /// Delete a pointer to a generic Value. void deleteValue(); @@ -660,7 +661,7 @@ struct ValueDeleter { void operator()(Value *V) { V->deleteValue(); } }; /// Use this instead of std::unique_ptr or std::unique_ptr. /// Those don't work because Value and Instruction's destructors are protected, /// aren't virtual, and won't destroy the complete object. -typedef std::unique_ptr unique_value; +using unique_value = std::unique_ptr; inline raw_ostream &operator<<(raw_ostream &OS, const Value &V) { V.print(OS); diff --git a/contrib/llvm/include/llvm/InitializePasses.h b/contrib/llvm/include/llvm/InitializePasses.h index abb0aa3e3caf..a52fa3b542a5 100644 --- a/contrib/llvm/include/llvm/InitializePasses.h +++ b/contrib/llvm/include/llvm/InitializePasses.h @@ -192,7 +192,6 @@ void initializeLiveRangeShrinkPass(PassRegistry&); void initializeLiveRegMatrixPass(PassRegistry&); void initializeLiveStacksPass(PassRegistry&); void initializeLiveVariablesPass(PassRegistry&); -void initializeLoadCombinePass(PassRegistry&); void initializeLoadStoreVectorizerPass(PassRegistry&); void initializeLoaderPassPass(PassRegistry&); void initializeLocalStackSlotPassPass(PassRegistry&); diff --git a/contrib/llvm/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h b/contrib/llvm/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h index f9545333aabd..14f0c48266f0 100644 --- a/contrib/llvm/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h +++ b/contrib/llvm/include/llvm/LTO/legacy/ThinLTOCodeGenerator.h @@ -177,7 +177,7 @@ class ThinLTOCodeGenerator { */ void setMaxCacheSizeRelativeToAvailableSpace(unsigned Percentage) { if (Percentage) - CacheOptions.Policy.PercentageOfAvailableSpace = Percentage; + CacheOptions.Policy.MaxSizePercentageOfAvailableSpace = Percentage; } /**@}*/ diff --git a/contrib/llvm/include/llvm/MC/MCAsmBackend.h b/contrib/llvm/include/llvm/MC/MCAsmBackend.h index fb21e195b1df..a270973204f2 100644 --- a/contrib/llvm/include/llvm/MC/MCAsmBackend.h +++ b/contrib/llvm/include/llvm/MC/MCAsmBackend.h @@ -63,19 +63,16 @@ class MCAsmBackend { /// Target hook to adjust the literal value of a fixup if necessary. /// IsResolved signals whether the caller believes a relocation is needed; the /// target can modify the value. The default does nothing. - virtual void processFixupValue(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFixup &Fixup, const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) {} + virtual void processFixupValue(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, bool &IsResolved) {} /// Apply the \p Value for given \p Fixup into the provided data fragment, at /// the offset specified by the fixup and following the fixup kind as /// appropriate. Errors (such as an out of range fixup value) should be /// reported via \p Ctx. - virtual void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, - MCContext &Ctx) const = 0; + virtual void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const = 0; /// @} diff --git a/contrib/llvm/include/llvm/MC/MCAssembler.h b/contrib/llvm/include/llvm/MC/MCAssembler.h index 63f7057a7076..4f1b5a8b3d72 100644 --- a/contrib/llvm/include/llvm/MC/MCAssembler.h +++ b/contrib/llvm/include/llvm/MC/MCAssembler.h @@ -195,8 +195,8 @@ class MCAssembler { /// finishLayout - Finalize a layout, including fragment lowering. void finishLayout(MCAsmLayout &Layout); - std::pair handleFixup(const MCAsmLayout &Layout, - MCFragment &F, const MCFixup &Fixup); + std::tuple + handleFixup(const MCAsmLayout &Layout, MCFragment &F, const MCFixup &Fixup); public: /// Construct a new assembler instance. @@ -413,7 +413,7 @@ class MCAssembler { /// @} - void dump(); + void dump() const; }; /// \brief Compute the amount of padding required before the fragment \p F to diff --git a/contrib/llvm/include/llvm/MC/MCFragment.h b/contrib/llvm/include/llvm/MC/MCFragment.h index 0aca922e3cf5..284ca50e19d5 100644 --- a/contrib/llvm/include/llvm/MC/MCFragment.h +++ b/contrib/llvm/include/llvm/MC/MCFragment.h @@ -130,7 +130,7 @@ class MCFragment : public ilist_node_with_parent { /// \brief Return true if given frgment has FT_Dummy type. bool isDummy() const { return Kind == FT_Dummy; } - void dump(); + void dump() const; }; class MCDummyFragment : public MCFragment { diff --git a/contrib/llvm/include/llvm/MC/MCSection.h b/contrib/llvm/include/llvm/MC/MCSection.h index cc306d47250d..2771b1e67eab 100644 --- a/contrib/llvm/include/llvm/MC/MCSection.h +++ b/contrib/llvm/include/llvm/MC/MCSection.h @@ -167,7 +167,7 @@ class MCSection { MCSection::iterator getSubsectionInsertionPoint(unsigned Subsection); - void dump(); + void dump() const; virtual void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, diff --git a/contrib/llvm/include/llvm/MC/MCSymbolWasm.h b/contrib/llvm/include/llvm/MC/MCSymbolWasm.h index 1b87095552d6..7ea89629efda 100644 --- a/contrib/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/contrib/llvm/include/llvm/MC/MCSymbolWasm.h @@ -17,6 +17,7 @@ namespace llvm { class MCSymbolWasm : public MCSymbol { private: bool IsFunction = false; + bool IsWeak = false; std::string ModuleName; SmallVector Returns; SmallVector Params; @@ -39,6 +40,9 @@ class MCSymbolWasm : public MCSymbol { bool isFunction() const { return IsFunction; } void setIsFunction(bool isFunc) { IsFunction = isFunc; } + bool isWeak() const { return IsWeak; } + void setWeak(bool isWeak) { IsWeak = isWeak; } + const StringRef getModuleName() const { return ModuleName; } const SmallVector &getReturns() const { return Returns; } diff --git a/contrib/llvm/include/llvm/MC/MCValue.h b/contrib/llvm/include/llvm/MC/MCValue.h index ead08fd90ca0..aa1eaf022c55 100644 --- a/contrib/llvm/include/llvm/MC/MCValue.h +++ b/contrib/llvm/include/llvm/MC/MCValue.h @@ -42,7 +42,7 @@ class MCValue { int64_t Cst; uint32_t RefKind; public: - + MCValue() : SymA(nullptr), SymB(nullptr), Cst(0), RefKind(0) {} int64_t getConstant() const { return Cst; } const MCSymbolRefExpr *getSymA() const { return SymA; } const MCSymbolRefExpr *getSymB() const { return SymB; } diff --git a/contrib/llvm/include/llvm/MC/MCWinCOFFObjectWriter.h b/contrib/llvm/include/llvm/MC/MCWinCOFFObjectWriter.h index 57bed213aad4..6e14cefaa0ab 100644 --- a/contrib/llvm/include/llvm/MC/MCWinCOFFObjectWriter.h +++ b/contrib/llvm/include/llvm/MC/MCWinCOFFObjectWriter.h @@ -30,8 +30,8 @@ class raw_pwrite_stream; virtual ~MCWinCOFFObjectTargetWriter() = default; unsigned getMachine() const { return Machine; } - virtual unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, - bool IsCrossSection, + virtual unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsCrossSection, const MCAsmBackend &MAB) const = 0; virtual bool recordRelocation(const MCFixup &) const { return true; } }; diff --git a/contrib/llvm/include/llvm/Object/COFF.h b/contrib/llvm/include/llvm/Object/COFF.h index ae695a529597..bf0172822d3f 100644 --- a/contrib/llvm/include/llvm/Object/COFF.h +++ b/contrib/llvm/include/llvm/Object/COFF.h @@ -562,8 +562,26 @@ struct coff_tls_directory { using coff_tls_directory32 = coff_tls_directory; using coff_tls_directory64 = coff_tls_directory; +/// Bits in control flow guard flags as we understand them. +enum class coff_guard_flags : uint32_t { + CFInstrumented = 0x00000100, + HasFidTable = 0x00000400, + ProtectDelayLoadIAT = 0x00001000, + DelayLoadIATSection = 0x00002000, // Delay load in separate section + HasLongJmpTable = 0x00010000, + FidTableHasFlags = 0x10000000, // Indicates that fid tables are 5 bytes +}; + +struct coff_load_config_code_integrity { + support::ulittle16_t Flags; + support::ulittle16_t Catalog; + support::ulittle32_t CatalogOffset; + support::ulittle32_t Reserved; +}; + +/// 32-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY32) struct coff_load_configuration32 { - support::ulittle32_t Characteristics; + support::ulittle32_t Size; support::ulittle32_t TimeDateStamp; support::ulittle16_t MajorVersion; support::ulittle16_t MinorVersion; @@ -578,34 +596,81 @@ struct coff_load_configuration32 { support::ulittle32_t ProcessAffinityMask; support::ulittle32_t ProcessHeapFlags; support::ulittle16_t CSDVersion; - support::ulittle16_t Reserved; + support::ulittle16_t DependentLoadFlags; support::ulittle32_t EditList; support::ulittle32_t SecurityCookie; support::ulittle32_t SEHandlerTable; support::ulittle32_t SEHandlerCount; + + // Added in MSVC 2015 for /guard:cf. + support::ulittle32_t GuardCFCheckFunction; + support::ulittle32_t GuardCFCheckDispatch; + support::ulittle32_t GuardCFFunctionTable; + support::ulittle32_t GuardCFFunctionCount; + support::ulittle32_t GuardFlags; // coff_guard_flags + + // Added in MSVC 2017 + coff_load_config_code_integrity CodeIntegrity; + support::ulittle32_t GuardAddressTakenIatEntryTable; + support::ulittle32_t GuardAddressTakenIatEntryCount; + support::ulittle32_t GuardLongJumpTargetTable; + support::ulittle32_t GuardLongJumpTargetCount; + support::ulittle32_t DynamicValueRelocTable; + support::ulittle32_t CHPEMetadataPointer; + support::ulittle32_t GuardRFFailureRoutine; + support::ulittle32_t GuardRFFailureRoutineFunctionPointer; + support::ulittle32_t DynamicValueRelocTableOffset; + support::ulittle16_t DynamicValueRelocTableSection; + support::ulittle16_t Reserved2; + support::ulittle32_t GuardRFVerifyStackPointerFunctionPointer; + support::ulittle32_t HotPatchTableOffset; }; +/// 64-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY64) struct coff_load_configuration64 { - support::ulittle32_t Characteristics; + support::ulittle32_t Size; support::ulittle32_t TimeDateStamp; support::ulittle16_t MajorVersion; support::ulittle16_t MinorVersion; support::ulittle32_t GlobalFlagsClear; support::ulittle32_t GlobalFlagsSet; support::ulittle32_t CriticalSectionDefaultTimeout; - support::ulittle32_t DeCommitFreeBlockThreshold; - support::ulittle32_t DeCommitTotalFreeThreshold; - support::ulittle32_t LockPrefixTable; - support::ulittle32_t MaximumAllocationSize; - support::ulittle32_t VirtualMemoryThreshold; - support::ulittle32_t ProcessAffinityMask; + support::ulittle64_t DeCommitFreeBlockThreshold; + support::ulittle64_t DeCommitTotalFreeThreshold; + support::ulittle64_t LockPrefixTable; + support::ulittle64_t MaximumAllocationSize; + support::ulittle64_t VirtualMemoryThreshold; + support::ulittle64_t ProcessAffinityMask; support::ulittle32_t ProcessHeapFlags; support::ulittle16_t CSDVersion; - support::ulittle16_t Reserved; - support::ulittle32_t EditList; + support::ulittle16_t DependentLoadFlags; + support::ulittle64_t EditList; support::ulittle64_t SecurityCookie; support::ulittle64_t SEHandlerTable; support::ulittle64_t SEHandlerCount; + + // Added in MSVC 2015 for /guard:cf. + support::ulittle64_t GuardCFCheckFunction; + support::ulittle64_t GuardCFCheckDispatch; + support::ulittle64_t GuardCFFunctionTable; + support::ulittle64_t GuardCFFunctionCount; + support::ulittle32_t GuardFlags; + + // Added in MSVC 2017 + coff_load_config_code_integrity CodeIntegrity; + support::ulittle64_t GuardAddressTakenIatEntryTable; + support::ulittle64_t GuardAddressTakenIatEntryCount; + support::ulittle64_t GuardLongJumpTargetTable; + support::ulittle64_t GuardLongJumpTargetCount; + support::ulittle64_t DynamicValueRelocTable; + support::ulittle64_t CHPEMetadataPointer; + support::ulittle64_t GuardRFFailureRoutine; + support::ulittle64_t GuardRFFailureRoutineFunctionPointer; + support::ulittle32_t DynamicValueRelocTableOffset; + support::ulittle16_t DynamicValueRelocTableSection; + support::ulittle16_t Reserved2; + support::ulittle64_t GuardRFVerifyStackPointerFunctionPointer; + support::ulittle32_t HotPatchTableOffset; }; struct coff_runtime_function_x64 { @@ -684,6 +749,8 @@ class COFFObjectFile : public ObjectFile { const coff_base_reloc_block_header *BaseRelocEnd; const debug_directory *DebugDirectoryBegin; const debug_directory *DebugDirectoryEnd; + // Either coff_load_configuration32 or coff_load_configuration64. + const void *LoadConfig; std::error_code getString(uint32_t offset, StringRef &Res) const; @@ -698,6 +765,7 @@ class COFFObjectFile : public ObjectFile { std::error_code initExportTablePtr(); std::error_code initBaseRelocPtr(); std::error_code initDebugDirectoryPtr(); + std::error_code initLoadConfigPtr(); public: uintptr_t getSymbolTable() const { @@ -775,6 +843,16 @@ class COFFObjectFile : public ObjectFile { return getRawNumberOfSymbols(); } + const coff_load_configuration32 *getLoadConfig32() const { + assert(!is64()); + return reinterpret_cast(LoadConfig); + } + + const coff_load_configuration64 *getLoadConfig64() const { + assert(is64()); + return reinterpret_cast(LoadConfig); + } + protected: void moveSymbolNext(DataRefImpl &Symb) const override; Expected getSymbolName(DataRefImpl Symb) const override; diff --git a/contrib/llvm/include/llvm/Object/IRSymtab.h b/contrib/llvm/include/llvm/Object/IRSymtab.h index 5b832141a865..502f133d307d 100644 --- a/contrib/llvm/include/llvm/Object/IRSymtab.h +++ b/contrib/llvm/include/llvm/Object/IRSymtab.h @@ -38,6 +38,7 @@ namespace llvm { struct BitcodeFileContents; +class StringTableBuilder; namespace irsymtab { @@ -136,9 +137,10 @@ struct Header { } // end namespace storage -/// Fills in Symtab and Strtab with a valid symbol and string table for Mods. +/// Fills in Symtab and StrtabBuilder with a valid symbol and string table for +/// Mods. Error build(ArrayRef Mods, SmallVector &Symtab, - SmallVector &Strtab); + StringTableBuilder &StrtabBuilder, BumpPtrAllocator &Alloc); /// This represents a symbol that has been read from a storage::Symbol and /// possibly a storage::Uncommon. diff --git a/contrib/llvm/include/llvm/Object/MachO.h b/contrib/llvm/include/llvm/Object/MachO.h index 3fc726f4ccb8..2c3c89d10546 100644 --- a/contrib/llvm/include/llvm/Object/MachO.h +++ b/contrib/llvm/include/llvm/Object/MachO.h @@ -304,6 +304,12 @@ class MachOObjectFile : public ObjectFile { relocation_iterator section_rel_begin(DataRefImpl Sec) const override; relocation_iterator section_rel_end(DataRefImpl Sec) const override; + relocation_iterator extrel_begin() const; + relocation_iterator extrel_end() const; + iterator_range external_relocations() const { + return make_range(extrel_begin(), extrel_end()); + } + void moveRelocationNext(DataRefImpl &Rel) const override; uint64_t getRelocationOffset(DataRefImpl Rel) const override; symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; diff --git a/contrib/llvm/include/llvm/Object/Wasm.h b/contrib/llvm/include/llvm/Object/Wasm.h index 10edc461b9e9..9d53131234f4 100644 --- a/contrib/llvm/include/llvm/Object/Wasm.h +++ b/contrib/llvm/include/llvm/Object/Wasm.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" @@ -48,7 +49,24 @@ class WasmSymbol { StringRef Name; SymbolType Type; uint32_t Section; + uint32_t Flags = 0; + + // Index into the imports, exports or functions array of the object depending + // on the type uint32_t ElementIndex; + + bool isWeak() const { + return Flags & wasm::WASM_SYMBOL_FLAG_WEAK; + } + + void print(raw_ostream &Out) const { + Out << "Name=" << Name << ", Type=" << static_cast(Type) + << ", Flags=" << Flags; + } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { print(dbgs()); } +#endif }; class WasmSection { @@ -63,6 +81,7 @@ class WasmSection { }; class WasmObjectFile : public ObjectFile { + public: WasmObjectFile(MemoryBufferRef Object, Error &Err); @@ -176,6 +195,7 @@ class WasmObjectFile : public ObjectFile { // Custom section types Error parseNameSection(const uint8_t *Ptr, const uint8_t *End); + Error parseLinkingSection(const uint8_t *Ptr, const uint8_t *End); Error parseRelocSection(StringRef Name, const uint8_t *Ptr, const uint8_t *End); @@ -190,13 +210,22 @@ class WasmObjectFile : public ObjectFile { std::vector Exports; std::vector ElemSegments; std::vector DataSegments; - std::vector Symbols; std::vector Functions; + std::vector Symbols; ArrayRef CodeSection; uint32_t StartFunction = -1; + + StringMap SymbolMap; }; } // end namespace object + +inline raw_ostream &operator<<(raw_ostream &OS, + const object::WasmSymbol &Sym) { + Sym.print(OS); + return OS; +} + } // end namespace llvm #endif // LLVM_OBJECT_WASM_H diff --git a/contrib/llvm/include/llvm/Object/WindowsResource.h b/contrib/llvm/include/llvm/Object/WindowsResource.h index 4839013c8228..3d32409fd4ac 100644 --- a/contrib/llvm/include/llvm/Object/WindowsResource.h +++ b/contrib/llvm/include/llvm/Object/WindowsResource.h @@ -30,7 +30,6 @@ #define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/Binary.h" #include "llvm/Object/Error.h" @@ -44,14 +43,47 @@ #include namespace llvm { - -class FileOutputBuffer; - namespace object { class WindowsResource; -enum class Machine { UNKNOWN, ARM, X64, X86 }; +const size_t WIN_RES_MAGIC_SIZE = 16; +const size_t WIN_RES_NULL_ENTRY_SIZE = 16; +const uint32_t WIN_RES_HEADER_ALIGNMENT = 4; +const uint32_t WIN_RES_DATA_ALIGNMENT = 4; +const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030; + +struct WinResHeaderPrefix { + support::ulittle32_t DataSize; + support::ulittle32_t HeaderSize; +}; + +// Type and Name may each either be an integer ID or a string. This struct is +// only used in the case where they are both IDs. +struct WinResIDs { + uint16_t TypeFlag; + support::ulittle16_t TypeID; + uint16_t NameFlag; + support::ulittle16_t NameID; + + void setType(uint16_t ID) { + TypeFlag = 0xffff; + TypeID = ID; + } + + void setName(uint16_t ID) { + NameFlag = 0xffff; + NameID = ID; + } +}; + +struct WinResHeaderSuffix { + support::ulittle32_t DataVersion; + support::ulittle16_t MemoryFlags; + support::ulittle16_t Language; + support::ulittle32_t Version; + support::ulittle32_t Characteristics; +}; class ResourceEntryRef { public: @@ -76,14 +108,6 @@ class ResourceEntryRef { Error loadNext(); - struct HeaderSuffix { - support::ulittle32_t DataVersion; - support::ulittle16_t MemoryFlags; - support::ulittle16_t Language; - support::ulittle32_t Version; - support::ulittle32_t Characteristics; - }; - BinaryStreamReader Reader; bool IsStringType; ArrayRef Type; @@ -91,7 +115,7 @@ class ResourceEntryRef { bool IsStringName; ArrayRef Name; uint16_t NameID; - const HeaderSuffix *Suffix = nullptr; + const WinResHeaderSuffix *Suffix = nullptr; ArrayRef Data; const WindowsResource *OwningRes = nullptr; }; @@ -185,8 +209,9 @@ class WindowsResourceParser { std::vector> StringTable; }; -Error writeWindowsResourceCOFF(StringRef OutputFile, Machine MachineType, - const WindowsResourceParser &Parser); +Expected> +writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, + const WindowsResourceParser &Parser); } // namespace object } // namespace llvm diff --git a/contrib/llvm/include/llvm/ObjectYAML/WasmYAML.h b/contrib/llvm/include/llvm/ObjectYAML/WasmYAML.h index 447dbd7a603d..74f5664c43ac 100644 --- a/contrib/llvm/include/llvm/ObjectYAML/WasmYAML.h +++ b/contrib/llvm/include/llvm/ObjectYAML/WasmYAML.h @@ -112,8 +112,13 @@ struct Signature { ValueType ReturnType; }; +struct SymbolInfo { + StringRef Name; + uint32_t Flags; +}; + struct Section { - Section(SectionType SecType) : Type(SecType) {} + explicit Section(SectionType SecType) : Type(SecType) {} virtual ~Section(); SectionType Type; @@ -121,20 +126,36 @@ struct Section { }; struct CustomSection : Section { - CustomSection() : Section(wasm::WASM_SEC_CUSTOM) {} + explicit CustomSection(StringRef Name) + : Section(wasm::WASM_SEC_CUSTOM), Name(Name) {} static bool classof(const Section *S) { return S->Type == wasm::WASM_SEC_CUSTOM; } StringRef Name; yaml::BinaryRef Payload; +}; + +struct NameSection : CustomSection { + NameSection() : CustomSection("name") {} + static bool classof(const Section *S) { + auto C = dyn_cast(S); + return C && C->Name == "name"; + } - // The follow is used by the "name" custom section. - // TODO(sbc): Add support for more then just functions names. The wasm - // name section can support multiple sub-sections. std::vector FunctionNames; }; +struct LinkingSection : CustomSection { + LinkingSection() : CustomSection("linking") {} + static bool classof(const Section *S) { + auto C = dyn_cast(S); + return C && C->Name == "linking"; + } + + std::vector SymbolInfos; +}; + struct TypeSection : Section { TypeSection() : Section(wasm::WASM_SEC_TYPE) {} static bool classof(const Section *S) { @@ -256,6 +277,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Function) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::LocalDecl) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Relocation) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::NameEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo) LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) namespace llvm { @@ -329,6 +351,10 @@ template <> struct MappingTraits { static void mapping(IO &IO, WasmYAML::ElemSegment &Segment); }; +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::SymbolInfo &Info); +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, WasmYAML::ValueType &Type); }; diff --git a/contrib/llvm/include/llvm/Option/OptParser.td b/contrib/llvm/include/llvm/Option/OptParser.td index 4da86f09750d..481223698719 100644 --- a/contrib/llvm/include/llvm/Option/OptParser.td +++ b/contrib/llvm/include/llvm/Option/OptParser.td @@ -92,6 +92,7 @@ class Option prefixes, string name, OptionKind kind> { int NumArgs = 0; string HelpText = ?; string MetaVarName = ?; + string Values = ?; list Flags = []; OptionGroup Group = ?; Option Alias = ?; @@ -126,6 +127,7 @@ class Flags flags> { list Flags = flags; } class Group { OptionGroup Group = group; } class HelpText { string HelpText = text; } class MetaVarName { string MetaVarName = name; } +class Values { string Values = value; } // Predefined options. diff --git a/contrib/llvm/include/llvm/Option/OptTable.h b/contrib/llvm/include/llvm/Option/OptTable.h index e0169b927319..3e7b019a0d4e 100644 --- a/contrib/llvm/include/llvm/Option/OptTable.h +++ b/contrib/llvm/include/llvm/Option/OptTable.h @@ -53,6 +53,7 @@ class OptTable { unsigned short GroupID; unsigned short AliasID; const char *AliasArgs; + const char *Values; }; private: @@ -120,6 +121,19 @@ class OptTable { return getInfo(id).MetaVar; } + /// Find possible value for given flags. This is used for shell + /// autocompletion. + /// + /// \param [in] Option - Key flag like "-stdlib=" when "-stdlib=l" + /// was passed to clang. + /// + /// \param [in] Arg - Value which we want to autocomplete like "l" + /// when "-stdlib=l" was passed to clang. + /// + /// \return The vector of possible values. + std::vector suggestValueCompletions(StringRef Option, + StringRef Arg) const; + /// Find flags from OptTable which starts with Cur. /// /// \param [in] Cur - String prefix that all returned flags need diff --git a/contrib/llvm/include/llvm/Option/Option.h b/contrib/llvm/include/llvm/Option/Option.h index c08834f90598..d9aebd5b0757 100644 --- a/contrib/llvm/include/llvm/Option/Option.h +++ b/contrib/llvm/include/llvm/Option/Option.h @@ -57,6 +57,7 @@ class Option { UnknownClass, FlagClass, JoinedClass, + ValuesClass, SeparateClass, RemainingArgsClass, RemainingArgsJoinedClass, @@ -155,6 +156,7 @@ class Option { case CommaJoinedClass: return RenderCommaJoinedStyle; case FlagClass: + case ValuesClass: case SeparateClass: case MultiArgClass: case JoinedOrSeparateClass: diff --git a/contrib/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/contrib/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h index b2f73fda2bae..0ba792e8dc43 100644 --- a/contrib/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/contrib/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -411,9 +411,11 @@ class CoverageData { std::vector::const_iterator begin() const { return Segments.begin(); } + std::vector::const_iterator end() const { return Segments.end(); } + bool empty() const { return Segments.empty(); } /// \brief Expansions that can be further processed. @@ -430,6 +432,7 @@ class CoverageMapping { unsigned MismatchedFunctionCount = 0; CoverageMapping() = default; + /// \brief Add a function record corresponding to \p Record. Error loadFunctionRecord(const CoverageMappingRecord &Record, IndexedInstrProfReader &ProfileReader); @@ -607,13 +610,13 @@ enum CovMapVersion { }; template struct CovMapTraits { - typedef CovMapFunctionRecord CovMapFuncRecordType; - typedef uint64_t NameRefType; + using CovMapFuncRecordType = CovMapFunctionRecord; + using NameRefType = uint64_t; }; template struct CovMapTraits { - typedef CovMapFunctionRecordV1 CovMapFuncRecordType; - typedef IntPtrT NameRefType; + using CovMapFuncRecordType = CovMapFunctionRecordV1; + using NameRefType = IntPtrT; }; } // end namespace coverage @@ -622,6 +625,7 @@ template struct CovMapTraits { template<> struct DenseMapInfo { static inline coverage::CounterExpression getEmptyKey() { using namespace coverage; + return CounterExpression(CounterExpression::ExprKind::Subtract, Counter::getCounter(~0U), Counter::getCounter(~0U)); @@ -629,6 +633,7 @@ template<> struct DenseMapInfo { static inline coverage::CounterExpression getTombstoneKey() { using namespace coverage; + return CounterExpression(CounterExpression::ExprKind::Add, Counter::getCounter(~0U), Counter::getCounter(~0U)); diff --git a/contrib/llvm/include/llvm/ProfileData/InstrProf.h b/contrib/llvm/include/llvm/ProfileData/InstrProf.h index 0dbb2cf9f269..573ea90cfd00 100644 --- a/contrib/llvm/include/llvm/ProfileData/InstrProf.h +++ b/contrib/llvm/include/llvm/ProfileData/InstrProf.h @@ -410,7 +410,7 @@ uint64_t ComputeHash(StringRef K); /// on how PGO name is formed. class InstrProfSymtab { public: - typedef std::vector> AddrHashMap; + using AddrHashMap = std::vector>; private: StringRef Data; @@ -450,11 +450,11 @@ class InstrProfSymtab { /// decls from module \c M. This interface is used by transformation /// passes such as indirect function call promotion. Variable \c InLTO /// indicates if this is called from LTO optimization passes. - void create(Module &M, bool InLTO = false); + Error create(Module &M, bool InLTO = false); /// Create InstrProfSymtab from a set of names iteratable from /// \p IterRange. This interface is used by IndexedProfReader. - template void create(const NameIterRange &IterRange); + template Error create(const NameIterRange &IterRange); // If the symtab is created by a series of calls to \c addFuncName, \c // finalizeSymtab needs to be called before looking up function names. @@ -464,11 +464,14 @@ class InstrProfSymtab { /// Update the symtab by adding \p FuncName to the table. This interface /// is used by the raw and text profile readers. - void addFuncName(StringRef FuncName) { + Error addFuncName(StringRef FuncName) { + if (FuncName.empty()) + return make_error(instrprof_error::malformed); auto Ins = NameTab.insert(FuncName); if (Ins.second) MD5NameMap.push_back(std::make_pair( IndexedInstrProf::ComputeHash(FuncName), Ins.first->getKey())); + return Error::success(); } /// Map a function address to its name's MD5 hash. This interface @@ -511,11 +514,13 @@ Error InstrProfSymtab::create(StringRef NameStrings) { } template -void InstrProfSymtab::create(const NameIterRange &IterRange) { +Error InstrProfSymtab::create(const NameIterRange &IterRange) { for (auto Name : IterRange) - addFuncName(Name); + if (Error E = addFuncName(Name)) + return E; finalizeSymtab(); + return Error::success(); } void InstrProfSymtab::finalizeSymtab() { @@ -594,7 +599,7 @@ struct InstrProfRecord { InstrProfRecord(StringRef Name, uint64_t Hash, std::vector Counts) : Name(Name), Hash(Hash), Counts(std::move(Counts)) {} - typedef std::vector> ValueMapType; + using ValueMapType = std::vector>; /// Return the number of value profile kinds with non-zero number /// of profile sites. @@ -668,8 +673,8 @@ struct InstrProfRecord { private: std::vector IndirectCallSites; std::vector MemOPSizes; - const std::vector & + const std::vector & getValueSitesForKind(uint32_t ValueKind) const { switch (ValueKind) { case IPVK_IndirectCallTarget: @@ -873,6 +878,11 @@ struct Summary { // The number of Cutoff Entries (Summary::Entry) following summary fields. uint64_t NumCutoffEntries; + Summary() = delete; + Summary(uint32_t Size) { memset(this, 0, Size); } + + void operator delete(void *ptr) { ::operator delete(ptr); } + static uint32_t getSize(uint32_t NumSumFields, uint32_t NumCutoffEntries) { return sizeof(Summary) + NumCutoffEntries * sizeof(Entry) + NumSumFields * sizeof(uint64_t); @@ -911,11 +921,6 @@ struct Summary { ER.MinBlockCount = E.MinCount; ER.NumBlocks = E.NumCounts; } - - Summary(uint32_t Size) { memset(this, 0, Size); } - void operator delete(void *ptr) { ::operator delete(ptr); } - - Summary() = delete; }; inline std::unique_ptr allocSummary(uint32_t TotalSize) { diff --git a/contrib/llvm/include/llvm/ProfileData/InstrProfReader.h b/contrib/llvm/include/llvm/ProfileData/InstrProfReader.h index 1d85a7149afc..8163ca159209 100644 --- a/contrib/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/contrib/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -92,6 +92,7 @@ class InstrProfReader { protected: std::unique_ptr Symtab; + /// Set the current error and return same. Error error(instrprof_error Err) { LastError = Err; @@ -202,7 +203,7 @@ class RawInstrProfReader : public InstrProfReader { public: RawInstrProfReader(std::unique_ptr DataBuffer) - : DataBuffer(std::move(DataBuffer)) { } + : DataBuffer(std::move(DataBuffer)) {} RawInstrProfReader(const RawInstrProfReader &) = delete; RawInstrProfReader &operator=(const RawInstrProfReader &) = delete; @@ -268,8 +269,8 @@ class RawInstrProfReader : public InstrProfReader { } }; -typedef RawInstrProfReader RawInstrProfReader32; -typedef RawInstrProfReader RawInstrProfReader64; +using RawInstrProfReader32 = RawInstrProfReader; +using RawInstrProfReader64 = RawInstrProfReader; namespace IndexedInstrProf { @@ -292,12 +293,12 @@ class InstrProfLookupTrait { InstrProfLookupTrait(IndexedInstrProf::HashT HashType, unsigned FormatVersion) : HashType(HashType), FormatVersion(FormatVersion) {} - typedef ArrayRef data_type; + using data_type = ArrayRef; - typedef StringRef internal_key_type; - typedef StringRef external_key_type; - typedef uint64_t hash_value_type; - typedef uint64_t offset_type; + using internal_key_type = StringRef; + using external_key_type = StringRef; + using hash_value_type = uint64_t; + using offset_type = uint64_t; static bool EqualKey(StringRef A, StringRef B) { return A == B; } static StringRef GetInternalKey(StringRef K) { return K; } @@ -343,15 +344,14 @@ struct InstrProfReaderIndexBase { virtual void setValueProfDataEndianness(support::endianness Endianness) = 0; virtual uint64_t getVersion() const = 0; virtual bool isIRLevelProfile() const = 0; - virtual void populateSymtab(InstrProfSymtab &) = 0; + virtual Error populateSymtab(InstrProfSymtab &) = 0; }; -typedef OnDiskIterableChainedHashTable - OnDiskHashTableImplV3; +using OnDiskHashTableImplV3 = + OnDiskIterableChainedHashTable; template class InstrProfReaderIndex : public InstrProfReaderIndexBase { - private: std::unique_ptr HashTable; typename HashTableImpl::data_iterator RecordIterator; @@ -383,8 +383,8 @@ class InstrProfReaderIndex : public InstrProfReaderIndexBase { return (FormatVersion & VARIANT_MASK_IR_PROF) != 0; } - void populateSymtab(InstrProfSymtab &Symtab) override { - Symtab.create(HashTable->keys()); + Error populateSymtab(InstrProfSymtab &Symtab) override { + return Symtab.create(HashTable->keys()); } }; diff --git a/contrib/llvm/include/llvm/ProfileData/InstrProfWriter.h b/contrib/llvm/include/llvm/ProfileData/InstrProfWriter.h index 10742c0228eb..fff10af30295 100644 --- a/contrib/llvm/include/llvm/ProfileData/InstrProfWriter.h +++ b/contrib/llvm/include/llvm/ProfileData/InstrProfWriter.h @@ -29,10 +29,11 @@ namespace llvm { /// Writer for instrumentation based profile data. class InstrProfRecordWriterTrait; class ProfOStream; +class raw_fd_ostream; class InstrProfWriter { public: - typedef SmallDenseMap ProfilingData; + using ProfilingData = SmallDenseMap; enum ProfKind { PF_Unknown = 0, PF_FE, PF_IRLevel }; private: @@ -58,7 +59,7 @@ class InstrProfWriter { void write(raw_fd_ostream &OS); /// Write the profile in text format to \c OS - void writeText(raw_fd_ostream &OS); + Error writeText(raw_fd_ostream &OS); /// Write \c Record in text format to \c OS static void writeRecordInText(const InstrProfRecord &Record, diff --git a/contrib/llvm/include/llvm/ProfileData/SampleProf.h b/contrib/llvm/include/llvm/ProfileData/SampleProf.h index 7a705ca5416d..7fc258831be8 100644 --- a/contrib/llvm/include/llvm/ProfileData/SampleProf.h +++ b/contrib/llvm/include/llvm/ProfileData/SampleProf.h @@ -125,7 +125,7 @@ raw_ostream &operator<<(raw_ostream &OS, const LineLocation &Loc); /// will be a list of one or more functions. class SampleRecord { public: - typedef StringMap CallTargetMap; + using CallTargetMap = StringMap; SampleRecord() = default; @@ -182,10 +182,11 @@ class SampleRecord { raw_ostream &operator<<(raw_ostream &OS, const SampleRecord &Sample); -typedef std::map BodySampleMap; class FunctionSamples; -typedef StringMap FunctionSamplesMap; -typedef std::map CallsiteSampleMap; + +using BodySampleMap = std::map; +using FunctionSamplesMap = StringMap; +using CallsiteSampleMap = std::map; /// Representation of the samples collected for a function. /// @@ -398,8 +399,8 @@ raw_ostream &operator<<(raw_ostream &OS, const FunctionSamples &FS); /// order of LocationT. template class SampleSorter { public: - typedef std::pair SamplesWithLoc; - typedef SmallVector SamplesWithLocList; + using SamplesWithLoc = std::pair; + using SamplesWithLocList = SmallVector; SampleSorter(const std::map &Samples) { for (const auto &I : Samples) diff --git a/contrib/llvm/include/llvm/ProfileData/SampleProfReader.h b/contrib/llvm/include/llvm/ProfileData/SampleProfReader.h index 29e3aba3e0e7..9c1f357cbbd1 100644 --- a/contrib/llvm/include/llvm/ProfileData/SampleProfReader.h +++ b/contrib/llvm/include/llvm/ProfileData/SampleProfReader.h @@ -350,7 +350,7 @@ class SampleProfileReaderText : public SampleProfileReader { class SampleProfileReaderBinary : public SampleProfileReader { public: SampleProfileReaderBinary(std::unique_ptr B, LLVMContext &C) - : SampleProfileReader(std::move(B), C), Data(nullptr), End(nullptr) {} + : SampleProfileReader(std::move(B), C) {} /// \brief Read and validate the file header. std::error_code readHeader() override; @@ -388,10 +388,10 @@ class SampleProfileReaderBinary : public SampleProfileReader { std::error_code readProfile(FunctionSamples &FProfile); /// \brief Points to the current location in the buffer. - const uint8_t *Data; + const uint8_t *Data = nullptr; /// \brief Points to the end of the buffer. - const uint8_t *End; + const uint8_t *End = nullptr; /// Function name table. std::vector NameTable; @@ -403,7 +403,7 @@ class SampleProfileReaderBinary : public SampleProfileReader { std::error_code readSummary(); }; -typedef SmallVector InlineCallStack; +using InlineCallStack = SmallVector; // Supported histogram types in GCC. Currently, we only need support for // call target histograms. diff --git a/contrib/llvm/include/llvm/Support/BinaryStreamReader.h b/contrib/llvm/include/llvm/Support/BinaryStreamReader.h index 738c042add3e..ae5ebb2c3628 100644 --- a/contrib/llvm/include/llvm/Support/BinaryStreamReader.h +++ b/contrib/llvm/include/llvm/Support/BinaryStreamReader.h @@ -137,6 +137,15 @@ class BinaryStreamReader { /// returns an appropriate error code. Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length); + /// Read \p Length bytes from the underlying stream into \p Stream. This is + /// equivalent to calling getUnderlyingStream().slice(Offset, Length). + /// Updates the stream's offset to point after the newly read object. Never + /// causes a copy. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readSubstream(BinarySubstreamRef &Stream, uint32_t Size); + /// Get a pointer to an object of type T from the underlying stream, as if by /// memcpy, and store the result into \p Dest. It is up to the caller to /// ensure that objects of type T can be safely treated in this manner. diff --git a/contrib/llvm/include/llvm/Support/BinaryStreamRef.h b/contrib/llvm/include/llvm/Support/BinaryStreamRef.h index e3bd4bf0860e..6d5135cb258d 100644 --- a/contrib/llvm/include/llvm/Support/BinaryStreamRef.h +++ b/contrib/llvm/include/llvm/Support/BinaryStreamRef.h @@ -166,6 +166,28 @@ class BinaryStreamRef ArrayRef &Buffer) const; }; +struct BinarySubstreamRef { + uint32_t Offset; // Offset in the parent stream + BinaryStreamRef StreamData; // Stream Data + + BinarySubstreamRef slice(uint32_t Off, uint32_t Size) const { + BinaryStreamRef SubSub = StreamData.slice(Off, Size); + return {Off + Offset, SubSub}; + } + BinarySubstreamRef drop_front(uint32_t N) const { + return slice(N, size() - N); + } + BinarySubstreamRef keep_front(uint32_t N) const { return slice(0, N); } + + std::pair + split(uint32_t Offset) const { + return std::make_pair(keep_front(Offset), drop_front(Offset)); + } + + uint32_t size() const { return StreamData.getLength(); } + bool empty() const { return size() == 0; } +}; + class WritableBinaryStreamRef : public BinaryStreamRefBase { diff --git a/contrib/llvm/include/llvm/Support/CachePruning.h b/contrib/llvm/include/llvm/Support/CachePruning.h index e826938878e5..46e34358573b 100644 --- a/contrib/llvm/include/llvm/Support/CachePruning.h +++ b/contrib/llvm/include/llvm/Support/CachePruning.h @@ -39,8 +39,13 @@ struct CachePruningPolicy { /// available space on the the disk. Set to 100 to indicate no limit, 50 to /// indicate that the cache size will not be left over half the available disk /// space. A value over 100 will be reduced to 100. A value of 0 disables the - /// size-based pruning. - unsigned PercentageOfAvailableSpace = 75; + /// percentage size-based pruning. + unsigned MaxSizePercentageOfAvailableSpace = 75; + + /// The maximum size for the cache directory in bytes. A value over the amount + /// of available space on the disk will be reduced to the amount of available + /// space. A value of 0 disables the absolute size-based pruning. + uint64_t MaxSizeBytes = 0; }; /// Parse the given string as a cache pruning policy. Defaults are taken from a diff --git a/contrib/llvm/include/llvm/Support/DataExtractor.h b/contrib/llvm/include/llvm/Support/DataExtractor.h index 380b628fd95f..31447882a919 100644 --- a/contrib/llvm/include/llvm/Support/DataExtractor.h +++ b/contrib/llvm/include/llvm/Support/DataExtractor.h @@ -14,6 +14,30 @@ #include "llvm/Support/DataTypes.h" namespace llvm { + +/// An auxiliary type to facilitate extraction of 3-byte entities. +struct Uint24 { + uint8_t Bytes[3]; + Uint24(uint8_t U) { + Bytes[0] = Bytes[1] = Bytes[2] = U; + } + Uint24(uint8_t U0, uint8_t U1, uint8_t U2) { + Bytes[0] = U0; Bytes[1] = U1; Bytes[2] = U2; + } + uint32_t getAsUint32(bool IsLittleEndian) const { + int LoIx = IsLittleEndian ? 0 : 2; + return Bytes[LoIx] + (Bytes[1] << 8) + (Bytes[2-LoIx] << 16); + } +}; + +using uint24_t = Uint24; +static_assert(sizeof(uint24_t) == 3, "sizeof(uint24_t) != 3"); + +/// Needed by swapByteOrder(). +inline uint24_t getSwappedBytes(uint24_t C) { + return uint24_t(C.Bytes[2], C.Bytes[1], C.Bytes[0]); +} + class DataExtractor { StringRef Data; uint8_t IsLittleEndian; @@ -236,6 +260,23 @@ class DataExtractor { /// NULL otherise. uint16_t *getU16(uint32_t *offset_ptr, uint16_t *dst, uint32_t count) const; + /// Extract a 24-bit unsigned value from \a *offset_ptr and return it + /// in a uint32_t. + /// + /// Extract 3 bytes from the binary data at the offset pointed to by + /// \a offset_ptr, construct a uint32_t from them and update the offset + /// on success. + /// + /// @param[in,out] offset_ptr + /// A pointer to an offset within the data that will be advanced + /// by the 3 bytes if the value is extracted correctly. If the offset + /// is out of bounds or there are not enough bytes to extract this value, + /// the offset will be left unmodified. + /// + /// @return + /// The extracted 24-bit value represented in a uint32_t. + uint32_t getU24(uint32_t *offset_ptr) const; + /// Extract a uint32_t value from \a *offset_ptr. /// /// Extract a single uint32_t from the binary data at the offset diff --git a/contrib/llvm/include/llvm/Support/Errno.h b/contrib/llvm/include/llvm/Support/Errno.h index 8e145c7b0b51..4ce65e7dc83c 100644 --- a/contrib/llvm/include/llvm/Support/Errno.h +++ b/contrib/llvm/include/llvm/Support/Errno.h @@ -14,6 +14,7 @@ #ifndef LLVM_SUPPORT_ERRNO_H #define LLVM_SUPPORT_ERRNO_H +#include #include namespace llvm { diff --git a/contrib/llvm/include/llvm/Support/Error.h b/contrib/llvm/include/llvm/Support/Error.h index 1e27e0b821f0..9a7fa0ae6356 100644 --- a/contrib/llvm/include/llvm/Support/Error.h +++ b/contrib/llvm/include/llvm/Support/Error.h @@ -1076,6 +1076,27 @@ T cantFail(Expected ValOrErr) { llvm_unreachable("Failure value returned from cantFail wrapped call"); } +/// Report a fatal error if ValOrErr is a failure value, otherwise unwraps and +/// returns the contained reference. +/// +/// This function can be used to wrap calls to fallible functions ONLY when it +/// is known that the Error will always be a success value. E.g. +/// +/// @code{.cpp} +/// // foo only attempts the fallible operation if DoFallibleOperation is +/// // true. If DoFallibleOperation is false then foo always returns a Bar&. +/// Expected foo(bool DoFallibleOperation); +/// +/// Bar &X = cantFail(foo(false)); +/// @endcode +template +T& cantFail(Expected ValOrErr) { + if (ValOrErr) + return *ValOrErr; + else + llvm_unreachable("Failure value returned from cantFail wrapped call"); +} + } // end namespace llvm #endif // LLVM_SUPPORT_ERROR_H diff --git a/contrib/llvm/include/llvm/Support/GCOV.h b/contrib/llvm/include/llvm/Support/GCOV.h index 268c53c50252..02016e7dbd62 100644 --- a/contrib/llvm/include/llvm/Support/GCOV.h +++ b/contrib/llvm/include/llvm/Support/GCOV.h @@ -271,8 +271,8 @@ struct GCOVEdge { /// GCOVFunction - Collects function information. class GCOVFunction { public: - typedef pointee_iterator>::const_iterator> BlockIterator; + using BlockIterator = pointee_iterator>::const_iterator>; GCOVFunction(GCOVFile &P) : Parent(P) {} @@ -321,7 +321,7 @@ class GCOVBlock { }; public: - typedef SmallVectorImpl::const_iterator EdgeIterator; + using EdgeIterator = SmallVectorImpl::const_iterator; GCOVBlock(GCOVFunction &P, uint32_t N) : Parent(P), Number(N) {} ~GCOVBlock(); @@ -381,10 +381,10 @@ class FileInfo { // Therefore this typedef allows LineData.Functions to store multiple // functions // per instance. This is rare, however, so optimize for the common case. - typedef SmallVector FunctionVector; - typedef DenseMap FunctionLines; - typedef SmallVector BlockVector; - typedef DenseMap BlockLines; + using FunctionVector = SmallVector; + using FunctionLines = DenseMap; + using BlockVector = SmallVector; + using BlockLines = DenseMap; struct LineData { LineData() = default; @@ -448,8 +448,8 @@ class FileInfo { uint32_t RunCount = 0; uint32_t ProgramCount = 0; - typedef SmallVector, 4> FileCoverageList; - typedef MapVector FuncCoverageMap; + using FileCoverageList = SmallVector, 4>; + using FuncCoverageMap = MapVector; FileCoverageList FileCoverages; FuncCoverageMap FuncCoverages; diff --git a/contrib/llvm/include/llvm/Support/GenericDomTree.h b/contrib/llvm/include/llvm/Support/GenericDomTree.h index 80a2dfcbad88..601633d41cff 100644 --- a/contrib/llvm/include/llvm/Support/GenericDomTree.h +++ b/contrib/llvm/include/llvm/Support/GenericDomTree.h @@ -69,14 +69,13 @@ template class DominatorBase { : Roots(), IsPostDominators(isPostDom) {} DominatorBase(DominatorBase &&Arg) - : Roots(std::move(Arg.Roots)), - IsPostDominators(std::move(Arg.IsPostDominators)) { + : Roots(std::move(Arg.Roots)), IsPostDominators(Arg.IsPostDominators) { Arg.Roots.clear(); } DominatorBase &operator=(DominatorBase &&RHS) { Roots = std::move(RHS.Roots); - IsPostDominators = std::move(RHS.IsPostDominators); + IsPostDominators = RHS.IsPostDominators; RHS.Roots.clear(); return *this; } @@ -99,18 +98,17 @@ template class DomTreeNodeBase { template friend class DominatorTreeBase; NodeT *TheBB; - DomTreeNodeBase *IDom; - std::vector *> Children; - mutable int DFSNumIn = -1; - mutable int DFSNumOut = -1; + DomTreeNodeBase *IDom; + std::vector Children; + mutable unsigned DFSNumIn = ~0; + mutable unsigned DFSNumOut = ~0; -public: - DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom) - : TheBB(BB), IDom(iDom) {} + public: + DomTreeNodeBase(NodeT *BB, DomTreeNodeBase *iDom) : TheBB(BB), IDom(iDom) {} - typedef typename std::vector *>::iterator iterator; - typedef typename std::vector *>::const_iterator - const_iterator; + using iterator = typename std::vector::iterator; + using const_iterator = + typename std::vector::const_iterator; iterator begin() { return Children.begin(); } iterator end() { return Children.end(); } @@ -118,14 +116,12 @@ template class DomTreeNodeBase { const_iterator end() const { return Children.end(); } NodeT *getBlock() const { return TheBB; } - DomTreeNodeBase *getIDom() const { return IDom; } + DomTreeNodeBase *getIDom() const { return IDom; } - const std::vector *> &getChildren() const { - return Children; - } + const std::vector &getChildren() const { return Children; } - std::unique_ptr> - addChild(std::unique_ptr> C) { + std::unique_ptr addChild( + std::unique_ptr C) { Children.push_back(C.get()); return C; } @@ -134,7 +130,7 @@ template class DomTreeNodeBase { void clearAllChildren() { Children.clear(); } - bool compare(const DomTreeNodeBase *Other) const { + bool compare(const DomTreeNodeBase *Other) const { if (getNumChildren() != Other->getNumChildren()) return true; @@ -152,10 +148,10 @@ template class DomTreeNodeBase { return false; } - void setIDom(DomTreeNodeBase *NewIDom) { + void setIDom(DomTreeNodeBase *NewIDom) { assert(IDom && "No immediate dominator?"); if (IDom != NewIDom) { - typename std::vector *>::iterator I = + typename std::vector::iterator I = find(IDom->Children, this); assert(I != IDom->Children.end() && "Not in immediate dominator children set!"); @@ -177,32 +173,32 @@ template class DomTreeNodeBase { private: // Return true if this node is dominated by other. Use this only if DFS info // is valid. - bool DominatedBy(const DomTreeNodeBase *other) const { + bool DominatedBy(const DomTreeNodeBase *other) const { return this->DFSNumIn >= other->DFSNumIn && this->DFSNumOut <= other->DFSNumOut; } }; template -raw_ostream &operator<<(raw_ostream &o, const DomTreeNodeBase *Node) { +raw_ostream &operator<<(raw_ostream &O, const DomTreeNodeBase *Node) { if (Node->getBlock()) - Node->getBlock()->printAsOperand(o, false); + Node->getBlock()->printAsOperand(O, false); else - o << " <>"; + O << " <>"; - o << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "}"; + O << " {" << Node->getDFSNumIn() << "," << Node->getDFSNumOut() << "}"; - return o << "\n"; + return O << "\n"; } template -void PrintDomTree(const DomTreeNodeBase *N, raw_ostream &o, +void PrintDomTree(const DomTreeNodeBase *N, raw_ostream &O, unsigned Lev) { - o.indent(2 * Lev) << "[" << Lev << "] " << N; + O.indent(2 * Lev) << "[" << Lev << "] " << N; for (typename DomTreeNodeBase::const_iterator I = N->begin(), E = N->end(); I != E; ++I) - PrintDomTree(*I, o, Lev + 1); + PrintDomTree(*I, O, Lev + 1); } // The calculate routine is provided in a separate header but referenced here. @@ -239,8 +235,8 @@ template class DominatorTreeBase : public DominatorBase { } protected: - typedef DenseMap>> - DomTreeNodeMapType; + using DomTreeNodeMapType = + DenseMap>>; DomTreeNodeMapType DomTreeNodes; DomTreeNodeBase *RootNode; @@ -663,19 +659,18 @@ template class DominatorTreeBase : public DominatorBase { /// print - Convert to human readable form /// - void print(raw_ostream &o) const { - o << "=============================--------------------------------\n"; + void print(raw_ostream &O) const { + O << "=============================--------------------------------\n"; if (this->isPostDominator()) - o << "Inorder PostDominator Tree: "; + O << "Inorder PostDominator Tree: "; else - o << "Inorder Dominator Tree: "; + O << "Inorder Dominator Tree: "; if (!DFSInfoValid) - o << "DFSNumbers invalid: " << SlowQueries << " slow queries."; - o << "\n"; + O << "DFSNumbers invalid: " << SlowQueries << " slow queries."; + O << "\n"; // The postdom tree can have a null root if there are no returns. - if (getRootNode()) - PrintDomTree(getRootNode(), o, 1); + if (getRootNode()) PrintDomTree(getRootNode(), O, 1); } protected: @@ -770,7 +765,7 @@ template class DominatorTreeBase : public DominatorBase { /// recalculate - compute a dominator tree for the given function template void recalculate(FT &F) { - typedef GraphTraits TraitsTy; + using TraitsTy = GraphTraits; reset(); Vertex.push_back(nullptr); diff --git a/contrib/llvm/include/llvm/Support/GenericDomTreeConstruction.h b/contrib/llvm/include/llvm/Support/GenericDomTreeConstruction.h index c1d757f3ab6a..449c385bc86a 100644 --- a/contrib/llvm/include/llvm/Support/GenericDomTreeConstruction.h +++ b/contrib/llvm/include/llvm/Support/GenericDomTreeConstruction.h @@ -35,10 +35,10 @@ namespace llvm { // converting the one argument insert calls. template struct df_iterator_dom_storage { public: - typedef DenseMap BaseSet; + using BaseSet = DenseMap; df_iterator_dom_storage(BaseSet &Storage) : Storage(Storage) {} - typedef typename BaseSet::iterator iterator; + using iterator = typename BaseSet::iterator; std::pair insert(NodeRef N) { return Storage.insert({N, InfoType()}); } @@ -101,20 +101,22 @@ template typename GraphT::NodeRef Eval(DominatorTreeBaseByGraphTraits &DT, typename GraphT::NodeRef VIn, unsigned LastLinked) { + using NodePtr = typename GraphT::NodeRef; + auto &VInInfo = DT.Info[VIn]; if (VInInfo.DFSNum < LastLinked) return VIn; - SmallVector Work; - SmallPtrSet Visited; + SmallVector Work; + SmallPtrSet Visited; if (VInInfo.Parent >= LastLinked) Work.push_back(VIn); while (!Work.empty()) { - typename GraphT::NodeRef V = Work.back(); + NodePtr V = Work.back(); auto &VInfo = DT.Info[V]; - typename GraphT::NodeRef VAncestor = DT.Vertex[VInfo.Parent]; + NodePtr VAncestor = DT.Vertex[VInfo.Parent]; // Process Ancestor first if (Visited.insert(VAncestor).second && VInfo.Parent >= LastLinked) { @@ -128,8 +130,8 @@ typename GraphT::NodeRef Eval(DominatorTreeBaseByGraphTraits &DT, continue; auto &VAInfo = DT.Info[VAncestor]; - typename GraphT::NodeRef VAncestorLabel = VAInfo.Label; - typename GraphT::NodeRef VLabel = VInfo.Label; + NodePtr VAncestorLabel = VAInfo.Label; + NodePtr VLabel = VInfo.Label; if (DT.Info[VAncestorLabel].Semi < DT.Info[VLabel].Semi) VInfo.Label = VAncestorLabel; VInfo.Parent = VAInfo.Parent; @@ -141,10 +143,11 @@ typename GraphT::NodeRef Eval(DominatorTreeBaseByGraphTraits &DT, template void Calculate(DominatorTreeBaseByGraphTraits> &DT, FuncT &F) { - typedef GraphTraits GraphT; - static_assert(std::is_pointer::value, + using GraphT = GraphTraits; + using NodePtr = typename GraphT::NodeRef; + static_assert(std::is_pointer::value, "NodeRef should be pointer type"); - typedef typename std::remove_pointer::type NodeType; + using NodeType = typename std::remove_pointer::type; unsigned N = 0; bool MultipleRoots = (DT.Roots.size() > 1); @@ -186,13 +189,13 @@ void Calculate(DominatorTreeBaseByGraphTraits> &DT, Buckets[i] = i; for (unsigned i = N; i >= 2; --i) { - typename GraphT::NodeRef W = DT.Vertex[i]; + NodePtr W = DT.Vertex[i]; auto &WInfo = DT.Info[W]; // Step #2: Implicitly define the immediate dominator of vertices for (unsigned j = i; Buckets[j] != i; j = Buckets[j]) { - typename GraphT::NodeRef V = DT.Vertex[Buckets[j]]; - typename GraphT::NodeRef U = Eval(DT, V, i + 1); + NodePtr V = DT.Vertex[Buckets[j]]; + NodePtr U = Eval(DT, V, i + 1); DT.IDoms[V] = DT.Info[U].Semi < i ? U : W; } @@ -219,17 +222,17 @@ void Calculate(DominatorTreeBaseByGraphTraits> &DT, } if (N >= 1) { - typename GraphT::NodeRef Root = DT.Vertex[1]; + NodePtr Root = DT.Vertex[1]; for (unsigned j = 1; Buckets[j] != 1; j = Buckets[j]) { - typename GraphT::NodeRef V = DT.Vertex[Buckets[j]]; + NodePtr V = DT.Vertex[Buckets[j]]; DT.IDoms[V] = Root; } } // Step #4: Explicitly define the immediate dominator of each vertex for (unsigned i = 2; i <= N; ++i) { - typename GraphT::NodeRef W = DT.Vertex[i]; - typename GraphT::NodeRef &WIDom = DT.IDoms[W]; + NodePtr W = DT.Vertex[i]; + NodePtr &WIDom = DT.IDoms[W]; if (WIDom != DT.Vertex[DT.Info[W].Semi]) WIDom = DT.IDoms[WIDom]; } @@ -240,7 +243,7 @@ void Calculate(DominatorTreeBaseByGraphTraits> &DT, // one exit block, or it may be the virtual exit (denoted by (BasicBlock *)0) // which postdominates all real exits if there are multiple exit blocks, or // an infinite loop. - typename GraphT::NodeRef Root = !MultipleRoots ? DT.Roots[0] : nullptr; + NodePtr Root = !MultipleRoots ? DT.Roots[0] : nullptr; DT.RootNode = (DT.DomTreeNodes[Root] = @@ -249,13 +252,13 @@ void Calculate(DominatorTreeBaseByGraphTraits> &DT, // Loop over all of the reachable blocks in the function... for (unsigned i = 2; i <= N; ++i) { - typename GraphT::NodeRef W = DT.Vertex[i]; + NodePtr W = DT.Vertex[i]; // Don't replace this with 'count', the insertion side effect is important if (DT.DomTreeNodes[W]) continue; // Haven't calculated this node yet? - typename GraphT::NodeRef ImmDom = DT.getIDom(W); + NodePtr ImmDom = DT.getIDom(W); assert(ImmDom || DT.DomTreeNodes[nullptr]); diff --git a/contrib/llvm/include/llvm/Support/GraphWriter.h b/contrib/llvm/include/llvm/Support/GraphWriter.h index c318fea53651..3df5c867f7d3 100644 --- a/contrib/llvm/include/llvm/Support/GraphWriter.h +++ b/contrib/llvm/include/llvm/Support/GraphWriter.h @@ -1,4 +1,4 @@ -//===-- llvm/Support/GraphWriter.h - Write graph to a .dot file -*- C++ -*-===// +//===- llvm/Support/GraphWriter.h - Write graph to a .dot file --*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -24,30 +24,40 @@ #define LLVM_SUPPORT_GRAPHWRITER_H #include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/DOTGraphTraits.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include #include namespace llvm { namespace DOT { // Private functions... - std::string EscapeString(const std::string &Label); - /// \brief Get a color string for this node number. Simply round-robin selects - /// from a reasonable number of colors. - StringRef getColorString(unsigned NodeNumber); -} +std::string EscapeString(const std::string &Label); + +/// \brief Get a color string for this node number. Simply round-robin selects +/// from a reasonable number of colors. +StringRef getColorString(unsigned NodeNumber); + +} // end namespace DOT namespace GraphProgram { - enum Name { - DOT, - FDP, - NEATO, - TWOPI, - CIRCO - }; -} + +enum Name { + DOT, + FDP, + NEATO, + TWOPI, + CIRCO +}; + +} // end namespace GraphProgram bool DisplayGraph(StringRef Filename, bool wait = true, GraphProgram::Name program = GraphProgram::DOT); @@ -57,11 +67,11 @@ class GraphWriter { raw_ostream &O; const GraphType &G; - typedef DOTGraphTraits DOTTraits; - typedef GraphTraits GTraits; - typedef typename GTraits::NodeRef NodeRef; - typedef typename GTraits::nodes_iterator node_iterator; - typedef typename GTraits::ChildIteratorType child_iterator; + using DOTTraits = DOTGraphTraits; + using GTraits = GraphTraits; + using NodeRef = typename GTraits::NodeRef; + using node_iterator = typename GTraits::nodes_iterator; + using child_iterator = typename GTraits::ChildIteratorType; DOTTraits DTraits; static_assert(std::is_pointer::value, @@ -346,6 +356,6 @@ void ViewGraph(const GraphType &G, const Twine &Name, DisplayGraph(Filename, false, Program); } -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_SUPPORT_GRAPHWRITER_H diff --git a/contrib/llvm/include/llvm/Support/Host.h b/contrib/llvm/include/llvm/Support/Host.h index 89986fdae971..be93dd99032e 100644 --- a/contrib/llvm/include/llvm/Support/Host.h +++ b/contrib/llvm/include/llvm/Support/Host.h @@ -21,6 +21,16 @@ #include #elif defined(_AIX) #include +#elif defined(__sun) +/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */ +#include +#define BIG_ENDIAN 4321 +#define LITTLE_ENDIAN 1234 +#if defined(_BIG_ENDIAN) +#define BYTE_ORDER BIG_ENDIAN +#else +#define BYTE_ORDER LITTLE_ENDIAN +#endif #else #if !defined(BYTE_ORDER) && !defined(LLVM_ON_WIN32) #include diff --git a/contrib/llvm/include/llvm/Support/Path.h b/contrib/llvm/include/llvm/Support/Path.h index 6ac51195519e..e5979674cf1c 100644 --- a/contrib/llvm/include/llvm/Support/Path.h +++ b/contrib/llvm/include/llvm/Support/Path.h @@ -17,6 +17,7 @@ #define LLVM_SUPPORT_PATH_H #include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator.h" #include "llvm/Support/DataTypes.h" #include @@ -49,7 +50,8 @@ enum class Style { windows, posix, native }; /// C:\foo\bar => C:,/,foo,bar /// @endcode class const_iterator - : public std::iterator { + : public iterator_facade_base { StringRef Path; ///< The entire path. StringRef Component; ///< The current component. Not necessarily in Path. size_t Position; ///< The iterators current position within Path. @@ -61,10 +63,8 @@ class const_iterator public: reference operator*() const { return Component; } - pointer operator->() const { return &Component; } const_iterator &operator++(); // preincrement bool operator==(const const_iterator &RHS) const; - bool operator!=(const const_iterator &RHS) const { return !(*this == RHS); } /// @brief Difference in bytes between this and RHS. ptrdiff_t operator-(const const_iterator &RHS) const; @@ -76,7 +76,8 @@ class const_iterator /// \a path in reverse order. The traversal order is exactly reversed from that /// of \a const_iterator class reverse_iterator - : public std::iterator { + : public iterator_facade_base { StringRef Path; ///< The entire path. StringRef Component; ///< The current component. Not necessarily in Path. size_t Position; ///< The iterators current position within Path. @@ -87,10 +88,8 @@ class reverse_iterator public: reference operator*() const { return Component; } - pointer operator->() const { return &Component; } reverse_iterator &operator++(); // preincrement bool operator==(const reverse_iterator &RHS) const; - bool operator!=(const reverse_iterator &RHS) const { return !(*this == RHS); } /// @brief Difference in bytes between this and RHS. ptrdiff_t operator-(const reverse_iterator &RHS) const; diff --git a/contrib/llvm/include/llvm/Support/Solaris.h b/contrib/llvm/include/llvm/Support/Solaris/sys/regset.h similarity index 52% rename from contrib/llvm/include/llvm/Support/Solaris.h rename to contrib/llvm/include/llvm/Support/Solaris/sys/regset.h index 88d83014c468..6a69ebe718a1 100644 --- a/contrib/llvm/include/llvm/Support/Solaris.h +++ b/contrib/llvm/include/llvm/Support/Solaris/sys/regset.h @@ -1,4 +1,4 @@ -/*===- llvm/Support/Solaris.h ------------------------------------*- C++ -*-===* +/*===- llvm/Support/Solaris/sys/regset.h ------------------------*- C++ -*-===* * * The LLVM Compiler Infrastructure * @@ -7,24 +7,14 @@ * *===----------------------------------------------------------------------===* * - * This file contains portability fixes for Solaris hosts. + * This file works around excessive name space pollution from the system header + * on Solaris hosts. * *===----------------------------------------------------------------------===*/ -#ifndef LLVM_SUPPORT_SOLARIS_H -#define LLVM_SUPPORT_SOLARIS_H +#ifndef LLVM_SUPPORT_SOLARIS_SYS_REGSET_H -#include -#include - -/* Solaris doesn't have endian.h. SPARC is the only supported big-endian ISA. */ -#define BIG_ENDIAN 4321 -#define LITTLE_ENDIAN 1234 -#if defined(__sparc) || defined(__sparc__) -#define BYTE_ORDER BIG_ENDIAN -#else -#define BYTE_ORDER LITTLE_ENDIAN -#endif +#include_next #undef CS #undef DS diff --git a/contrib/llvm/include/llvm/Support/TargetRegistry.h b/contrib/llvm/include/llvm/Support/TargetRegistry.h index 9e9a91b0abda..90d6c084ee95 100644 --- a/contrib/llvm/include/llvm/Support/TargetRegistry.h +++ b/contrib/llvm/include/llvm/Support/TargetRegistry.h @@ -54,6 +54,7 @@ class MCSymbolizer; class MCTargetAsmParser; class MCTargetOptions; class MCTargetStreamer; +class raw_ostream; class raw_pwrite_stream; class TargetMachine; class TargetOptions; @@ -96,75 +97,75 @@ class Target { public: friend struct TargetRegistry; - typedef bool (*ArchMatchFnTy)(Triple::ArchType Arch); + using ArchMatchFnTy = bool (*)(Triple::ArchType Arch); - typedef MCAsmInfo *(*MCAsmInfoCtorFnTy)(const MCRegisterInfo &MRI, - const Triple &TT); - typedef void (*MCAdjustCodeGenOptsFnTy)(const Triple &TT, Reloc::Model RM, - CodeModel::Model &CM); + using MCAsmInfoCtorFnTy = MCAsmInfo *(*)(const MCRegisterInfo &MRI, + const Triple &TT); + using MCAdjustCodeGenOptsFnTy = void (*)(const Triple &TT, Reloc::Model RM, + CodeModel::Model &CM); - typedef MCInstrInfo *(*MCInstrInfoCtorFnTy)(void); - typedef MCInstrAnalysis *(*MCInstrAnalysisCtorFnTy)(const MCInstrInfo *Info); - typedef MCRegisterInfo *(*MCRegInfoCtorFnTy)(const Triple &TT); - typedef MCSubtargetInfo *(*MCSubtargetInfoCtorFnTy)(const Triple &TT, - StringRef CPU, - StringRef Features); - typedef TargetMachine *(*TargetMachineCtorTy)( + using MCInstrInfoCtorFnTy = MCInstrInfo *(*)(); + using MCInstrAnalysisCtorFnTy = MCInstrAnalysis *(*)(const MCInstrInfo *Info); + using MCRegInfoCtorFnTy = MCRegisterInfo *(*)(const Triple &TT); + using MCSubtargetInfoCtorFnTy = MCSubtargetInfo *(*)(const Triple &TT, + StringRef CPU, + StringRef Features); + using TargetMachineCtorTy = TargetMachine *(*)( const Target &T, const Triple &TT, StringRef CPU, StringRef Features, const TargetOptions &Options, Optional RM, CodeModel::Model CM, CodeGenOpt::Level OL); // If it weren't for layering issues (this header is in llvm/Support, but // depends on MC?) this should take the Streamer by value rather than rvalue // reference. - typedef AsmPrinter *(*AsmPrinterCtorTy)( + using AsmPrinterCtorTy = AsmPrinter *(*)( TargetMachine &TM, std::unique_ptr &&Streamer); - typedef MCAsmBackend *(*MCAsmBackendCtorTy)(const Target &T, - const MCRegisterInfo &MRI, - const Triple &TT, StringRef CPU, - const MCTargetOptions &Options); - typedef MCTargetAsmParser *(*MCAsmParserCtorTy)( + using MCAsmBackendCtorTy = MCAsmBackend *(*)(const Target &T, + const MCRegisterInfo &MRI, + const Triple &TT, StringRef CPU, + const MCTargetOptions &Options); + using MCAsmParserCtorTy = MCTargetAsmParser *(*)( const MCSubtargetInfo &STI, MCAsmParser &P, const MCInstrInfo &MII, const MCTargetOptions &Options); - typedef MCDisassembler *(*MCDisassemblerCtorTy)(const Target &T, - const MCSubtargetInfo &STI, - MCContext &Ctx); - typedef MCInstPrinter *(*MCInstPrinterCtorTy)(const Triple &T, - unsigned SyntaxVariant, - const MCAsmInfo &MAI, - const MCInstrInfo &MII, - const MCRegisterInfo &MRI); - typedef MCCodeEmitter *(*MCCodeEmitterCtorTy)(const MCInstrInfo &II, - const MCRegisterInfo &MRI, - MCContext &Ctx); - typedef MCStreamer *(*ELFStreamerCtorTy)(const Triple &T, MCContext &Ctx, - MCAsmBackend &TAB, - raw_pwrite_stream &OS, - MCCodeEmitter *Emitter, - bool RelaxAll); - typedef MCStreamer *(*MachOStreamerCtorTy)(MCContext &Ctx, MCAsmBackend &TAB, - raw_pwrite_stream &OS, - MCCodeEmitter *Emitter, - bool RelaxAll, - bool DWARFMustBeAtTheEnd); - typedef MCStreamer *(*COFFStreamerCtorTy)(MCContext &Ctx, MCAsmBackend &TAB, - raw_pwrite_stream &OS, - MCCodeEmitter *Emitter, - bool RelaxAll, - bool IncrementalLinkerCompatible); - typedef MCStreamer *(*WasmStreamerCtorTy)(const Triple &T, MCContext &Ctx, + using MCDisassemblerCtorTy = MCDisassembler *(*)(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx); + using MCInstPrinterCtorTy = MCInstPrinter *(*)(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI); + using MCCodeEmitterCtorTy = MCCodeEmitter *(*)(const MCInstrInfo &II, + const MCRegisterInfo &MRI, + MCContext &Ctx); + using ELFStreamerCtorTy = MCStreamer *(*)(const Triple &T, MCContext &Ctx, MCAsmBackend &TAB, raw_pwrite_stream &OS, MCCodeEmitter *Emitter, bool RelaxAll); - typedef MCTargetStreamer *(*NullTargetStreamerCtorTy)(MCStreamer &S); - typedef MCTargetStreamer *(*AsmTargetStreamerCtorTy)( + using MachOStreamerCtorTy = MCStreamer *(*)(MCContext &Ctx, MCAsmBackend &TAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, + bool RelaxAll, + bool DWARFMustBeAtTheEnd); + using COFFStreamerCtorTy = MCStreamer *(*)(MCContext &Ctx, MCAsmBackend &TAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, + bool RelaxAll, + bool IncrementalLinkerCompatible); + using WasmStreamerCtorTy = MCStreamer *(*)(const Triple &T, MCContext &Ctx, + MCAsmBackend &TAB, + raw_pwrite_stream &OS, + MCCodeEmitter *Emitter, + bool RelaxAll); + using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S); + using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)( MCStreamer &S, formatted_raw_ostream &OS, MCInstPrinter *InstPrint, bool IsVerboseAsm); - typedef MCTargetStreamer *(*ObjectTargetStreamerCtorTy)( + using ObjectTargetStreamerCtorTy = MCTargetStreamer *(*)( MCStreamer &S, const MCSubtargetInfo &STI); - typedef MCRelocationInfo *(*MCRelocationInfoCtorTy)(const Triple &TT, - MCContext &Ctx); - typedef MCSymbolizer *(*MCSymbolizerCtorTy)( + using MCRelocationInfoCtorTy = MCRelocationInfo *(*)(const Triple &TT, + MCContext &Ctx); + using MCSymbolizerCtorTy = MCSymbolizer *(*)( const Triple &TT, LLVMOpInfoCallback GetOpInfo, LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo, MCContext *Ctx, std::unique_ptr &&RelInfo); diff --git a/contrib/llvm/include/llvm/Support/YAMLParser.h b/contrib/llvm/include/llvm/Support/YAMLParser.h index b9e3fa47752c..c196dd6c1ddc 100644 --- a/contrib/llvm/include/llvm/Support/YAMLParser.h +++ b/contrib/llvm/include/llvm/Support/YAMLParser.h @@ -1,4 +1,4 @@ -//===--- YAMLParser.h - Simple YAML parser --------------------------------===// +//===- YAMLParser.h - Simple YAML parser ------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -41,20 +41,25 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/SMLoc.h" +#include +#include +#include #include +#include +#include #include -#include namespace llvm { + class MemoryBufferRef; class SourceMgr; -class Twine; class raw_ostream; +class Twine; namespace yaml { -class document_iterator; class Document; +class document_iterator; class Node; class Scanner; struct Token; @@ -87,6 +92,7 @@ class Stream { document_iterator end(); void skip(); bool failed(); + bool validate() { skip(); return !failed(); @@ -95,10 +101,10 @@ class Stream { void printError(Node *N, const Twine &Msg); private: + friend class Document; + std::unique_ptr scanner; std::unique_ptr CurrentDoc; - - friend class Document; }; /// \brief Abstract base class for all Nodes. @@ -119,6 +125,18 @@ class Node { Node(unsigned int Type, std::unique_ptr &, StringRef Anchor, StringRef Tag); + void *operator new(size_t Size, BumpPtrAllocator &Alloc, + size_t Alignment = 16) noexcept { + return Alloc.Allocate(Size, Alignment); + } + + void operator delete(void *Ptr, BumpPtrAllocator &Alloc, + size_t Size) noexcept { + Alloc.Deallocate(Ptr, Size); + } + + void operator delete(void *) noexcept = delete; + /// \brief Get the value of the anchor attached to this node. If it does not /// have one, getAnchor().size() will be 0. StringRef getAnchor() const { return Anchor; } @@ -146,22 +164,10 @@ class Node { unsigned int getType() const { return TypeID; } - void *operator new(size_t Size, BumpPtrAllocator &Alloc, - size_t Alignment = 16) noexcept { - return Alloc.Allocate(Size, Alignment); - } - - void operator delete(void *Ptr, BumpPtrAllocator &Alloc, - size_t Size) noexcept { - Alloc.Deallocate(Ptr, Size); - } - protected: std::unique_ptr &Doc; SMRange SourceRange; - void operator delete(void *) noexcept = delete; - ~Node() = default; private: @@ -268,8 +274,7 @@ class KeyValueNode final : public Node { public: KeyValueNode(std::unique_ptr &D) - : Node(NK_KeyValue, D, StringRef(), StringRef()), Key(nullptr), - Value(nullptr) {} + : Node(NK_KeyValue, D, StringRef(), StringRef()) {} /// \brief Parse and return the key. /// @@ -296,8 +301,8 @@ class KeyValueNode final : public Node { } private: - Node *Key; - Node *Value; + Node *Key = nullptr; + Node *Value = nullptr; }; /// \brief This is an iterator abstraction over YAML collections shared by both @@ -309,7 +314,7 @@ template class basic_collection_iterator : public std::iterator { public: - basic_collection_iterator() : Base(nullptr) {} + basic_collection_iterator() = default; basic_collection_iterator(BaseT *B) : Base(B) {} ValueT *operator->() const { @@ -358,7 +363,7 @@ class basic_collection_iterator } private: - BaseT *Base; + BaseT *Base = nullptr; }; // The following two templates are used for both MappingNode and Sequence Node. @@ -399,11 +404,12 @@ class MappingNode final : public Node { MappingNode(std::unique_ptr &D, StringRef Anchor, StringRef Tag, MappingType MT) - : Node(NK_Mapping, D, Anchor, Tag), Type(MT), IsAtBeginning(true), - IsAtEnd(false), CurrentEntry(nullptr) {} + : Node(NK_Mapping, D, Anchor, Tag), Type(MT) {} friend class basic_collection_iterator; - typedef basic_collection_iterator iterator; + + using iterator = basic_collection_iterator; + template friend typename T::iterator yaml::begin(T &); template friend void yaml::skip(T &); @@ -419,9 +425,9 @@ class MappingNode final : public Node { private: MappingType Type; - bool IsAtBeginning; - bool IsAtEnd; - KeyValueNode *CurrentEntry; + bool IsAtBeginning = true; + bool IsAtEnd = false; + KeyValueNode *CurrentEntry = nullptr; void increment(); }; @@ -453,13 +459,12 @@ class SequenceNode final : public Node { SequenceNode(std::unique_ptr &D, StringRef Anchor, StringRef Tag, SequenceType ST) - : Node(NK_Sequence, D, Anchor, Tag), SeqType(ST), IsAtBeginning(true), - IsAtEnd(false), - WasPreviousTokenFlowEntry(true), // Start with an imaginary ','. - CurrentEntry(nullptr) {} + : Node(NK_Sequence, D, Anchor, Tag), SeqType(ST) {} friend class basic_collection_iterator; - typedef basic_collection_iterator iterator; + + using iterator = basic_collection_iterator; + template friend typename T::iterator yaml::begin(T &); template friend void yaml::skip(T &); @@ -477,10 +482,10 @@ class SequenceNode final : public Node { private: SequenceType SeqType; - bool IsAtBeginning; - bool IsAtEnd; - bool WasPreviousTokenFlowEntry; - Node *CurrentEntry; + bool IsAtBeginning = true; + bool IsAtEnd = false; + bool WasPreviousTokenFlowEntry = true; // Start with an imaginary ','. + Node *CurrentEntry = nullptr; }; /// \brief Represents an alias to a Node with an anchor. @@ -507,11 +512,11 @@ class AliasNode final : public Node { /// node. class Document { public: + Document(Stream &ParentStream); + /// \brief Root for parsing a node. Returns a single node. Node *parseBlockNode(); - Document(Stream &ParentStream); - /// \brief Finish parsing the current document and return true if there are /// more. Return false otherwise. bool skip(); @@ -564,7 +569,7 @@ class Document { /// \brief Iterator abstraction for Documents over a Stream. class document_iterator { public: - document_iterator() : Doc(nullptr) {} + document_iterator() = default; document_iterator(std::unique_ptr &D) : Doc(&D) {} bool operator==(const document_iterator &Other) { @@ -593,11 +598,11 @@ class document_iterator { private: bool isAtEnd() const { return !Doc || !*Doc; } - std::unique_ptr *Doc; + std::unique_ptr *Doc = nullptr; }; -} // End namespace yaml. +} // end namespace yaml -} // End namespace llvm. +} // end namespace llvm -#endif +#endif // LLVM_SUPPORT_YAMLPARSER_H diff --git a/contrib/llvm/include/llvm/Support/YAMLTraits.h b/contrib/llvm/include/llvm/Support/YAMLTraits.h index 8949d69ce724..53618a56f853 100644 --- a/contrib/llvm/include/llvm/Support/YAMLTraits.h +++ b/contrib/llvm/include/llvm/Support/YAMLTraits.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -226,7 +227,7 @@ struct MissingTrait; template struct has_ScalarEnumerationTraits { - typedef void (*Signature_enumeration)(class IO&, T&); + using Signature_enumeration = void (*)(class IO&, T&); template static char test(SameType*); @@ -243,7 +244,7 @@ struct has_ScalarEnumerationTraits template struct has_ScalarBitSetTraits { - typedef void (*Signature_bitset)(class IO&, T&); + using Signature_bitset = void (*)(class IO&, T&); template static char test(SameType*); @@ -259,9 +260,9 @@ struct has_ScalarBitSetTraits template struct has_ScalarTraits { - typedef StringRef (*Signature_input)(StringRef, void*, T&); - typedef void (*Signature_output)(const T&, void*, llvm::raw_ostream&); - typedef bool (*Signature_mustQuote)(StringRef); + using Signature_input = StringRef (*)(StringRef, void*, T&); + using Signature_output = void (*)(const T&, void*, raw_ostream&); + using Signature_mustQuote = bool (*)(StringRef); template static char test(SameType *, @@ -280,8 +281,8 @@ struct has_ScalarTraits template struct has_BlockScalarTraits { - typedef StringRef (*Signature_input)(StringRef, void *, T &); - typedef void (*Signature_output)(const T &, void *, llvm::raw_ostream &); + using Signature_input = StringRef (*)(StringRef, void *, T &); + using Signature_output = void (*)(const T &, void *, raw_ostream &); template static char test(SameType *, @@ -297,7 +298,7 @@ struct has_BlockScalarTraits // Test if MappingContextTraits is defined on type T. template struct has_MappingTraits { - typedef void (*Signature_mapping)(class IO &, T &, Context &); + using Signature_mapping = void (*)(class IO &, T &, Context &); template static char test(SameType*); @@ -312,7 +313,7 @@ template struct has_MappingTraits { // Test if MappingTraits is defined on type T. template struct has_MappingTraits { - typedef void (*Signature_mapping)(class IO &, T &); + using Signature_mapping = void (*)(class IO &, T &); template static char test(SameType *); @@ -325,7 +326,7 @@ template struct has_MappingTraits { // Test if MappingContextTraits::validate() is defined on type T. template struct has_MappingValidateTraits { - typedef StringRef (*Signature_validate)(class IO &, T &, Context &); + using Signature_validate = StringRef (*)(class IO &, T &, Context &); template static char test(SameType*); @@ -340,7 +341,7 @@ template struct has_MappingValidateTraits { // Test if MappingTraits::validate() is defined on type T. template struct has_MappingValidateTraits { - typedef StringRef (*Signature_validate)(class IO &, T &); + using Signature_validate = StringRef (*)(class IO &, T &); template static char test(SameType *); @@ -355,7 +356,7 @@ template struct has_MappingValidateTraits { template struct has_SequenceMethodTraits { - typedef size_t (*Signature_size)(class IO&, T&); + using Signature_size = size_t (*)(class IO&, T&); template static char test(SameType*); @@ -371,7 +372,7 @@ struct has_SequenceMethodTraits template struct has_CustomMappingTraits { - typedef void (*Signature_input)(IO &io, StringRef key, T &v); + using Signature_input = void (*)(IO &io, StringRef key, T &v); template static char test(SameType*); @@ -422,7 +423,7 @@ struct has_SequenceTraits : public std::integral_constant struct has_DocumentListTraits { - typedef size_t (*Signature_size)(class IO&, T&); + using Signature_size = size_t (*)(class IO &, T &); template static char test(SameType*); @@ -537,7 +538,7 @@ struct unvalidatedMappingTraits // Base class for Input and Output. class IO { public: - IO(void *Ctxt=nullptr); + IO(void *Ctxt = nullptr); virtual ~IO(); virtual bool outputting() = 0; @@ -638,6 +639,7 @@ class IO { EmptyContext Ctx; this->processKey(Key, Val, true, Ctx); } + template void mapRequired(const char *Key, T &Val, Context &Ctx) { this->processKey(Key, Val, true, Ctx); @@ -773,7 +775,7 @@ typename std::enable_if::value, void>::type yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { if ( io.outputting() ) { std::string Storage; - llvm::raw_string_ostream Buffer(Storage); + raw_string_ostream Buffer(Storage); ScalarTraits::output(Val, io.getContext(), Buffer); StringRef Str = Buffer.str(); io.scalarString(Str, ScalarTraits::mustQuote(Str)); @@ -783,7 +785,7 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { io.scalarString(Str, ScalarTraits::mustQuote(Str)); StringRef Result = ScalarTraits::input(Str, io.getContext(), Val); if ( !Result.empty() ) { - io.setError(llvm::Twine(Result)); + io.setError(Twine(Result)); } } } @@ -793,7 +795,7 @@ typename std::enable_if::value, void>::type yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { if (YamlIO.outputting()) { std::string Storage; - llvm::raw_string_ostream Buffer(Storage); + raw_string_ostream Buffer(Storage); BlockScalarTraits::output(Val, YamlIO.getContext(), Buffer); StringRef Str = Buffer.str(); YamlIO.blockScalarString(Str); @@ -803,7 +805,7 @@ yamlize(IO &YamlIO, T &Val, bool, EmptyContext &Ctx) { StringRef Result = BlockScalarTraits::input(Str, YamlIO.getContext(), Val); if (!Result.empty()) - YamlIO.setError(llvm::Twine(Result)); + YamlIO.setError(Twine(Result)); } } @@ -817,7 +819,7 @@ yamlize(IO &io, T &Val, bool, Context &Ctx) { if (io.outputting()) { StringRef Err = MappingTraits::validate(io, Val); if (!Err.empty()) { - llvm::errs() << Err << "\n"; + errs() << Err << "\n"; assert(Err.empty() && "invalid struct trying to be written as yaml"); } } @@ -871,7 +873,7 @@ yamlize(IO &io, T &Val, bool, EmptyContext &Ctx) { template typename std::enable_if::value, void>::type yamlize(IO &io, T &Seq, bool, Context &Ctx) { - if ( has_FlowTraits< SequenceTraits >::value ) { + if ( has_FlowTraits< SequenceTraits>::value ) { unsigned incnt = io.beginFlowSequence(); unsigned count = io.outputting() ? SequenceTraits::size(io, Seq) : incnt; for(unsigned i=0; i < count; ++i) { @@ -899,92 +901,92 @@ yamlize(IO &io, T &Seq, bool, Context &Ctx) { template<> struct ScalarTraits { - static void output(const bool &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, bool &); + static void output(const bool &, void* , raw_ostream &); + static StringRef input(StringRef, void *, bool &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const StringRef &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, StringRef &); + static void output(const StringRef &, void *, raw_ostream &); + static StringRef input(StringRef, void *, StringRef &); static bool mustQuote(StringRef S) { return needsQuotes(S); } }; template<> struct ScalarTraits { - static void output(const std::string &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, std::string &); + static void output(const std::string &, void *, raw_ostream &); + static StringRef input(StringRef, void *, std::string &); static bool mustQuote(StringRef S) { return needsQuotes(S); } }; template<> struct ScalarTraits { - static void output(const uint8_t &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, uint8_t &); + static void output(const uint8_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, uint8_t &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const uint16_t &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, uint16_t &); + static void output(const uint16_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, uint16_t &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const uint32_t &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, uint32_t &); + static void output(const uint32_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, uint32_t &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const uint64_t &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, uint64_t &); + static void output(const uint64_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, uint64_t &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const int8_t &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, int8_t &); + static void output(const int8_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, int8_t &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const int16_t &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, int16_t &); + static void output(const int16_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, int16_t &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const int32_t &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, int32_t &); + static void output(const int32_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, int32_t &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const int64_t &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, int64_t &); + static void output(const int64_t &, void *, raw_ostream &); + static StringRef input(StringRef, void *, int64_t &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const float &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, float &); + static void output(const float &, void *, raw_ostream &); + static StringRef input(StringRef, void *, float &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const double &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, double &); + static void output(const double &, void *, raw_ostream &); + static StringRef input(StringRef, void *, double &); static bool mustQuote(StringRef) { return false; } }; @@ -994,12 +996,11 @@ struct ScalarTraits { template struct ScalarTraits> { - typedef support::detail::packed_endian_specific_integral - endian_type; + using endian_type = + support::detail::packed_endian_specific_integral; - static void output(const endian_type &E, void *Ctx, - llvm::raw_ostream &Stream) { + static void output(const endian_type &E, void *Ctx, raw_ostream &Stream) { ScalarTraits::output(static_cast(E), Ctx, Stream); } @@ -1039,7 +1040,7 @@ struct MappingNormalization { TNorm* operator->() { return BufPtr; } private: - typedef llvm::AlignedCharArrayUnion Storage; + using Storage = AlignedCharArrayUnion; Storage Buffer; IO &io; @@ -1051,9 +1052,8 @@ struct MappingNormalization { // to [de]normalize an object for use with YAML conversion. template struct MappingNormalizationHeap { - MappingNormalizationHeap(IO &i_o, TFinal &Obj, - llvm::BumpPtrAllocator *allocator) - : io(i_o), BufPtr(nullptr), Result(Obj) { + MappingNormalizationHeap(IO &i_o, TFinal &Obj, BumpPtrAllocator *allocator) + : io(i_o), Result(Obj) { if ( io.outputting() ) { BufPtr = new (&Buffer) TNorm(io, Obj); } @@ -1077,11 +1077,11 @@ struct MappingNormalizationHeap { TNorm* operator->() { return BufPtr; } private: - typedef llvm::AlignedCharArrayUnion Storage; + using Storage = AlignedCharArrayUnion; Storage Buffer; IO &io; - TNorm *BufPtr; + TNorm *BufPtr = nullptr; TFinal &Result; }; @@ -1197,10 +1197,10 @@ class Input : public IO { static inline bool classof(const MapHNode *) { return true; } - typedef llvm::StringMap> NameToNode; + using NameToNode = StringMap>; - NameToNode Mapping; - llvm::SmallVector ValidKeys; + NameToNode Mapping; + SmallVector ValidKeys; }; class SequenceHNode : public HNode { @@ -1232,14 +1232,14 @@ class Input : public IO { const Node *getCurrentNode() const; private: - llvm::SourceMgr SrcMgr; // must be before Strm + SourceMgr SrcMgr; // must be before Strm std::unique_ptr Strm; std::unique_ptr TopNode; std::error_code EC; - llvm::BumpPtrAllocator StringAllocator; - llvm::yaml::document_iterator DocIterator; + BumpPtrAllocator StringAllocator; + document_iterator DocIterator; std::vector BitValuesUsed; - HNode *CurrentNode; + HNode *CurrentNode = nullptr; bool ScalarMatchFound; }; @@ -1249,7 +1249,7 @@ class Input : public IO { /// class Output : public IO { public: - Output(llvm::raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70); + Output(raw_ostream &, void *Ctxt = nullptr, int WrapColumn = 70); ~Output() override; /// \brief Set whether or not to output optional values which are equal @@ -1312,17 +1312,17 @@ class Output : public IO { inFlowMapOtherKey }; - llvm::raw_ostream &Out; - int WrapColumn; - SmallVector StateStack; - int Column; - int ColumnAtFlowStart; - int ColumnAtMapFlowStart; - bool NeedBitValueComma; - bool NeedFlowSequenceComma; - bool EnumerationMatchFound; - bool NeedsNewLine; - bool WriteDefaultValues; + raw_ostream &Out; + int WrapColumn; + SmallVector StateStack; + int Column = 0; + int ColumnAtFlowStart = 0; + int ColumnAtMapFlowStart = 0; + bool NeedBitValueComma = false; + bool NeedFlowSequenceComma = false; + bool EnumerationMatchFound = false; + bool NeedsNewLine = false; + bool WriteDefaultValues = false; }; /// YAML I/O does conversion based on types. But often native data types @@ -1345,7 +1345,7 @@ class Output : public IO { bool operator==(const _base &rhs) const { return value == rhs; } \ bool operator<(const _type &rhs) const { return value < rhs.value; } \ _base value; \ - typedef _base BaseType; \ + using BaseType = _base; \ }; /// @@ -1359,29 +1359,29 @@ LLVM_YAML_STRONG_TYPEDEF(uint64_t, Hex64) template<> struct ScalarTraits { - static void output(const Hex8 &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, Hex8 &); + static void output(const Hex8 &, void *, raw_ostream &); + static StringRef input(StringRef, void *, Hex8 &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const Hex16 &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, Hex16 &); + static void output(const Hex16 &, void *, raw_ostream &); + static StringRef input(StringRef, void *, Hex16 &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const Hex32 &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, Hex32 &); + static void output(const Hex32 &, void *, raw_ostream &); + static StringRef input(StringRef, void *, Hex32 &); static bool mustQuote(StringRef) { return false; } }; template<> struct ScalarTraits { - static void output(const Hex64 &, void*, llvm::raw_ostream &); - static StringRef input(StringRef, void*, Hex64 &); + static void output(const Hex64 &, void *, raw_ostream &); + static StringRef input(StringRef, void *, Hex64 &); static bool mustQuote(StringRef) { return false; } }; @@ -1545,8 +1545,10 @@ operator<<(Output &yout, T &seq) { } template struct SequenceTraitsImpl { - typedef typename T::value_type _type; + using _type = typename T::value_type; + static size_t size(IO &io, T &seq) { return seq.size(); } + static _type &element(IO &io, T &seq, size_t index) { if (index >= seq.size()) seq.resize(index + 1); @@ -1556,10 +1558,12 @@ template struct SequenceTraitsImpl { /// Implementation of CustomMappingTraits for std::map. template struct StdMapStringCustomMappingTraitsImpl { - typedef std::map map_type; + using map_type = std::map; + static void inputOne(IO &io, StringRef key, map_type &v) { io.mapRequired(key.str().c_str(), v[key]); } + static void output(IO &io, map_type &v) { for (auto &p : v) io.mapRequired(p.first.c_str(), p.second); @@ -1637,7 +1641,7 @@ template struct StdMapStringCustomMappingTraitsImpl { namespace llvm { \ namespace yaml { \ template <> struct ScalarTraits { \ - static void output(const Type &Value, void *ctx, llvm::raw_ostream &Out); \ + static void output(const Type &Value, void *ctx, raw_ostream &Out); \ static StringRef input(StringRef Scalar, void *ctxt, Type &Value); \ static bool mustQuote(StringRef) { return MustQuote; } \ }; \ diff --git a/contrib/llvm/include/llvm/TableGen/Main.h b/contrib/llvm/include/llvm/TableGen/Main.h index ca8c95cb6da2..670572dc8103 100644 --- a/contrib/llvm/include/llvm/TableGen/Main.h +++ b/contrib/llvm/include/llvm/TableGen/Main.h @@ -19,8 +19,8 @@ namespace llvm { class raw_ostream; class RecordKeeper; -/// \brief Perform the action using Records, and write output to OS. -/// \returns true on error, false otherwise +/// Perform the action using Records, and write output to OS. +/// Returns true on error, false otherwise. using TableGenMainFn = bool (raw_ostream &OS, RecordKeeper &Records); int TableGenMain(char *argv0, TableGenMainFn *MainFn); diff --git a/contrib/llvm/include/llvm/Target/GenericOpcodes.td b/contrib/llvm/include/llvm/Target/GenericOpcodes.td index de3796cd4ee5..9593d8bd7edb 100644 --- a/contrib/llvm/include/llvm/Target/GenericOpcodes.td +++ b/contrib/llvm/include/llvm/Target/GenericOpcodes.td @@ -386,6 +386,15 @@ def G_FMUL : Instruction { let isCommutable = 1; } +// Generic fused multiply-add instruction. +// Behaves like llvm fma intrinsic ie src1 * src2 + src3 +def G_FMA : Instruction { + let OutOperandList = (outs type0:$dst); + let InOperandList = (ins type0:$src1, type0:$src2, type0:$src3); + let hasSideEffects = 0; + let isCommutable = 0; +} + // Generic FP division. def G_FDIV : Instruction { let OutOperandList = (outs type0:$dst); @@ -456,15 +465,6 @@ def G_INSERT : Instruction { let hasSideEffects = 0; } -// Combine a sequence of generic vregs into a single larger value (starting at -// bit 0). Essentially a G_INSERT where $src is an IMPLICIT_DEF, but it's so -// important to legalization it probably deserves its own instruction. -def G_SEQUENCE : Instruction { - let OutOperandList = (outs type0:$dst); - let InOperandList = (ins variable_ops); - let hasSideEffects = 0; -} - def G_MERGE_VALUES : Instruction { let OutOperandList = (outs type0:$dst); let InOperandList = (ins variable_ops); diff --git a/contrib/llvm/include/llvm/Target/TargetInstrInfo.h b/contrib/llvm/include/llvm/Target/TargetInstrInfo.h index 7595d4339810..2fc3ec996e7f 100644 --- a/contrib/llvm/include/llvm/Target/TargetInstrInfo.h +++ b/contrib/llvm/include/llvm/Target/TargetInstrInfo.h @@ -1,4 +1,4 @@ -//===-- llvm/Target/TargetInstrInfo.h - Instruction Info --------*- C++ -*-===// +//===- llvm/Target/TargetInstrInfo.h - Instruction Info ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -14,36 +14,46 @@ #ifndef LLVM_TARGET_TARGETINSTRINFO_H #define LLVM_TARGET_TARGETINSTRINFO_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/None.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineCombinerPattern.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineOperand.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/BranchProbability.h" -#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include +#include +#include namespace llvm { +class DFAPacketizer; class InstrItineraryData; class LiveVariables; -class MCAsmInfo; class MachineMemOperand; class MachineRegisterInfo; -class MDNode; +class MCAsmInfo; class MCInst; struct MCSchedModel; -class MCSymbolRefExpr; -class SDNode; -class ScheduleHazardRecognizer; -class SelectionDAG; +class Module; class ScheduleDAG; +class ScheduleHazardRecognizer; +class SDNode; +class SelectionDAG; +class RegScavenger; class TargetRegisterClass; class TargetRegisterInfo; -class TargetSubtargetInfo; class TargetSchedModel; -class DFAPacketizer; +class TargetSubtargetInfo; template class SmallVectorImpl; @@ -52,8 +62,6 @@ template class SmallVectorImpl; /// TargetInstrInfo - Interface to description of machine instruction set /// class TargetInstrInfo : public MCInstrInfo { - TargetInstrInfo(const TargetInstrInfo &) = delete; - void operator=(const TargetInstrInfo &) = delete; public: TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u) @@ -61,7 +69,8 @@ class TargetInstrInfo : public MCInstrInfo { CallFrameDestroyOpcode(CFDestroyOpcode), CatchRetOpcode(CatchRetOpcode), ReturnOpcode(ReturnOpcode) {} - + TargetInstrInfo(const TargetInstrInfo &) = delete; + TargetInstrInfo &operator=(const TargetInstrInfo &) = delete; virtual ~TargetInstrInfo(); static bool isGenericOpcode(unsigned Opc) { @@ -396,14 +405,17 @@ class TargetInstrInfo : public MCInstrInfo { struct RegSubRegPair { unsigned Reg; unsigned SubReg; + RegSubRegPair(unsigned Reg = 0, unsigned SubReg = 0) : Reg(Reg), SubReg(SubReg) {} }; + /// A pair composed of a pair of a register and a sub-register index, /// and another sub-register index. /// Used to give some type checking when modeling Reg:SubReg1, SubReg2. struct RegSubRegPairAndIdx : RegSubRegPair { unsigned SubIdx; + RegSubRegPairAndIdx(unsigned Reg = 0, unsigned SubReg = 0, unsigned SubIdx = 0) : RegSubRegPair(Reg, SubReg), SubIdx(SubIdx) {} @@ -469,7 +481,6 @@ class TargetInstrInfo : public MCInstrInfo { RegSubRegPair &BaseReg, RegSubRegPairAndIdx &InsertedReg) const; - /// Return true if two machine instructions would produce identical values. /// By default, this is only true when the two instructions /// are deemed identical except for defs. If this function is called when the @@ -551,23 +562,19 @@ class TargetInstrInfo : public MCInstrInfo { PRED_INVALID // Sentinel value }; - ComparePredicate Predicate; - MachineOperand LHS; - MachineOperand RHS; - MachineBasicBlock *TrueDest; - MachineBasicBlock *FalseDest; - MachineInstr *ConditionDef; + ComparePredicate Predicate = PRED_INVALID; + MachineOperand LHS = MachineOperand::CreateImm(0); + MachineOperand RHS = MachineOperand::CreateImm(0); + MachineBasicBlock *TrueDest = nullptr; + MachineBasicBlock *FalseDest = nullptr; + MachineInstr *ConditionDef = nullptr; /// SingleUseCondition is true if ConditionDef is dead except for the /// branch(es) at the end of the basic block. /// - bool SingleUseCondition; + bool SingleUseCondition = false; - explicit MachineBranchPredicate() - : Predicate(PRED_INVALID), LHS(MachineOperand::CreateImm(0)), - RHS(MachineOperand::CreateImm(0)), TrueDest(nullptr), - FalseDest(nullptr), ConditionDef(nullptr), SingleUseCondition(false) { - } + explicit MachineBranchPredicate() = default; }; /// Analyze the branching code at the end of MBB and parse it into the @@ -1117,7 +1124,6 @@ class TargetInstrInfo : public MCInstrInfo { virtual void insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const; - /// Return the noop instruction to use for a noop. virtual void getNoop(MCInst &NopInst) const; @@ -1621,16 +1627,18 @@ class TargetInstrInfo : public MCInstrInfo { /// \brief Provide DenseMapInfo for TargetInstrInfo::RegSubRegPair. template<> struct DenseMapInfo { - typedef DenseMapInfo RegInfo; + using RegInfo = DenseMapInfo; static inline TargetInstrInfo::RegSubRegPair getEmptyKey() { return TargetInstrInfo::RegSubRegPair(RegInfo::getEmptyKey(), RegInfo::getEmptyKey()); } + static inline TargetInstrInfo::RegSubRegPair getTombstoneKey() { return TargetInstrInfo::RegSubRegPair(RegInfo::getTombstoneKey(), RegInfo::getTombstoneKey()); } + /// \brief Reuse getHashValue implementation from /// std::pair. static unsigned getHashValue(const TargetInstrInfo::RegSubRegPair &Val) { @@ -1638,6 +1646,7 @@ struct DenseMapInfo { std::make_pair(Val.Reg, Val.SubReg); return DenseMapInfo>::getHashValue(PairVal); } + static bool isEqual(const TargetInstrInfo::RegSubRegPair &LHS, const TargetInstrInfo::RegSubRegPair &RHS) { return RegInfo::isEqual(LHS.Reg, RHS.Reg) && diff --git a/contrib/llvm/include/llvm/Target/TargetLowering.h b/contrib/llvm/include/llvm/Target/TargetLowering.h index a9d67228d205..22dab2e82828 100644 --- a/contrib/llvm/include/llvm/Target/TargetLowering.h +++ b/contrib/llvm/include/llvm/Target/TargetLowering.h @@ -1,4 +1,4 @@ -//===-- llvm/Target/TargetLowering.h - Target Lowering Info -----*- C++ -*-===// +//===- llvm/Target/TargetLowering.h - Target Lowering Info ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,6 +23,7 @@ #ifndef LLVM_TARGET_TARGETLOWERING_H #define LLVM_TARGET_TARGETLOWERING_H +#include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" @@ -40,6 +41,7 @@ #include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instruction.h" @@ -66,10 +68,13 @@ namespace llvm { class BranchProbability; class CCState; class CCValAssign; +class Constant; class FastISel; class FunctionLoweringInfo; +class GlobalValue; class IntrinsicInst; struct KnownBits; +class LLVMContext; class MachineBasicBlock; class MachineFunction; class MachineInstr; @@ -78,6 +83,7 @@ class MachineLoop; class MachineRegisterInfo; class MCContext; class MCExpr; +class Module; class TargetRegisterClass; class TargetLibraryInfo; class TargetRegisterInfo; @@ -127,7 +133,7 @@ class TargetLoweringBase { /// LegalizeKind holds the legalization kind that needs to happen to EVT /// in order to type-legalize it. - typedef std::pair LegalizeKind; + using LegalizeKind = std::pair; /// Enum that describes how the target represents true/false values. enum BooleanContent { @@ -189,7 +195,7 @@ class TargetLoweringBase { void setAttributes(ImmutableCallSite *CS, unsigned ArgIdx); }; - typedef std::vector ArgListTy; + using ArgListTy = std::vector; virtual void markLibCallAttributes(MachineFunction *MF, unsigned CC, ArgListTy &Args) const {}; @@ -211,8 +217,8 @@ class TargetLoweringBase { /// NOTE: The TargetMachine owns TLOF. explicit TargetLoweringBase(const TargetMachine &TM); - TargetLoweringBase(const TargetLoweringBase&) = delete; - void operator=(const TargetLoweringBase&) = delete; + TargetLoweringBase(const TargetLoweringBase &) = delete; + TargetLoweringBase &operator=(const TargetLoweringBase &) = delete; virtual ~TargetLoweringBase() = default; protected: @@ -404,6 +410,10 @@ class TargetLoweringBase { return false; } + /// Should we merge stores after Legalization (generally + /// better quality) or before (simpler) + virtual bool mergeStoresAfterLegalization() const { return false; } + /// Returns if it's reasonable to merge stores to MemVT size. virtual bool canMergeStoresTo(unsigned AddressSpace, EVT MemVT) const { return true; @@ -1364,6 +1374,12 @@ class TargetLoweringBase { /// Returns the target-specific address of the unsafe stack pointer. virtual Value *getSafeStackPointerLocation(IRBuilder<> &IRB) const; + /// Returns the name of the symbol used to emit stack probes or the empty + /// string if not applicable. + virtual StringRef getStackProbeSymbolName(MachineFunction &MF) const { + return ""; + } + /// Returns true if a cast between SrcAS and DestAS is a noop. virtual bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const { return false; @@ -2455,8 +2471,8 @@ class TargetLowering : public TargetLoweringBase { public: struct DAGCombinerInfo; - TargetLowering(const TargetLowering&) = delete; - void operator=(const TargetLowering&) = delete; + TargetLowering(const TargetLowering &) = delete; + TargetLowering &operator=(const TargetLowering &) = delete; /// NOTE: The TargetMachine owns TLOF. explicit TargetLowering(const TargetMachine &TM); @@ -2772,7 +2788,6 @@ class TargetLowering : public TargetLoweringBase { /// described by the Ins array, into the specified DAG. The implementation /// should fill in the InVals array with legal-type argument values, and /// return the resulting token chain value. - /// virtual SDValue LowerFormalArguments( SDValue /*Chain*/, CallingConv::ID /*CallConv*/, bool /*isVarArg*/, const SmallVectorImpl & /*Ins*/, const SDLoc & /*dl*/, @@ -2786,7 +2801,7 @@ class TargetLowering : public TargetLoweringBase { /// implementation. struct CallLoweringInfo { SDValue Chain; - Type *RetTy; + Type *RetTy = nullptr; bool RetSExt : 1; bool RetZExt : 1; bool IsVarArg : 1; @@ -2794,30 +2809,28 @@ class TargetLowering : public TargetLoweringBase { bool DoesNotReturn : 1; bool IsReturnValueUsed : 1; bool IsConvergent : 1; + bool IsPatchPoint : 1; // IsTailCall should be modified by implementations of // TargetLowering::LowerCall that perform tail call conversions. - bool IsTailCall; + bool IsTailCall = false; - unsigned NumFixedArgs; - CallingConv::ID CallConv; + unsigned NumFixedArgs = -1; + CallingConv::ID CallConv = CallingConv::C; SDValue Callee; ArgListTy Args; SelectionDAG &DAG; SDLoc DL; - ImmutableCallSite *CS; - bool IsPatchPoint; + ImmutableCallSite *CS = nullptr; SmallVector Outs; SmallVector OutVals; SmallVector Ins; SmallVector InVals; CallLoweringInfo(SelectionDAG &DAG) - : RetTy(nullptr), RetSExt(false), RetZExt(false), IsVarArg(false), - IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true), - IsConvergent(false), IsTailCall(false), NumFixedArgs(-1), - CallConv(CallingConv::C), DAG(DAG), CS(nullptr), IsPatchPoint(false) { - } + : RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false), + DoesNotReturn(false), IsReturnValueUsed(true), IsConvergent(false), + IsPatchPoint(false), DAG(DAG) {} CallLoweringInfo &setDebugLoc(const SDLoc &dl) { DL = dl; @@ -3091,7 +3104,6 @@ class TargetLowering : public TargetLoweringBase { return nullptr; } - bool verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const; @@ -3140,15 +3152,19 @@ class TargetLowering : public TargetLoweringBase { /// Information about the constraint code, e.g. Register, RegisterClass, /// Memory, Other, Unknown. - TargetLowering::ConstraintType ConstraintType; + TargetLowering::ConstraintType ConstraintType = TargetLowering::C_Unknown; /// If this is the result output operand or a clobber, this is null, /// otherwise it is the incoming operand to the CallInst. This gets /// modified as the asm is processed. - Value *CallOperandVal; + Value *CallOperandVal = nullptr; /// The ValueType for the operand value. - MVT ConstraintVT; + MVT ConstraintVT = MVT::Other; + + /// Copy constructor for copying from a ConstraintInfo. + AsmOperandInfo(InlineAsm::ConstraintInfo Info) + : InlineAsm::ConstraintInfo(std::move(Info)) {} /// Return true of this is an input operand that is a matching constraint /// like "4". @@ -3157,15 +3173,9 @@ class TargetLowering : public TargetLoweringBase { /// If this is an input matching constraint, this method returns the output /// operand it matches. unsigned getMatchedOperand() const; - - /// Copy constructor for copying from a ConstraintInfo. - AsmOperandInfo(InlineAsm::ConstraintInfo Info) - : InlineAsm::ConstraintInfo(std::move(Info)), - ConstraintType(TargetLowering::C_Unknown), CallOperandVal(nullptr), - ConstraintVT(MVT::Other) {} }; - typedef std::vector AsmOperandInfoVector; + using AsmOperandInfoVector = std::vector; /// Split up the constraint string from the inline assembly value into the /// specific constraints and their prefixes, and also tie in the associated diff --git a/contrib/llvm/include/llvm/Target/TargetOpcodes.def b/contrib/llvm/include/llvm/Target/TargetOpcodes.def index 36764249632d..836b11cf89c6 100644 --- a/contrib/llvm/include/llvm/Target/TargetOpcodes.def +++ b/contrib/llvm/include/llvm/Target/TargetOpcodes.def @@ -241,8 +241,6 @@ HANDLE_TARGET_OPCODE(G_INSERT) /// Generic instruction to paste a variable number of components together into a /// larger register. -HANDLE_TARGET_OPCODE(G_SEQUENCE) - HANDLE_TARGET_OPCODE(G_MERGE_VALUES) /// Generic pointer to int conversion. @@ -359,6 +357,9 @@ HANDLE_TARGET_OPCODE(G_FSUB) /// Generic FP multiplication. HANDLE_TARGET_OPCODE(G_FMUL) +/// Generic FMA multiplication. Behaves like llvm fma intrinsic +HANDLE_TARGET_OPCODE(G_FMA) + /// Generic FP division. HANDLE_TARGET_OPCODE(G_FDIV) diff --git a/contrib/llvm/include/llvm/Target/TargetRegisterInfo.h b/contrib/llvm/include/llvm/Target/TargetRegisterInfo.h index 86ad8ad53052..b6839dad106f 100644 --- a/contrib/llvm/include/llvm/Target/TargetRegisterInfo.h +++ b/contrib/llvm/include/llvm/Target/TargetRegisterInfo.h @@ -1,4 +1,4 @@ -//=== Target/TargetRegisterInfo.h - Target Register Information -*- C++ -*-===// +//==- Target/TargetRegisterInfo.h - Target Register Information --*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -17,30 +17,35 @@ #define LLVM_TARGET_TARGETREGISTERINFO_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/IR/CallingConv.h" +#include "llvm/MC/LaneBitmask.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/Printable.h" #include +#include #include namespace llvm { class BitVector; -class MachineFunction; -class RegScavenger; -template class SmallVectorImpl; -class VirtRegMap; -class raw_ostream; class LiveRegMatrix; +class MachineFunction; +class MachineInstr; +class RegScavenger; +class VirtRegMap; class TargetRegisterClass { public: - typedef const MCPhysReg* iterator; - typedef const MCPhysReg* const_iterator; - typedef const TargetRegisterClass* const * sc_iterator; + using iterator = const MCPhysReg *; + using const_iterator = const MCPhysReg *; + using sc_iterator = const TargetRegisterClass* const *; // Instance variables filled by tablegen, do not use! const MCRegisterClass *MC; @@ -151,7 +156,6 @@ class TargetRegisterClass { /// There exists SuperRC where: /// For all Reg in SuperRC: /// this->contains(Reg:Idx) - /// const uint16_t *getSuperRegIndices() const { return SuperRegIndices; } @@ -182,7 +186,6 @@ class TargetRegisterClass { /// other criteria. /// /// By default, this method returns all registers in the class. - /// ArrayRef getRawAllocationOrder(const MachineFunction &MF) const { return OrderFunc ? OrderFunc(MF) : makeArrayRef(begin(), getNumRegs()); } @@ -217,8 +220,9 @@ struct RegClassWeight { /// class TargetRegisterInfo : public MCRegisterInfo { public: - typedef const TargetRegisterClass * const * regclass_iterator; - typedef const MVT::SimpleValueType* vt_iterator; + using regclass_iterator = const TargetRegisterClass * const *; + using vt_iterator = const MVT::SimpleValueType *; + private: const TargetRegisterInfoDesc *InfoDesc; // Extra desc array for codegen const char *const *SubRegIndexNames; // Names of subreg indexes. @@ -236,8 +240,8 @@ class TargetRegisterInfo : public MCRegisterInfo { const LaneBitmask *SRILaneMasks, LaneBitmask CoveringLanes); virtual ~TargetRegisterInfo(); -public: +public: // Register numbers can represent physical registers, virtual registers, and // sometimes stack slots. The unsigned values are divided into these ranges: // @@ -510,7 +514,7 @@ class TargetRegisterInfo : public MCRegisterInfo { /// Prior to adding the live-out mask to a stackmap or patchpoint /// instruction, provide the target the opportunity to adjust it (mainly to /// remove pseudo-registers that should be ignored). - virtual void adjustStackMapLiveOutMask(uint32_t *Mask) const { } + virtual void adjustStackMapLiveOutMask(uint32_t *Mask) const {} /// Return a super-register of the specified register /// Reg so its sub-register of index SubIdx is Reg. @@ -568,7 +572,6 @@ class TargetRegisterInfo : public MCRegisterInfo { /// The ARM register Q0 has two D subregs dsub_0:D0 and dsub_1:D1. It also has /// ssub_0:S0 - ssub_3:S3 subregs. /// If you compose subreg indices dsub_1, ssub_0 you get ssub_2. - /// unsigned composeSubRegIndices(unsigned a, unsigned b) const { if (!a) return b; if (!b) return a; @@ -643,7 +646,6 @@ class TargetRegisterInfo : public MCRegisterInfo { /// corresponding argument register class. /// /// The function returns NULL if no register class can be found. - /// const TargetRegisterClass* getCommonSuperRegClass(const TargetRegisterClass *RCA, unsigned SubA, const TargetRegisterClass *RCB, unsigned SubB, @@ -654,7 +656,6 @@ class TargetRegisterInfo : public MCRegisterInfo { // /// Register class iterators - /// regclass_iterator regclass_begin() const { return RegClassBegin; } regclass_iterator regclass_end() const { return RegClassEnd; } iterator_range regclasses() const { @@ -909,7 +910,6 @@ class TargetRegisterInfo : public MCRegisterInfo { /// Return true if the register was spilled, false otherwise. /// If this function does not spill the register, the scavenger /// will instead spill it to the emergency spill slot. - /// virtual bool saveScavengerRegister(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineBasicBlock::iterator &UseMI, @@ -968,7 +968,6 @@ class TargetRegisterInfo : public MCRegisterInfo { ArrayRef Exceptions = ArrayRef()) const; }; - //===----------------------------------------------------------------------===// // SuperRegClassIterator //===----------------------------------------------------------------------===// @@ -987,7 +986,7 @@ class TargetRegisterInfo : public MCRegisterInfo { // class SuperRegClassIterator { const unsigned RCMaskWords; - unsigned SubReg; + unsigned SubReg = 0; const uint16_t *Idx; const uint32_t *Mask; @@ -998,9 +997,7 @@ class SuperRegClassIterator { const TargetRegisterInfo *TRI, bool IncludeSelf = false) : RCMaskWords((TRI->getNumRegClasses() + 31) / 32), - SubReg(0), - Idx(RC->getSuperRegIndices()), - Mask(RC->getSubClassMask()) { + Idx(RC->getSuperRegIndices()), Mask(RC->getSubClassMask()) { if (!IncludeSelf) ++*this; } @@ -1039,12 +1036,12 @@ class BitMaskClassIterator { /// Base index of CurrentChunk. /// In other words, the number of bit we read to get at the /// beginning of that chunck. - unsigned Base; + unsigned Base = 0; /// Adjust base index of CurrentChunk. /// Base index + how many bit we read within CurrentChunk. - unsigned Idx; + unsigned Idx = 0; /// Current register class ID. - unsigned ID; + unsigned ID = 0; /// Mask we are iterating over. const uint32_t *Mask; /// Current chunk of the Mask we are traversing. @@ -1098,8 +1095,7 @@ class BitMaskClassIterator { /// /// \pre \p Mask != nullptr BitMaskClassIterator(const uint32_t *Mask, const TargetRegisterInfo &TRI) - : NumRegClasses(TRI.getNumRegClasses()), Base(0), Idx(0), ID(0), - Mask(Mask), CurrentChunk(*Mask) { + : NumRegClasses(TRI.getNumRegClasses()), Mask(Mask), CurrentChunk(*Mask) { // Move to the first ID. moveToNextID(); } @@ -1151,6 +1147,6 @@ Printable PrintRegUnit(unsigned Unit, const TargetRegisterInfo *TRI); /// registers on a \ref raw_ostream. Printable PrintVRegOrUnit(unsigned VRegOrUnit, const TargetRegisterInfo *TRI); -} // End llvm namespace +} // end namespace llvm -#endif +#endif // LLVM_TARGET_TARGETREGISTERINFO_H diff --git a/contrib/llvm/include/llvm/Target/TargetSubtargetInfo.h b/contrib/llvm/include/llvm/Target/TargetSubtargetInfo.h index 9cb07a5c6dae..9440c56dcf17 100644 --- a/contrib/llvm/include/llvm/Target/TargetSubtargetInfo.h +++ b/contrib/llvm/include/llvm/Target/TargetSubtargetInfo.h @@ -1,4 +1,4 @@ -//==-- llvm/Target/TargetSubtargetInfo.h - Target Information ----*- C++ -*-==// +//===- llvm/Target/TargetSubtargetInfo.h - Target Information ---*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -20,21 +20,29 @@ #include "llvm/CodeGen/PBQPRAConstraint.h" #include "llvm/CodeGen/ScheduleDAGMutation.h" #include "llvm/CodeGen/SchedulerRegistry.h" -#include "llvm/MC/MCInst.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/CodeGen.h" #include #include + namespace llvm { class CallLowering; +class InstrItineraryData; +struct InstrStage; class InstructionSelector; class LegalizerInfo; class MachineInstr; +struct MachineSchedPolicy; +struct MCReadAdvanceEntry; +struct MCWriteLatencyEntry; +struct MCWriteProcResEntry; class RegisterBankInfo; class SDep; class SelectionDAGTargetInfo; +struct SubtargetFeatureKV; +struct SubtargetInfoKV; class SUnit; class TargetFrameLowering; class TargetInstrInfo; @@ -42,7 +50,7 @@ class TargetLowering; class TargetRegisterClass; class TargetRegisterInfo; class TargetSchedModel; -struct MachineSchedPolicy; +class Triple; //===----------------------------------------------------------------------===// /// @@ -64,13 +72,13 @@ class TargetSubtargetInfo : public MCSubtargetInfo { public: // AntiDepBreakMode - Type of anti-dependence breaking that should // be performed before post-RA scheduling. - typedef enum { ANTIDEP_NONE, ANTIDEP_CRITICAL, ANTIDEP_ALL } AntiDepBreakMode; - typedef SmallVectorImpl RegClassVector; + using AntiDepBreakMode = enum { ANTIDEP_NONE, ANTIDEP_CRITICAL, ANTIDEP_ALL }; + using RegClassVector = SmallVectorImpl; TargetSubtargetInfo() = delete; TargetSubtargetInfo(const TargetSubtargetInfo &) = delete; - void operator=(const TargetSubtargetInfo &) = delete; - virtual ~TargetSubtargetInfo(); + TargetSubtargetInfo &operator=(const TargetSubtargetInfo &) = delete; + ~TargetSubtargetInfo() override; virtual bool isXRaySupported() const { return false; } @@ -112,7 +120,6 @@ class TargetSubtargetInfo : public MCSubtargetInfo { /// getRegisterInfo - If register information is available, return it. If /// not, return null. - /// virtual const TargetRegisterInfo *getRegisterInfo() const { return nullptr; } /// If the information for the register banks is available, return it. @@ -121,7 +128,6 @@ class TargetSubtargetInfo : public MCSubtargetInfo { /// getInstrItineraryData - Returns instruction itinerary data for the target /// or specific subtarget. - /// virtual const InstrItineraryData *getInstrItineraryData() const { return nullptr; } diff --git a/contrib/llvm/include/llvm/Testing/Support/Error.h b/contrib/llvm/include/llvm/Testing/Support/Error.h index d52752901593..f23d289266ad 100644 --- a/contrib/llvm/include/llvm/Testing/Support/Error.h +++ b/contrib/llvm/include/llvm/Testing/Support/Error.h @@ -30,8 +30,8 @@ template ExpectedHolder TakeExpected(Expected &Exp) { return Result; } -template ExpectedHolder TakeExpected(const Expected &Exp) { - return TakeExpected(const_cast &>(Exp)); +template ExpectedHolder TakeExpected(Expected &&Exp) { + return TakeExpected(Exp); } } // namespace detail diff --git a/contrib/llvm/include/llvm/Transforms/IPO/PassManagerBuilder.h b/contrib/llvm/include/llvm/Transforms/IPO/PassManagerBuilder.h index 247382c35eeb..db4bfb15f51d 100644 --- a/contrib/llvm/include/llvm/Transforms/IPO/PassManagerBuilder.h +++ b/contrib/llvm/include/llvm/Transforms/IPO/PassManagerBuilder.h @@ -149,7 +149,6 @@ class PassManagerBuilder { bool SLPVectorize; bool LoopVectorize; bool RerollLoops; - bool LoadCombine; bool NewGVN; bool DisableGVNLoadPRE; bool VerifyInput; diff --git a/contrib/llvm/include/llvm/Transforms/InstrProfiling.h b/contrib/llvm/include/llvm/Transforms/InstrProfiling.h index 65e69761badd..0fe6ad5eeac7 100644 --- a/contrib/llvm/include/llvm/Transforms/InstrProfiling.h +++ b/contrib/llvm/include/llvm/Transforms/InstrProfiling.h @@ -28,6 +28,7 @@ namespace llvm { class TargetLibraryInfo; +using LoadStorePair = std::pair; /// Instrumentation based profiling lowering pass. This pass lowers /// the profile instrumented code generated by FE or the IR based @@ -60,11 +61,26 @@ class InstrProfiling : public PassInfoMixin { GlobalVariable *NamesVar; size_t NamesSize; + // vector of counter load/store pairs to be register promoted. + std::vector PromotionCandidates; + // The start value of precise value profile range for memory intrinsic sizes. int64_t MemOPSizeRangeStart; // The end value of precise value profile range for memory intrinsic sizes. int64_t MemOPSizeRangeLast; + int64_t TotalCountersPromoted = 0; + + /// Lower instrumentation intrinsics in the function. Returns true if there + /// any lowering. + bool lowerIntrinsics(Function *F); + + /// Register-promote counter loads and stores in loops. + void promoteCounterLoadStores(Function *F); + + /// Returns true if profile counter update register promotion is enabled. + bool isCounterPromotionEnabled() const; + /// Count the number of instrumented value sites for the function. void computeNumValueSiteCounts(InstrProfValueProfileInst *Ins); diff --git a/contrib/llvm/include/llvm/Transforms/Instrumentation.h b/contrib/llvm/include/llvm/Transforms/Instrumentation.h index b6c6c091631d..f2fc6dc8dad5 100644 --- a/contrib/llvm/include/llvm/Transforms/Instrumentation.h +++ b/contrib/llvm/include/llvm/Transforms/Instrumentation.h @@ -116,6 +116,9 @@ struct InstrProfOptions { // Add the 'noredzone' attribute to added runtime library calls. bool NoRedZone = false; + // Do counter register promotion + bool DoCounterPromotion = false; + // Name of the profile file to use as output std::string InstrProfileOutput; diff --git a/contrib/llvm/include/llvm/Transforms/Scalar.h b/contrib/llvm/include/llvm/Transforms/Scalar.h index 856c288a071f..1913a9d5da02 100644 --- a/contrib/llvm/include/llvm/Transforms/Scalar.h +++ b/contrib/llvm/include/llvm/Transforms/Scalar.h @@ -485,12 +485,6 @@ FunctionPass *createSpeculativeExecutionPass(); // TargetTransformInfo::hasBranchDivergence() is true. FunctionPass *createSpeculativeExecutionIfHasBranchDivergencePass(); -//===----------------------------------------------------------------------===// -// -// LoadCombine - Combine loads into bigger loads. -// -BasicBlockPass *createLoadCombinePass(); - //===----------------------------------------------------------------------===// // // StraightLineStrengthReduce - This pass strength-reduces some certain diff --git a/contrib/llvm/include/llvm/Transforms/Scalar/GVN.h b/contrib/llvm/include/llvm/Transforms/Scalar/GVN.h index 589aaaca02fe..4c585a20021c 100644 --- a/contrib/llvm/include/llvm/Transforms/Scalar/GVN.h +++ b/contrib/llvm/include/llvm/Transforms/Scalar/GVN.h @@ -68,6 +68,21 @@ class GVN : public PassInfoMixin { class ValueTable { DenseMap valueNumbering; DenseMap expressionNumbering; + + // Expressions is the vector of Expression. ExprIdx is the mapping from + // value number to the index of Expression in Expressions. We use it + // instead of a DenseMap because filling such mapping is faster than + // filling a DenseMap and the compile time is a little better. + uint32_t nextExprNumber; + std::vector Expressions; + std::vector ExprIdx; + // Value number to PHINode mapping. Used for phi-translate in scalarpre. + DenseMap NumberingPhi; + // Cache for phi-translate in scalarpre. + typedef DenseMap, uint32_t> + PhiTranslateMap; + PhiTranslateMap PhiTranslateTable; + AliasAnalysis *AA; MemoryDependenceResults *MD; DominatorTree *DT; @@ -79,6 +94,10 @@ class GVN : public PassInfoMixin { Value *LHS, Value *RHS); Expression createExtractvalueExpr(ExtractValueInst *EI); uint32_t lookupOrAddCall(CallInst *C); + uint32_t phiTranslateImpl(const BasicBlock *BB, const BasicBlock *PhiBlock, + uint32_t Num, GVN &Gvn); + std::pair assignExpNewValueNum(Expression &exp); + bool areAllValsInBB(uint32_t num, const BasicBlock *BB, GVN &Gvn); public: ValueTable(); @@ -87,9 +106,11 @@ class GVN : public PassInfoMixin { ~ValueTable(); uint32_t lookupOrAdd(Value *V); - uint32_t lookup(Value *V) const; + uint32_t lookup(Value *V, bool Verify = true) const; uint32_t lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Pred, Value *LHS, Value *RHS); + uint32_t phiTranslate(const BasicBlock *BB, const BasicBlock *PhiBlock, + uint32_t Num, GVN &Gvn); bool exists(Value *V) const; void add(Value *V, uint32_t num); void clear(); @@ -131,6 +152,10 @@ class GVN : public PassInfoMixin { SmallMapVector ReplaceWithConstMap; SmallVector InstrsToErase; + // Map the block to reversed postorder traversal number. It is used to + // find back edge easily. + DenseMap BlockRPONumber; + typedef SmallVector LoadDepVect; typedef SmallVector AvailValInBlkVect; typedef SmallVector UnavailBlkVect; @@ -209,12 +234,12 @@ class GVN : public PassInfoMixin { // Other helper routines bool processInstruction(Instruction *I); bool processBlock(BasicBlock *BB); - void dump(DenseMap &d); + void dump(DenseMap &d) const; bool iterateOnFunction(Function &F); bool performPRE(Function &F); bool performScalarPRE(Instruction *I); bool performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred, - unsigned int ValNo); + BasicBlock *Curr, unsigned int ValNo); Value *findLeader(const BasicBlock *BB, uint32_t num); void cleanupGlobalSets(); void verifyRemoved(const Instruction *I) const; @@ -226,6 +251,7 @@ class GVN : public PassInfoMixin { bool processFoldableCondBr(BranchInst *BI); void addDeadBlock(BasicBlock *BB); void assignValNumForDeadCode(); + void assignBlockRPONumber(Function &F); }; /// Create a legacy GVN pass. This also allows parameterizing whether or not diff --git a/contrib/llvm/include/llvm/Transforms/Scalar/Reassociate.h b/contrib/llvm/include/llvm/Transforms/Scalar/Reassociate.h index 7b68b4489306..a30a7176baa8 100644 --- a/contrib/llvm/include/llvm/Transforms/Scalar/Reassociate.h +++ b/contrib/llvm/include/llvm/Transforms/Scalar/Reassociate.h @@ -82,8 +82,6 @@ class ReassociatePass : public PassInfoMixin { bool CombineXorOpnd(Instruction *I, reassociate::XorOpnd *Opnd1, reassociate::XorOpnd *Opnd2, APInt &ConstOpnd, Value *&Res); - bool collectMultiplyFactors(SmallVectorImpl &Ops, - SmallVectorImpl &Factors); Value *buildMinimalMultiplyDAG(IRBuilder<> &Builder, SmallVectorImpl &Factors); Value *OptimizeMul(BinaryOperator *I, diff --git a/contrib/llvm/include/llvm/Transforms/Utils/Local.h b/contrib/llvm/include/llvm/Transforms/Utils/Local.h index 8fed292e77a3..30b27616cd98 100644 --- a/contrib/llvm/include/llvm/Transforms/Utils/Local.h +++ b/contrib/llvm/include/llvm/Transforms/Utils/Local.h @@ -380,6 +380,19 @@ unsigned replaceDominatedUsesWith(Value *From, Value *To, DominatorTree &DT, /// during lowering by the GC infrastructure. bool callsGCLeafFunction(ImmutableCallSite CS); +/// Copy a nonnull metadata node to a new load instruction. +/// +/// This handles mapping it to range metadata if the new load is an integer +/// load instead of a pointer load. +void copyNonnullMetadata(const LoadInst &OldLI, MDNode *N, LoadInst &NewLI); + +/// Copy a range metadata node to a new load instruction. +/// +/// This handles mapping it to nonnull metadata if the new load is a pointer +/// load instead of an integer load and the range doesn't cover null. +void copyRangeMetadata(const DataLayout &DL, const LoadInst &OldLI, MDNode *N, + LoadInst &NewLI); + //===----------------------------------------------------------------------===// // Intrinsic pattern matching // diff --git a/contrib/llvm/include/llvm/Transforms/Utils/LoopUtils.h b/contrib/llvm/include/llvm/Transforms/Utils/LoopUtils.h index 561f94880624..0397eb95e763 100644 --- a/contrib/llvm/include/llvm/Transforms/Utils/LoopUtils.h +++ b/contrib/llvm/include/llvm/Transforms/Utils/LoopUtils.h @@ -362,6 +362,14 @@ class InductionDescriptor { BasicBlock *InsertPreheaderForLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, bool PreserveLCSSA); +/// Ensure that all exit blocks of the loop are dedicated exits. +/// +/// For any loop exit block with non-loop predecessors, we split the loop +/// predecessors to use a dedicated loop exit block. We update the dominator +/// tree and loop info if provided, and will preserve LCSSA if requested. +bool formDedicatedExitBlocks(Loop *L, DominatorTree *DT, LoopInfo *LI, + bool PreserveLCSSA); + /// Ensures LCSSA form for every instruction from the Worklist in the scope of /// innermost containing loop. /// diff --git a/contrib/llvm/include/llvm/Transforms/Utils/OrderedInstructions.h b/contrib/llvm/include/llvm/Transforms/Utils/OrderedInstructions.h index e043ff39a998..64c6bcb68b18 100644 --- a/contrib/llvm/include/llvm/Transforms/Utils/OrderedInstructions.h +++ b/contrib/llvm/include/llvm/Transforms/Utils/OrderedInstructions.h @@ -43,6 +43,9 @@ class OrderedInstructions { bool dominates(const Instruction *, const Instruction *) const; /// Invalidate the OrderedBasicBlock cache when its basic block changes. + /// i.e. If an instruction is deleted or added to the basic block, the user + /// should call this function to invalidate the OrderedBasicBlock cache for + /// this basic block. void invalidateBlock(BasicBlock *BB) { OBBMap.erase(BB); } }; diff --git a/contrib/llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h b/contrib/llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h index 73d1f264c37b..57d10c4c7473 100644 --- a/contrib/llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h +++ b/contrib/llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h @@ -87,8 +87,6 @@ struct LoopVectorizePass : public PassInfoMixin { std::function *GetLAA; OptimizationRemarkEmitter *ORE; - BlockFrequency ColdEntryFreq; - PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); // Shim for old PM. diff --git a/contrib/llvm/include/llvm/module.modulemap b/contrib/llvm/include/llvm/module.modulemap index d906b05f7aaa..dd419e861316 100644 --- a/contrib/llvm/include/llvm/module.modulemap +++ b/contrib/llvm/include/llvm/module.modulemap @@ -275,11 +275,9 @@ module LLVM_Utils { umbrella "Support" module * { export * } - // Exclude this; it's only included on Solaris. - exclude header "Support/Solaris.h" - - // Exclude this; it's fundamentally non-modular. + // Exclude these; they are fundamentally non-modular. exclude header "Support/PluginLoader.h" + exclude header "Support/Solaris/sys/regset.h" // These are intended for textual inclusion. textual header "Support/ARMTargetParser.def" diff --git a/contrib/llvm/lib/Analysis/AliasSetTracker.cpp b/contrib/llvm/lib/Analysis/AliasSetTracker.cpp index ee17ad3ba586..4dfa25490d00 100644 --- a/contrib/llvm/lib/Analysis/AliasSetTracker.cpp +++ b/contrib/llvm/lib/Analysis/AliasSetTracker.cpp @@ -218,8 +218,8 @@ bool AliasSet::aliasesUnknownInst(const Instruction *Inst, return false; for (unsigned i = 0, e = UnknownInsts.size(); i != e; ++i) { - if (auto *Inst = getUnknownInst(i)) { - ImmutableCallSite C1(Inst), C2(Inst); + if (auto *UnknownInst = getUnknownInst(i)) { + ImmutableCallSite C1(UnknownInst), C2(Inst); if (!C1 || !C2 || AA.getModRefInfo(C1, C2) != MRI_NoModRef || AA.getModRefInfo(C2, C1) != MRI_NoModRef) return true; diff --git a/contrib/llvm/lib/Analysis/AssumptionCache.cpp b/contrib/llvm/lib/Analysis/AssumptionCache.cpp index 0468c794e81d..3ff27890dc38 100644 --- a/contrib/llvm/lib/Analysis/AssumptionCache.cpp +++ b/contrib/llvm/lib/Analysis/AssumptionCache.cpp @@ -84,18 +84,11 @@ void AssumptionCache::updateAffectedValues(CallInst *CI) { Value *B; ConstantInt *C; // (A & B) or (A | B) or (A ^ B). - if (match(V, - m_CombineOr(m_And(m_Value(A), m_Value(B)), - m_CombineOr(m_Or(m_Value(A), m_Value(B)), - m_Xor(m_Value(A), m_Value(B)))))) { + if (match(V, m_BitwiseLogic(m_Value(A), m_Value(B)))) { AddAffected(A); AddAffected(B); // (A << C) or (A >>_s C) or (A >>_u C) where C is some constant. - } else if (match(V, - m_CombineOr(m_Shl(m_Value(A), m_ConstantInt(C)), - m_CombineOr(m_LShr(m_Value(A), m_ConstantInt(C)), - m_AShr(m_Value(A), - m_ConstantInt(C)))))) { + } else if (match(V, m_Shift(m_Value(A), m_ConstantInt(C)))) { AddAffected(A); } }; diff --git a/contrib/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/contrib/llvm/lib/Analysis/BasicAliasAnalysis.cpp index dbb1b01b94ac..b52a1d7b24d6 100644 --- a/contrib/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/contrib/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -1021,11 +1021,14 @@ static AliasResult aliasSameBasePointerGEPs(const GEPOperator *GEP1, // asking about values from different loop iterations. See PR32314. // TODO: We may be able to change the check so we only do this when // we definitely looked through a PHINode. - KnownBits Known1 = computeKnownBits(GEP1LastIdx, DL); - KnownBits Known2 = computeKnownBits(GEP2LastIdx, DL); - if (Known1.Zero.intersects(Known2.One) || - Known1.One.intersects(Known2.Zero)) - return NoAlias; + if (GEP1LastIdx != GEP2LastIdx && + GEP1LastIdx->getType() == GEP2LastIdx->getType()) { + KnownBits Known1 = computeKnownBits(GEP1LastIdx, DL); + KnownBits Known2 = computeKnownBits(GEP2LastIdx, DL); + if (Known1.Zero.intersects(Known2.One) || + Known1.One.intersects(Known2.Zero)) + return NoAlias; + } } else if (isKnownNonEqual(GEP1LastIdx, GEP2LastIdx, DL)) return NoAlias; } @@ -1345,11 +1348,7 @@ AliasResult BasicAAResult::aliasGEP(const GEPOperator *GEP1, uint64_t V1Size, // Statically, we can see that the base objects are the same, but the // pointers have dynamic offsets which we can't resolve. And none of our // little tricks above worked. - // - // TODO: Returning PartialAlias instead of MayAlias is a mild hack; the - // practical effect of this is protecting TBAA in the case of dynamic - // indices into arrays of unions or malloc'd memory. - return PartialAlias; + return MayAlias; } static AliasResult MergeAliasResults(AliasResult A, AliasResult B) { diff --git a/contrib/llvm/lib/Analysis/CFLSteensAliasAnalysis.cpp b/contrib/llvm/lib/Analysis/CFLSteensAliasAnalysis.cpp index dde24ef5fdd5..6e4263920e58 100644 --- a/contrib/llvm/lib/Analysis/CFLSteensAliasAnalysis.cpp +++ b/contrib/llvm/lib/Analysis/CFLSteensAliasAnalysis.cpp @@ -80,9 +80,6 @@ class CFLSteensAAResult::FunctionInfo { const AliasSummary &getAliasSummary() const { return Summary; } }; -/// Try to go from a Value* to a Function*. Never returns nullptr. -static Optional parentFunctionOfValue(Value *); - const StratifiedIndex StratifiedLink::SetSentinel = std::numeric_limits::max(); diff --git a/contrib/llvm/lib/Analysis/DemandedBits.cpp b/contrib/llvm/lib/Analysis/DemandedBits.cpp index 8f808f3e7871..926b28d6094a 100644 --- a/contrib/llvm/lib/Analysis/DemandedBits.cpp +++ b/contrib/llvm/lib/Analysis/DemandedBits.cpp @@ -107,6 +107,8 @@ void DemandedBits::determineLiveOperandBits( AB = AOut.byteSwap(); break; case Intrinsic::bitreverse: + // The alive bits of the input are the reversed alive bits of + // the output. AB = AOut.reverseBits(); break; case Intrinsic::ctlz: diff --git a/contrib/llvm/lib/Analysis/InlineCost.cpp b/contrib/llvm/lib/Analysis/InlineCost.cpp index 6ff5938a3175..77ad6f1e166f 100644 --- a/contrib/llvm/lib/Analysis/InlineCost.cpp +++ b/contrib/llvm/lib/Analysis/InlineCost.cpp @@ -1022,12 +1022,15 @@ bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { // inlining those. It will prevent inlining in cases where the optimization // does not (yet) fire. + // Maximum valid cost increased in this function. + int CostUpperBound = INT_MAX - InlineConstants::InstrCost - 1; + // Exit early for a large switch, assuming one case needs at least one // instruction. // FIXME: This is not true for a bit test, but ignore such case for now to // save compile-time. int64_t CostLowerBound = - std::min((int64_t)INT_MAX, + std::min((int64_t)CostUpperBound, (int64_t)SI.getNumCases() * InlineConstants::InstrCost + Cost); if (CostLowerBound > Threshold) { @@ -1044,7 +1047,8 @@ bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { if (JumpTableSize) { int64_t JTCost = (int64_t)JumpTableSize * InlineConstants::InstrCost + 4 * InlineConstants::InstrCost; - Cost = std::min((int64_t)INT_MAX, JTCost + Cost); + + Cost = std::min((int64_t)CostUpperBound, JTCost + Cost); return false; } @@ -1068,10 +1072,12 @@ bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { Cost += NumCaseCluster * 2 * InlineConstants::InstrCost; return false; } - int64_t ExpectedNumberOfCompare = 3 * (uint64_t)NumCaseCluster / 2 - 1; - uint64_t SwitchCost = + + int64_t ExpectedNumberOfCompare = 3 * (int64_t)NumCaseCluster / 2 - 1; + int64_t SwitchCost = ExpectedNumberOfCompare * 2 * InlineConstants::InstrCost; - Cost = std::min((uint64_t)INT_MAX, SwitchCost + Cost); + + Cost = std::min((int64_t)CostUpperBound, SwitchCost + Cost); return false; } diff --git a/contrib/llvm/lib/Analysis/InstructionSimplify.cpp b/contrib/llvm/lib/Analysis/InstructionSimplify.cpp index a975be79619b..d9e32a3c417e 100644 --- a/contrib/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/contrib/llvm/lib/Analysis/InstructionSimplify.cpp @@ -2688,16 +2688,14 @@ static Value *simplifyICmpWithBinOp(CmpInst::Predicate Pred, Value *LHS, } // icmp pred (and X, Y), X - if (LBO && match(LBO, m_CombineOr(m_And(m_Value(), m_Specific(RHS)), - m_And(m_Specific(RHS), m_Value())))) { + if (LBO && match(LBO, m_c_And(m_Value(), m_Specific(RHS)))) { if (Pred == ICmpInst::ICMP_UGT) return getFalse(ITy); if (Pred == ICmpInst::ICMP_ULE) return getTrue(ITy); } // icmp pred X, (and X, Y) - if (RBO && match(RBO, m_CombineOr(m_And(m_Value(), m_Specific(LHS)), - m_And(m_Specific(LHS), m_Value())))) { + if (RBO && match(RBO, m_c_And(m_Value(), m_Specific(LHS)))) { if (Pred == ICmpInst::ICMP_UGE) return getTrue(ITy); if (Pred == ICmpInst::ICMP_ULT) diff --git a/contrib/llvm/lib/Analysis/LazyValueInfo.cpp b/contrib/llvm/lib/Analysis/LazyValueInfo.cpp index 3ed61a79478a..102081e721ac 100644 --- a/contrib/llvm/lib/Analysis/LazyValueInfo.cpp +++ b/contrib/llvm/lib/Analysis/LazyValueInfo.cpp @@ -1324,12 +1324,12 @@ getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest, return getValueFromICmpCondition(Val, ICI, isTrueDest); // Handle conditions in the form of (cond1 && cond2), we know that on the - // true dest path both of the conditions hold. - if (!isTrueDest) - return LVILatticeVal::getOverdefined(); - + // true dest path both of the conditions hold. Similarly for conditions of + // the form (cond1 || cond2), we know that on the false dest path neither + // condition holds. BinaryOperator *BO = dyn_cast(Cond); - if (!BO || BO->getOpcode() != BinaryOperator::And) + if (!BO || (isTrueDest && BO->getOpcode() != BinaryOperator::And) || + (!isTrueDest && BO->getOpcode() != BinaryOperator::Or)) return LVILatticeVal::getOverdefined(); auto RHS = getValueFromCondition(Val, BO->getOperand(0), isTrueDest, Visited); @@ -1660,6 +1660,26 @@ Constant *LazyValueInfo::getConstantOnEdge(Value *V, BasicBlock *FromBB, return nullptr; } +ConstantRange LazyValueInfo::getConstantRangeOnEdge(Value *V, + BasicBlock *FromBB, + BasicBlock *ToBB, + Instruction *CxtI) { + unsigned Width = V->getType()->getIntegerBitWidth(); + const DataLayout &DL = FromBB->getModule()->getDataLayout(); + LVILatticeVal Result = + getImpl(PImpl, AC, &DL, DT).getValueOnEdge(V, FromBB, ToBB, CxtI); + + if (Result.isUndefined()) + return ConstantRange(Width, /*isFullSet=*/false); + if (Result.isConstantRange()) + return Result.getConstantRange(); + // We represent ConstantInt constants as constant ranges but other kinds + // of integer constants, i.e. ConstantExpr will be tagged as constants + assert(!(Result.isConstant() && isa(Result.getConstant())) && + "ConstantInt value must be represented as constantrange"); + return ConstantRange(Width, /*isFullSet=*/true); +} + static LazyValueInfo::Tristate getPredicateResult(unsigned Pred, Constant *C, const LVILatticeVal &Val, const DataLayout &DL, diff --git a/contrib/llvm/lib/Analysis/Loads.cpp b/contrib/llvm/lib/Analysis/Loads.cpp index 96799a459bfc..591b0fc481d2 100644 --- a/contrib/llvm/lib/Analysis/Loads.cpp +++ b/contrib/llvm/lib/Analysis/Loads.cpp @@ -116,6 +116,16 @@ static bool isDereferenceableAndAlignedPointer( return false; } +bool llvm::isDereferenceableAndAlignedPointer(const Value *V, unsigned Align, + const APInt &Size, + const DataLayout &DL, + const Instruction *CtxI, + const DominatorTree *DT) { + SmallPtrSet Visited; + return ::isDereferenceableAndAlignedPointer(V, Align, Size, DL, CtxI, DT, + Visited); +} + bool llvm::isDereferenceableAndAlignedPointer(const Value *V, unsigned Align, const DataLayout &DL, const Instruction *CtxI, diff --git a/contrib/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp b/contrib/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp index 3fdedbb0ab3c..263cf42ebe27 100644 --- a/contrib/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/contrib/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -310,11 +310,11 @@ unsigned MemoryDependenceResults::getLoadLoadClobberFullWidthSize( } static bool isVolatile(Instruction *Inst) { - if (LoadInst *LI = dyn_cast(Inst)) + if (auto *LI = dyn_cast(Inst)) return LI->isVolatile(); - else if (StoreInst *SI = dyn_cast(Inst)) + if (auto *SI = dyn_cast(Inst)) return SI->isVolatile(); - else if (AtomicCmpXchgInst *AI = dyn_cast(Inst)) + if (auto *AI = dyn_cast(Inst)) return AI->isVolatile(); return false; } diff --git a/contrib/llvm/lib/Analysis/ScalarEvolution.cpp b/contrib/llvm/lib/Analysis/ScalarEvolution.cpp index aebc80a0a885..73a95ec405c7 100644 --- a/contrib/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/contrib/llvm/lib/Analysis/ScalarEvolution.cpp @@ -126,11 +126,11 @@ static cl::opt static cl::opt MulOpsInlineThreshold( "scev-mulops-inline-threshold", cl::Hidden, cl::desc("Threshold for inlining multiplication operands into a SCEV"), - cl::init(1000)); + cl::init(32)); static cl::opt AddOpsInlineThreshold( "scev-addops-inline-threshold", cl::Hidden, - cl::desc("Threshold for inlining multiplication operands into a SCEV"), + cl::desc("Threshold for inlining addition operands into a SCEV"), cl::init(500)); static cl::opt MaxSCEVCompareDepth( @@ -1259,12 +1259,12 @@ static const SCEV *getSignedOverflowLimitForStep(const SCEV *Step, if (SE->isKnownPositive(Step)) { *Pred = ICmpInst::ICMP_SLT; return SE->getConstant(APInt::getSignedMinValue(BitWidth) - - SE->getSignedRange(Step).getSignedMax()); + SE->getSignedRangeMax(Step)); } if (SE->isKnownNegative(Step)) { *Pred = ICmpInst::ICMP_SGT; return SE->getConstant(APInt::getSignedMaxValue(BitWidth) - - SE->getSignedRange(Step).getSignedMin()); + SE->getSignedRangeMin(Step)); } return nullptr; } @@ -1279,7 +1279,7 @@ static const SCEV *getUnsignedOverflowLimitForStep(const SCEV *Step, *Pred = ICmpInst::ICMP_ULT; return SE->getConstant(APInt::getMinValue(BitWidth) - - SE->getUnsignedRange(Step).getUnsignedMax()); + SE->getUnsignedRangeMax(Step)); } namespace { @@ -1670,7 +1670,7 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty, // is safe. if (isKnownPositive(Step)) { const SCEV *N = getConstant(APInt::getMinValue(BitWidth) - - getUnsignedRange(Step).getUnsignedMax()); + getUnsignedRangeMax(Step)); if (isLoopBackedgeGuardedByCond(L, ICmpInst::ICMP_ULT, AR, N) || (isLoopEntryGuardedByCond(L, ICmpInst::ICMP_ULT, Start, N) && isLoopBackedgeGuardedByCond(L, ICmpInst::ICMP_ULT, @@ -1686,7 +1686,7 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty, } } else if (isKnownNegative(Step)) { const SCEV *N = getConstant(APInt::getMaxValue(BitWidth) - - getSignedRange(Step).getSignedMin()); + getSignedRangeMin(Step)); if (isLoopBackedgeGuardedByCond(L, ICmpInst::ICMP_UGT, AR, N) || (isLoopEntryGuardedByCond(L, ICmpInst::ICMP_UGT, Start, N) && isLoopBackedgeGuardedByCond(L, ICmpInst::ICMP_UGT, @@ -3745,7 +3745,7 @@ const SCEV *ScalarEvolution::getMinusSCEV(const SCEV *LHS, const SCEV *RHS, // makes it so that we cannot make much use of NUW. auto AddFlags = SCEV::FlagAnyWrap; const bool RHSIsNotMinSigned = - !getSignedRange(RHS).getSignedMin().isMinSignedValue(); + !getSignedRangeMin(RHS).isMinSignedValue(); if (maskFlags(Flags, SCEV::FlagNSW) == SCEV::FlagNSW) { // Let M be the minimum representable signed value. Then (-1)*RHS // signed-wraps if and only if RHS is M. That can happen even for @@ -4758,9 +4758,9 @@ static Optional GetRangeFromMetadata(Value *V) { /// Determine the range for a particular SCEV. If SignHint is /// HINT_RANGE_UNSIGNED (resp. HINT_RANGE_SIGNED) then getRange prefers ranges /// with a "cleaner" unsigned (resp. signed) representation. -ConstantRange -ScalarEvolution::getRange(const SCEV *S, - ScalarEvolution::RangeSignHint SignHint) { +const ConstantRange & +ScalarEvolution::getRangeRef(const SCEV *S, + ScalarEvolution::RangeSignHint SignHint) { DenseMap &Cache = SignHint == ScalarEvolution::HINT_RANGE_UNSIGNED ? UnsignedRanges : SignedRanges; @@ -4791,54 +4791,54 @@ ScalarEvolution::getRange(const SCEV *S, } if (const SCEVAddExpr *Add = dyn_cast(S)) { - ConstantRange X = getRange(Add->getOperand(0), SignHint); + ConstantRange X = getRangeRef(Add->getOperand(0), SignHint); for (unsigned i = 1, e = Add->getNumOperands(); i != e; ++i) - X = X.add(getRange(Add->getOperand(i), SignHint)); + X = X.add(getRangeRef(Add->getOperand(i), SignHint)); return setRange(Add, SignHint, ConservativeResult.intersectWith(X)); } if (const SCEVMulExpr *Mul = dyn_cast(S)) { - ConstantRange X = getRange(Mul->getOperand(0), SignHint); + ConstantRange X = getRangeRef(Mul->getOperand(0), SignHint); for (unsigned i = 1, e = Mul->getNumOperands(); i != e; ++i) - X = X.multiply(getRange(Mul->getOperand(i), SignHint)); + X = X.multiply(getRangeRef(Mul->getOperand(i), SignHint)); return setRange(Mul, SignHint, ConservativeResult.intersectWith(X)); } if (const SCEVSMaxExpr *SMax = dyn_cast(S)) { - ConstantRange X = getRange(SMax->getOperand(0), SignHint); + ConstantRange X = getRangeRef(SMax->getOperand(0), SignHint); for (unsigned i = 1, e = SMax->getNumOperands(); i != e; ++i) - X = X.smax(getRange(SMax->getOperand(i), SignHint)); + X = X.smax(getRangeRef(SMax->getOperand(i), SignHint)); return setRange(SMax, SignHint, ConservativeResult.intersectWith(X)); } if (const SCEVUMaxExpr *UMax = dyn_cast(S)) { - ConstantRange X = getRange(UMax->getOperand(0), SignHint); + ConstantRange X = getRangeRef(UMax->getOperand(0), SignHint); for (unsigned i = 1, e = UMax->getNumOperands(); i != e; ++i) - X = X.umax(getRange(UMax->getOperand(i), SignHint)); + X = X.umax(getRangeRef(UMax->getOperand(i), SignHint)); return setRange(UMax, SignHint, ConservativeResult.intersectWith(X)); } if (const SCEVUDivExpr *UDiv = dyn_cast(S)) { - ConstantRange X = getRange(UDiv->getLHS(), SignHint); - ConstantRange Y = getRange(UDiv->getRHS(), SignHint); + ConstantRange X = getRangeRef(UDiv->getLHS(), SignHint); + ConstantRange Y = getRangeRef(UDiv->getRHS(), SignHint); return setRange(UDiv, SignHint, ConservativeResult.intersectWith(X.udiv(Y))); } if (const SCEVZeroExtendExpr *ZExt = dyn_cast(S)) { - ConstantRange X = getRange(ZExt->getOperand(), SignHint); + ConstantRange X = getRangeRef(ZExt->getOperand(), SignHint); return setRange(ZExt, SignHint, ConservativeResult.intersectWith(X.zeroExtend(BitWidth))); } if (const SCEVSignExtendExpr *SExt = dyn_cast(S)) { - ConstantRange X = getRange(SExt->getOperand(), SignHint); + ConstantRange X = getRangeRef(SExt->getOperand(), SignHint); return setRange(SExt, SignHint, ConservativeResult.intersectWith(X.signExtend(BitWidth))); } if (const SCEVTruncateExpr *Trunc = dyn_cast(S)) { - ConstantRange X = getRange(Trunc->getOperand(), SignHint); + ConstantRange X = getRangeRef(Trunc->getOperand(), SignHint); return setRange(Trunc, SignHint, ConservativeResult.intersectWith(X.truncate(BitWidth))); } @@ -5005,8 +5005,7 @@ ConstantRange ScalarEvolution::getRangeForAffineAR(const SCEV *Start, "Precondition!"); MaxBECount = getNoopOrZeroExtend(MaxBECount, Start->getType()); - ConstantRange MaxBECountRange = getUnsignedRange(MaxBECount); - APInt MaxBECountValue = MaxBECountRange.getUnsignedMax(); + APInt MaxBECountValue = getUnsignedRangeMax(MaxBECount); // First, consider step signed. ConstantRange StartSRange = getSignedRange(Start); @@ -5023,7 +5022,7 @@ ConstantRange ScalarEvolution::getRangeForAffineAR(const SCEV *Start, // Next, consider step unsigned. ConstantRange UR = getRangeForAffineARHelper( - getUnsignedRange(Step).getUnsignedMax(), getUnsignedRange(Start), + getUnsignedRangeMax(Step), getUnsignedRange(Start), MaxBECountValue, BitWidth, /* Signed = */ false); // Finally, intersect signed and unsigned ranges. @@ -6373,7 +6372,7 @@ ScalarEvolution::ExitLimit ScalarEvolution::computeExitLimitFromCondImpl( // to not. if (isa(MaxBECount) && !isa(BECount)) - MaxBECount = getConstant(getUnsignedRange(BECount).getUnsignedMax()); + MaxBECount = getConstant(getUnsignedRangeMax(BECount)); return ExitLimit(BECount, MaxBECount, false, {&EL0.Predicates, &EL1.Predicates}); @@ -7647,7 +7646,7 @@ ScalarEvolution::howFarToZero(const SCEV *V, const Loop *L, bool ControlsExit, // 1*N = -Start; -1*N = Start (mod 2^BW), so: // N = Distance (as unsigned) if (StepC->getValue()->equalsInt(1) || StepC->getValue()->isAllOnesValue()) { - APInt MaxBECount = getUnsignedRange(Distance).getUnsignedMax(); + APInt MaxBECount = getUnsignedRangeMax(Distance); // When a loop like "for (int i = 0; i != n; ++i) { /* body */ }" is rotated, // we end up with a loop whose backedge-taken count is n - 1. Detect this @@ -7680,7 +7679,7 @@ ScalarEvolution::howFarToZero(const SCEV *V, const Loop *L, bool ControlsExit, const SCEV *Max = Exact == getCouldNotCompute() ? Exact - : getConstant(getUnsignedRange(Exact).getUnsignedMax()); + : getConstant(getUnsignedRangeMax(Exact)); return ExitLimit(Exact, Max, false, Predicates); } @@ -7689,7 +7688,7 @@ ScalarEvolution::howFarToZero(const SCEV *V, const Loop *L, bool ControlsExit, getNegativeSCEV(Start), *this); const SCEV *M = E == getCouldNotCompute() ? E - : getConstant(getUnsignedRange(E).getUnsignedMax()); + : getConstant(getUnsignedRangeMax(E)); return ExitLimit(E, M, false, Predicates); } @@ -7886,12 +7885,12 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, // adding or subtracting 1 from one of the operands. switch (Pred) { case ICmpInst::ICMP_SLE: - if (!getSignedRange(RHS).getSignedMax().isMaxSignedValue()) { + if (!getSignedRangeMax(RHS).isMaxSignedValue()) { RHS = getAddExpr(getConstant(RHS->getType(), 1, true), RHS, SCEV::FlagNSW); Pred = ICmpInst::ICMP_SLT; Changed = true; - } else if (!getSignedRange(LHS).getSignedMin().isMinSignedValue()) { + } else if (!getSignedRangeMin(LHS).isMinSignedValue()) { LHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), LHS, SCEV::FlagNSW); Pred = ICmpInst::ICMP_SLT; @@ -7899,12 +7898,12 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, } break; case ICmpInst::ICMP_SGE: - if (!getSignedRange(RHS).getSignedMin().isMinSignedValue()) { + if (!getSignedRangeMin(RHS).isMinSignedValue()) { RHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), RHS, SCEV::FlagNSW); Pred = ICmpInst::ICMP_SGT; Changed = true; - } else if (!getSignedRange(LHS).getSignedMax().isMaxSignedValue()) { + } else if (!getSignedRangeMax(LHS).isMaxSignedValue()) { LHS = getAddExpr(getConstant(RHS->getType(), 1, true), LHS, SCEV::FlagNSW); Pred = ICmpInst::ICMP_SGT; @@ -7912,23 +7911,23 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, } break; case ICmpInst::ICMP_ULE: - if (!getUnsignedRange(RHS).getUnsignedMax().isMaxValue()) { + if (!getUnsignedRangeMax(RHS).isMaxValue()) { RHS = getAddExpr(getConstant(RHS->getType(), 1, true), RHS, SCEV::FlagNUW); Pred = ICmpInst::ICMP_ULT; Changed = true; - } else if (!getUnsignedRange(LHS).getUnsignedMin().isMinValue()) { + } else if (!getUnsignedRangeMin(LHS).isMinValue()) { LHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), LHS); Pred = ICmpInst::ICMP_ULT; Changed = true; } break; case ICmpInst::ICMP_UGE: - if (!getUnsignedRange(RHS).getUnsignedMin().isMinValue()) { + if (!getUnsignedRangeMin(RHS).isMinValue()) { RHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), RHS); Pred = ICmpInst::ICMP_UGT; Changed = true; - } else if (!getUnsignedRange(LHS).getUnsignedMax().isMaxValue()) { + } else if (!getUnsignedRangeMax(LHS).isMaxValue()) { LHS = getAddExpr(getConstant(RHS->getType(), 1, true), LHS, SCEV::FlagNUW); Pred = ICmpInst::ICMP_UGT; @@ -7962,19 +7961,19 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, } bool ScalarEvolution::isKnownNegative(const SCEV *S) { - return getSignedRange(S).getSignedMax().isNegative(); + return getSignedRangeMax(S).isNegative(); } bool ScalarEvolution::isKnownPositive(const SCEV *S) { - return getSignedRange(S).getSignedMin().isStrictlyPositive(); + return getSignedRangeMin(S).isStrictlyPositive(); } bool ScalarEvolution::isKnownNonNegative(const SCEV *S) { - return !getSignedRange(S).getSignedMin().isNegative(); + return !getSignedRangeMin(S).isNegative(); } bool ScalarEvolution::isKnownNonPositive(const SCEV *S) { - return !getSignedRange(S).getSignedMax().isStrictlyPositive(); + return !getSignedRangeMax(S).isStrictlyPositive(); } bool ScalarEvolution::isKnownNonZero(const SCEV *S) { @@ -8560,7 +8559,7 @@ bool ScalarEvolution::isImpliedCond(ICmpInst::Predicate Pred, const SCEV *LHS, // predicate we're interested in folding. APInt Min = ICmpInst::isSigned(Pred) ? - getSignedRange(V).getSignedMin() : getUnsignedRange(V).getUnsignedMin(); + getSignedRangeMin(V) : getUnsignedRangeMin(V); if (Min == C->getAPInt()) { // Given (V >= Min && V != Min) we conclude V >= (Min + 1). @@ -9115,19 +9114,17 @@ bool ScalarEvolution::doesIVOverflowOnLT(const SCEV *RHS, const SCEV *Stride, const SCEV *One = getOne(Stride->getType()); if (IsSigned) { - APInt MaxRHS = getSignedRange(RHS).getSignedMax(); + APInt MaxRHS = getSignedRangeMax(RHS); APInt MaxValue = APInt::getSignedMaxValue(BitWidth); - APInt MaxStrideMinusOne = getSignedRange(getMinusSCEV(Stride, One)) - .getSignedMax(); + APInt MaxStrideMinusOne = getSignedRangeMax(getMinusSCEV(Stride, One)); // SMaxRHS + SMaxStrideMinusOne > SMaxValue => overflow! return (std::move(MaxValue) - MaxStrideMinusOne).slt(MaxRHS); } - APInt MaxRHS = getUnsignedRange(RHS).getUnsignedMax(); + APInt MaxRHS = getUnsignedRangeMax(RHS); APInt MaxValue = APInt::getMaxValue(BitWidth); - APInt MaxStrideMinusOne = getUnsignedRange(getMinusSCEV(Stride, One)) - .getUnsignedMax(); + APInt MaxStrideMinusOne = getUnsignedRangeMax(getMinusSCEV(Stride, One)); // UMaxRHS + UMaxStrideMinusOne > UMaxValue => overflow! return (std::move(MaxValue) - MaxStrideMinusOne).ult(MaxRHS); @@ -9141,19 +9138,17 @@ bool ScalarEvolution::doesIVOverflowOnGT(const SCEV *RHS, const SCEV *Stride, const SCEV *One = getOne(Stride->getType()); if (IsSigned) { - APInt MinRHS = getSignedRange(RHS).getSignedMin(); + APInt MinRHS = getSignedRangeMin(RHS); APInt MinValue = APInt::getSignedMinValue(BitWidth); - APInt MaxStrideMinusOne = getSignedRange(getMinusSCEV(Stride, One)) - .getSignedMax(); + APInt MaxStrideMinusOne = getSignedRangeMax(getMinusSCEV(Stride, One)); // SMinRHS - SMaxStrideMinusOne < SMinValue => overflow! return (std::move(MinValue) + MaxStrideMinusOne).sgt(MinRHS); } - APInt MinRHS = getUnsignedRange(RHS).getUnsignedMin(); + APInt MinRHS = getUnsignedRangeMin(RHS); APInt MinValue = APInt::getMinValue(BitWidth); - APInt MaxStrideMinusOne = getUnsignedRange(getMinusSCEV(Stride, One)) - .getUnsignedMax(); + APInt MaxStrideMinusOne = getUnsignedRangeMax(getMinusSCEV(Stride, One)); // UMinRHS - UMaxStrideMinusOne < UMinValue => overflow! return (std::move(MinValue) + MaxStrideMinusOne).ugt(MinRHS); @@ -9292,8 +9287,8 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS, } else { // Calculate the maximum backedge count based on the range of values // permitted by Start, End, and Stride. - APInt MinStart = IsSigned ? getSignedRange(Start).getSignedMin() - : getUnsignedRange(Start).getUnsignedMin(); + APInt MinStart = IsSigned ? getSignedRangeMin(Start) + : getUnsignedRangeMin(Start); unsigned BitWidth = getTypeSizeInBits(LHS->getType()); @@ -9301,8 +9296,8 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS, if (PositiveStride) StrideForMaxBECount = - IsSigned ? getSignedRange(Stride).getSignedMin() - : getUnsignedRange(Stride).getUnsignedMin(); + IsSigned ? getSignedRangeMin(Stride) + : getUnsignedRangeMin(Stride); else // Using a stride of 1 is safe when computing max backedge taken count for // a loop with unknown stride. @@ -9316,8 +9311,8 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS, // the case End = RHS. This is safe because in the other case (End - Start) // is zero, leading to a zero maximum backedge taken count. APInt MaxEnd = - IsSigned ? APIntOps::smin(getSignedRange(RHS).getSignedMax(), Limit) - : APIntOps::umin(getUnsignedRange(RHS).getUnsignedMax(), Limit); + IsSigned ? APIntOps::smin(getSignedRangeMax(RHS), Limit) + : APIntOps::umin(getUnsignedRangeMax(RHS), Limit); MaxBECount = computeBECount(getConstant(MaxEnd - MinStart), getConstant(StrideForMaxBECount), false); @@ -9325,7 +9320,7 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS, if (isa(MaxBECount) && !isa(BECount)) - MaxBECount = getConstant(getUnsignedRange(BECount).getUnsignedMax()); + MaxBECount = getConstant(getUnsignedRangeMax(BECount)); return ExitLimit(BECount, MaxBECount, MaxOrZero, Predicates); } @@ -9376,11 +9371,11 @@ ScalarEvolution::howManyGreaterThans(const SCEV *LHS, const SCEV *RHS, const SCEV *BECount = computeBECount(getMinusSCEV(Start, End), Stride, false); - APInt MaxStart = IsSigned ? getSignedRange(Start).getSignedMax() - : getUnsignedRange(Start).getUnsignedMax(); + APInt MaxStart = IsSigned ? getSignedRangeMax(Start) + : getUnsignedRangeMax(Start); - APInt MinStride = IsSigned ? getSignedRange(Stride).getSignedMin() - : getUnsignedRange(Stride).getUnsignedMin(); + APInt MinStride = IsSigned ? getSignedRangeMin(Stride) + : getUnsignedRangeMin(Stride); unsigned BitWidth = getTypeSizeInBits(LHS->getType()); APInt Limit = IsSigned ? APInt::getSignedMinValue(BitWidth) + (MinStride - 1) @@ -9390,8 +9385,8 @@ ScalarEvolution::howManyGreaterThans(const SCEV *LHS, const SCEV *RHS, // the case End = RHS. This is safe because in the other case (Start - End) // is zero, leading to a zero maximum backedge taken count. APInt MinEnd = - IsSigned ? APIntOps::smax(getSignedRange(RHS).getSignedMin(), Limit) - : APIntOps::umax(getUnsignedRange(RHS).getUnsignedMin(), Limit); + IsSigned ? APIntOps::smax(getSignedRangeMin(RHS), Limit) + : APIntOps::umax(getUnsignedRangeMin(RHS), Limit); const SCEV *MaxBECount = getCouldNotCompute(); diff --git a/contrib/llvm/lib/Analysis/ScalarEvolutionExpander.cpp b/contrib/llvm/lib/Analysis/ScalarEvolutionExpander.cpp index f9b9df2bc707..47bdac00ae1f 100644 --- a/contrib/llvm/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/contrib/llvm/lib/Analysis/ScalarEvolutionExpander.cpp @@ -748,18 +748,56 @@ Value *SCEVExpander::visitMulExpr(const SCEVMulExpr *S) { // Emit instructions to mul all the operands. Hoist as much as possible // out of loops. Value *Prod = nullptr; - for (const auto &I : OpsAndLoops) { - const SCEV *Op = I.second; + auto I = OpsAndLoops.begin(); + + // Expand the calculation of X pow N in the following manner: + // Let N = P1 + P2 + ... + PK, where all P are powers of 2. Then: + // X pow N = (X pow P1) * (X pow P2) * ... * (X pow PK). + const auto ExpandOpBinPowN = [this, &I, &OpsAndLoops, &Ty]() { + auto E = I; + // Calculate how many times the same operand from the same loop is included + // into this power. + uint64_t Exponent = 0; + const uint64_t MaxExponent = UINT64_MAX >> 1; + // No one sane will ever try to calculate such huge exponents, but if we + // need this, we stop on UINT64_MAX / 2 because we need to exit the loop + // below when the power of 2 exceeds our Exponent, and we want it to be + // 1u << 31 at most to not deal with unsigned overflow. + while (E != OpsAndLoops.end() && *I == *E && Exponent != MaxExponent) { + ++Exponent; + ++E; + } + assert(Exponent > 0 && "Trying to calculate a zeroth exponent of operand?"); + + // Calculate powers with exponents 1, 2, 4, 8 etc. and include those of them + // that are needed into the result. + Value *P = expandCodeFor(I->second, Ty); + Value *Result = nullptr; + if (Exponent & 1) + Result = P; + for (uint64_t BinExp = 2; BinExp <= Exponent; BinExp <<= 1) { + P = InsertBinop(Instruction::Mul, P, P); + if (Exponent & BinExp) + Result = Result ? InsertBinop(Instruction::Mul, Result, P) : P; + } + + I = E; + assert(Result && "Nothing was expanded?"); + return Result; + }; + + while (I != OpsAndLoops.end()) { if (!Prod) { // This is the first operand. Just expand it. - Prod = expand(Op); - } else if (Op->isAllOnesValue()) { + Prod = ExpandOpBinPowN(); + } else if (I->second->isAllOnesValue()) { // Instead of doing a multiply by negative one, just do a negate. Prod = InsertNoopCastOfTo(Prod, Ty); Prod = InsertBinop(Instruction::Sub, Constant::getNullValue(Ty), Prod); + ++I; } else { // A simple mul. - Value *W = expandCodeFor(Op, Ty); + Value *W = ExpandOpBinPowN(); Prod = InsertNoopCastOfTo(Prod, Ty); // Canonicalize a constant to the RHS. if (isa(Prod)) std::swap(Prod, W); diff --git a/contrib/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp b/contrib/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp index e920c4c4e6b2..cd9972ab56a6 100644 --- a/contrib/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ b/contrib/llvm/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -58,7 +58,7 @@ // // The struct type node has a name and a list of pairs, one pair for each member // of the struct. The first element of each pair is a type node (a struct type -// node or a sclar type node), specifying the type of the member, the second +// node or a scalar type node), specifying the type of the member, the second // element of each pair is the offset of the member. // // Given an example diff --git a/contrib/llvm/lib/Analysis/ValueTracking.cpp b/contrib/llvm/lib/Analysis/ValueTracking.cpp index b065f427b06c..fd6e3a643bf0 100644 --- a/contrib/llvm/lib/Analysis/ValueTracking.cpp +++ b/contrib/llvm/lib/Analysis/ValueTracking.cpp @@ -686,8 +686,7 @@ static void computeKnownBitsFromAssume(const Value *V, KnownBits &Known, Known.One |= RHSKnown.Zero; // assume(v >> c = a) } else if (match(Arg, - m_c_ICmp(Pred, m_CombineOr(m_LShr(m_V, m_ConstantInt(C)), - m_AShr(m_V, m_ConstantInt(C))), + m_c_ICmp(Pred, m_Shr(m_V, m_ConstantInt(C)), m_Value(A))) && Pred == ICmpInst::ICMP_EQ && isValidAssumeForContext(I, Q.CxtI, Q.DT)) { @@ -698,9 +697,7 @@ static void computeKnownBitsFromAssume(const Value *V, KnownBits &Known, Known.Zero |= RHSKnown.Zero << C->getZExtValue(); Known.One |= RHSKnown.One << C->getZExtValue(); // assume(~(v >> c) = a) - } else if (match(Arg, m_c_ICmp(Pred, m_Not(m_CombineOr( - m_LShr(m_V, m_ConstantInt(C)), - m_AShr(m_V, m_ConstantInt(C)))), + } else if (match(Arg, m_c_ICmp(Pred, m_Not(m_Shr(m_V, m_ConstantInt(C))), m_Value(A))) && Pred == ICmpInst::ICMP_EQ && isValidAssumeForContext(I, Q.CxtI, Q.DT)) { diff --git a/contrib/llvm/lib/BinaryFormat/Magic.cpp b/contrib/llvm/lib/BinaryFormat/Magic.cpp index ca4d93f99d92..f24f22c88a8a 100644 --- a/contrib/llvm/lib/BinaryFormat/Magic.cpp +++ b/contrib/llvm/lib/BinaryFormat/Magic.cpp @@ -51,7 +51,8 @@ file_magic llvm::identify_magic(StringRef Magic) { return file_magic::coff_import_library; } // Windows resource file - if (startswith(Magic, "\0\0\0\0\x20\0\0\0\xFF")) + if (Magic.size() >= sizeof(COFF::WinResMagic) && + memcmp(Magic.data(), COFF::WinResMagic, sizeof(COFF::WinResMagic)) == 0) return file_magic::windows_resource; // 0x0000 = COFF unknown machine type if (Magic[1] == 0) diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index ad348d723bae..c48fcaa7b0d1 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -2801,26 +2801,24 @@ void AsmPrinter::emitXRayTable() { } // Before we switch over, we force a reference to a label inside the - // xray_instr_map and xray_fn_idx sections. Since this function is always - // called just before the function's end, we assume that this is happening - // after the last return instruction. We also use the synthetic label in the - // xray_inster_map as a delimeter for the range of sleds for this function in - // the index. + // xray_fn_idx sections. This makes sure that the xray_fn_idx section is kept + // live by the linker if the function is not garbage-collected. Since this + // function is always called just before the function's end, we assume that + // this is happening after the last return instruction. auto WordSizeBytes = MAI->getCodePointerSize(); - MCSymbol *SledsStart = OutContext.createTempSymbol("xray_synthetic_", true); MCSymbol *IdxRef = OutContext.createTempSymbol("xray_fn_idx_synth_", true); OutStreamer->EmitCodeAlignment(16); - OutStreamer->EmitSymbolValue(SledsStart, WordSizeBytes, false); OutStreamer->EmitSymbolValue(IdxRef, WordSizeBytes, false); // Now we switch to the instrumentation map section. Because this is done // per-function, we are able to create an index entry that will represent the // range of sleds associated with a function. + MCSymbol *SledsStart = OutContext.createTempSymbol("xray_sleds_start", true); OutStreamer->SwitchSection(InstMap); OutStreamer->EmitLabel(SledsStart); for (const auto &Sled : Sleds) Sled.emit(WordSizeBytes, OutStreamer.get(), CurrentFnSym); - MCSymbol *SledsEnd = OutContext.createTempSymbol("xray_synthetic_end", true); + MCSymbol *SledsEnd = OutContext.createTempSymbol("xray_sleds_end", true); OutStreamer->EmitLabel(SledsEnd); // We then emit a single entry in the index per function. We use the symbols diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DIE.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DIE.cpp index 30bfd7c94e68..886e6e264b3e 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DIE.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DIE.cpp @@ -105,7 +105,7 @@ void DIEAbbrev::Emit(const AsmPrinter *AP) const { } LLVM_DUMP_METHOD -void DIEAbbrev::print(raw_ostream &O) { +void DIEAbbrev::print(raw_ostream &O) const { O << "Abbreviation @" << format("0x%lx", (long)(intptr_t)this) << " " @@ -128,7 +128,7 @@ void DIEAbbrev::print(raw_ostream &O) { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void DIEAbbrev::dump() { +LLVM_DUMP_METHOD void DIEAbbrev::dump() const { print(dbgs()); } #endif @@ -268,7 +268,7 @@ void DIE::print(raw_ostream &O, unsigned IndentCount) const { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void DIE::dump() { +LLVM_DUMP_METHOD void DIE::dump() const { print(dbgs()); } #endif diff --git a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 75eb355bfb54..f1b4d9f20ca9 100644 --- a/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/contrib/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -972,16 +972,62 @@ DbgVariable *DwarfDebug::createConcreteVariable(DwarfCompileUnit &TheCU, return ConcreteVariables.back().get(); } -// Determine whether this DBG_VALUE is valid at the beginning of the function. -static bool validAtEntry(const MachineInstr *MInsn) { - auto MBB = MInsn->getParent(); - // Is it in the entry basic block? - if (!MBB->pred_empty()) +/// Determine whether a *singular* DBG_VALUE is valid for the entirety of its +/// enclosing lexical scope. The check ensures there are no other instructions +/// in the same lexical scope preceding the DBG_VALUE and that its range is +/// either open or otherwise rolls off the end of the scope. +static bool validThroughout(LexicalScopes &LScopes, + const MachineInstr *DbgValue, + const MachineInstr *RangeEnd) { + assert(DbgValue->getDebugLoc() && "DBG_VALUE without a debug location"); + auto MBB = DbgValue->getParent(); + auto DL = DbgValue->getDebugLoc(); + auto *LScope = LScopes.findLexicalScope(DL); + // Scope doesn't exist; this is a dead DBG_VALUE. + if (!LScope) return false; - for (MachineBasicBlock::const_reverse_iterator I(MInsn); I != MBB->rend(); ++I) - if (!(I->isDebugValue() || I->getFlag(MachineInstr::FrameSetup))) + auto &LSRange = LScope->getRanges(); + if (LSRange.size() == 0) + return false; + + // Determine if the DBG_VALUE is valid at the beginning of its lexical block. + const MachineInstr *LScopeBegin = LSRange.front().first; + // Early exit if the lexical scope begins outside of the current block. + if (LScopeBegin->getParent() != MBB) + return false; + MachineBasicBlock::const_reverse_iterator Pred(DbgValue); + for (++Pred; Pred != MBB->rend(); ++Pred) { + if (Pred->getFlag(MachineInstr::FrameSetup)) + break; + auto PredDL = Pred->getDebugLoc(); + if (!PredDL || Pred->isMetaInstruction()) + continue; + // Check whether the instruction preceding the DBG_VALUE is in the same + // (sub)scope as the DBG_VALUE. + if (DL->getScope() == PredDL->getScope()) return false; - return true; + auto *PredScope = LScopes.findLexicalScope(PredDL); + if (!PredScope || LScope->dominates(PredScope)) + return false; + } + + // If the range of the DBG_VALUE is open-ended, report success. + if (!RangeEnd) + return true; + + // Fail if there are instructions belonging to our scope in another block. + const MachineInstr *LScopeEnd = LSRange.back().second; + if (LScopeEnd->getParent() != MBB) + return false; + + // Single, constant DBG_VALUEs in the prologue are promoted to be live + // throughout the function. This is a hack, presumably for DWARF v2 and not + // necessarily correct. It would be much better to use a dbg.declare instead + // if we know the constant is live throughout the scope. + if (DbgValue->getOperand(0).isImm() && MBB->pred_empty()) + return true; + + return false; } // Find variables for each lexical scope. @@ -1016,11 +1062,9 @@ void DwarfDebug::collectVariableInfo(DwarfCompileUnit &TheCU, const MachineInstr *MInsn = Ranges.front().first; assert(MInsn->isDebugValue() && "History must begin with debug value"); - // Check if there is a single DBG_VALUE, valid throughout the function. - // A single constant is also considered valid for the entire function. + // Check if there is a single DBG_VALUE, valid throughout the var's scope. if (Ranges.size() == 1 && - (MInsn->getOperand(0).isImm() || - (validAtEntry(MInsn) && Ranges.front().second == nullptr))) { + validThroughout(LScopes, MInsn, Ranges.front().second)) { RegVar->initializeDbgValue(MInsn); continue; } diff --git a/contrib/llvm/lib/CodeGen/CodeGenPrepare.cpp b/contrib/llvm/lib/CodeGen/CodeGenPrepare.cpp index 37e176099ea7..cb31c21293f4 100644 --- a/contrib/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/contrib/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -1663,17 +1663,18 @@ class MemCmpExpansion { bool IsUsedForZeroCmp; const DataLayout &DL; - int calculateNumBlocks(unsigned Size); + unsigned calculateNumBlocks(unsigned Size); void createLoadCmpBlocks(); void createResultBlock(); void setupResultBlockPHINodes(); void setupEndBlockPHINodes(); - void emitLoadCompareBlock(unsigned Index, int LoadSize, int GEPIndex); + void emitLoadCompareBlock(unsigned Index, unsigned LoadSize, + unsigned GEPIndex); Value *getCompareLoadPairs(unsigned Index, unsigned Size, unsigned &NumBytesProcessed, IRBuilder<> &Builder); void emitLoadCompareBlockMultipleLoads(unsigned Index, unsigned Size, unsigned &NumBytesProcessed); - void emitLoadCompareByteBlock(unsigned Index, int GEPIndex); + void emitLoadCompareByteBlock(unsigned Index, unsigned GEPIndex); void emitMemCmpResultBlock(); Value *getMemCmpExpansionZeroCase(unsigned Size); Value *getMemCmpEqZeroOneBlock(unsigned Size); @@ -1751,7 +1752,8 @@ void MemCmpExpansion::createResultBlock() { // It loads 1 byte from each source of the memcmp parameters with the given // GEPIndex. It then subtracts the two loaded values and adds this result to the // final phi node for selecting the memcmp result. -void MemCmpExpansion::emitLoadCompareByteBlock(unsigned Index, int GEPIndex) { +void MemCmpExpansion::emitLoadCompareByteBlock(unsigned Index, + unsigned GEPIndex) { IRBuilder<> Builder(CI->getContext()); Value *Source1 = CI->getArgOperand(0); @@ -1833,6 +1835,7 @@ Value *MemCmpExpansion::getCompareLoadPairs(unsigned Index, unsigned Size, Type *LoadSizeType = IntegerType::get(CI->getContext(), LoadSize * 8); Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8); + assert(LoadSize <= MaxLoadSize && "Unexpected load type"); Value *Source1 = CI->getArgOperand(0); Value *Source2 = CI->getArgOperand(1); @@ -1851,18 +1854,28 @@ Value *MemCmpExpansion::getCompareLoadPairs(unsigned Index, unsigned Size, ConstantInt::get(LoadSizeType, GEPIndex)); } - // Load LoadSizeType from the base address. - Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1); - Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2); + // Get a constant or load a value for each source address. + Value *LoadSrc1 = nullptr; + if (auto *Source1C = dyn_cast(Source1)) + LoadSrc1 = ConstantFoldLoadFromConstPtr(Source1C, LoadSizeType, DL); + if (!LoadSrc1) + LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1); + + Value *LoadSrc2 = nullptr; + if (auto *Source2C = dyn_cast(Source2)) + LoadSrc2 = ConstantFoldLoadFromConstPtr(Source2C, LoadSizeType, DL); + if (!LoadSrc2) + LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2); + if (NumLoads != 1) { if (LoadSizeType != MaxLoadType) { - LoadSrc1 = Builder.CreateZExtOrTrunc(LoadSrc1, MaxLoadType); - LoadSrc2 = Builder.CreateZExtOrTrunc(LoadSrc2, MaxLoadType); + LoadSrc1 = Builder.CreateZExt(LoadSrc1, MaxLoadType); + LoadSrc2 = Builder.CreateZExt(LoadSrc2, MaxLoadType); } // If we have multiple loads per block, we need to generate a composite // comparison using xor+or. Diff = Builder.CreateXor(LoadSrc1, LoadSrc2); - Diff = Builder.CreateZExtOrTrunc(Diff, MaxLoadType); + Diff = Builder.CreateZExt(Diff, MaxLoadType); XorList.push_back(Diff); } else { // If there's only one load per block, we just compare the loaded values. @@ -1926,8 +1939,8 @@ void MemCmpExpansion::emitLoadCompareBlockMultipleLoads( // the EndBlock if this is the last LoadCmpBlock. Loading 1 byte is handled with // a special case through emitLoadCompareByteBlock. The special handling can // simply subtract the loaded values and add it to the result phi node. -void MemCmpExpansion::emitLoadCompareBlock(unsigned Index, int LoadSize, - int GEPIndex) { +void MemCmpExpansion::emitLoadCompareBlock(unsigned Index, unsigned LoadSize, + unsigned GEPIndex) { if (LoadSize == 1) { MemCmpExpansion::emitLoadCompareByteBlock(Index, GEPIndex); return; @@ -1937,6 +1950,7 @@ void MemCmpExpansion::emitLoadCompareBlock(unsigned Index, int LoadSize, Type *LoadSizeType = IntegerType::get(CI->getContext(), LoadSize * 8); Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8); + assert(LoadSize <= MaxLoadSize && "Unexpected load type"); Value *Source1 = CI->getArgOperand(0); Value *Source2 = CI->getArgOperand(1); @@ -1970,8 +1984,8 @@ void MemCmpExpansion::emitLoadCompareBlock(unsigned Index, int LoadSize, } if (LoadSizeType != MaxLoadType) { - LoadSrc1 = Builder.CreateZExtOrTrunc(LoadSrc1, MaxLoadType); - LoadSrc2 = Builder.CreateZExtOrTrunc(LoadSrc2, MaxLoadType); + LoadSrc1 = Builder.CreateZExt(LoadSrc1, MaxLoadType); + LoadSrc2 = Builder.CreateZExt(LoadSrc2, MaxLoadType); } // Add the loaded values to the phi nodes for calculating memcmp result only @@ -2034,8 +2048,8 @@ void MemCmpExpansion::emitMemCmpResultBlock() { PhiRes->addIncoming(Res, ResBlock.BB); } -int MemCmpExpansion::calculateNumBlocks(unsigned Size) { - int NumBlocks = 0; +unsigned MemCmpExpansion::calculateNumBlocks(unsigned Size) { + unsigned NumBlocks = 0; bool HaveOneByteLoad = false; unsigned RemainingSize = Size; unsigned LoadSize = MaxLoadSize; @@ -2104,13 +2118,13 @@ Value *MemCmpExpansion::getMemCmpExpansion(uint64_t Size) { // memcmp sources. It starts with loading using the maximum load size set by // the target. It processes any remaining bytes using a load size which is the // next smallest power of 2. - int LoadSize = MaxLoadSize; - int NumBytesToBeProcessed = Size; + unsigned LoadSize = MaxLoadSize; + unsigned NumBytesToBeProcessed = Size; unsigned Index = 0; while (NumBytesToBeProcessed) { // Calculate how many blocks we can create with the current load size. - int NumBlocks = NumBytesToBeProcessed / LoadSize; - int GEPIndex = (Size - NumBytesToBeProcessed) / LoadSize; + unsigned NumBlocks = NumBytesToBeProcessed / LoadSize; + unsigned GEPIndex = (Size - NumBytesToBeProcessed) / LoadSize; NumBytesToBeProcessed = NumBytesToBeProcessed % LoadSize; // For each NumBlocks, populate the instruction sequence for loading and diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index dccd8e0706ca..239bad2f5355 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -582,7 +582,7 @@ bool IRTranslator::translateOverflowIntrinsic(const CallInst &CI, unsigned Op, MIB.addUse(Zero); } - MIRBuilder.buildSequence(getOrCreateVReg(CI), Res, 0, Overflow, Width); + MIRBuilder.buildSequence(getOrCreateVReg(CI), {Res, Overflow}, {0, Width}); return true; } @@ -686,6 +686,13 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, .addUse(getOrCreateVReg(*CI.getArgOperand(0))) .addUse(getOrCreateVReg(*CI.getArgOperand(1))); return true; + case Intrinsic::fma: + MIRBuilder.buildInstr(TargetOpcode::G_FMA) + .addDef(getOrCreateVReg(CI)) + .addUse(getOrCreateVReg(*CI.getArgOperand(0))) + .addUse(getOrCreateVReg(*CI.getArgOperand(1))) + .addUse(getOrCreateVReg(*CI.getArgOperand(2))); + return true; case Intrinsic::memcpy: case Intrinsic::memmove: case Intrinsic::memset: diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp index 4c0b06dffd21..5466efd7e90f 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/InstructionSelector.cpp @@ -25,6 +25,18 @@ using namespace llvm; InstructionSelector::InstructionSelector() {} +bool InstructionSelector::constrainOperandRegToRegClass( + MachineInstr &I, unsigned OpIdx, const TargetRegisterClass &RC, + const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) const { + MachineBasicBlock &MBB = *I.getParent(); + MachineFunction &MF = *MBB.getParent(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + + return llvm::constrainRegToClass(MRI, TII, RBI, I, + I.getOperand(OpIdx).getReg(), RC); +} + bool InstructionSelector::constrainSelectedInstRegOperands( MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const { diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp index 1b50489deeba..b699156c568b 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/Legalizer.cpp @@ -50,72 +50,9 @@ void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const { void Legalizer::init(MachineFunction &MF) { } -bool Legalizer::combineExtracts(MachineInstr &MI, MachineRegisterInfo &MRI, - const TargetInstrInfo &TII) { - bool Changed = false; - if (MI.getOpcode() != TargetOpcode::G_EXTRACT) - return Changed; - - unsigned NumDefs = (MI.getNumOperands() - 1) / 2; - unsigned SrcReg = MI.getOperand(NumDefs).getReg(); - MachineInstr &SeqI = *MRI.def_instr_begin(SrcReg); - if (SeqI.getOpcode() != TargetOpcode::G_SEQUENCE) - return Changed; - - unsigned NumSeqSrcs = (SeqI.getNumOperands() - 1) / 2; - bool AllDefsReplaced = true; - - // Try to match each register extracted with a corresponding insertion formed - // by the G_SEQUENCE. - for (unsigned Idx = 0, SeqIdx = 0; Idx < NumDefs; ++Idx) { - MachineOperand &ExtractMO = MI.getOperand(Idx); - assert(ExtractMO.isReg() && ExtractMO.isDef() && - "unexpected extract operand"); - - unsigned ExtractReg = ExtractMO.getReg(); - unsigned ExtractPos = MI.getOperand(NumDefs + Idx + 1).getImm(); - - while (SeqIdx < NumSeqSrcs && - SeqI.getOperand(2 * SeqIdx + 2).getImm() < ExtractPos) - ++SeqIdx; - - if (SeqIdx == NumSeqSrcs) { - AllDefsReplaced = false; - continue; - } - - unsigned OrigReg = SeqI.getOperand(2 * SeqIdx + 1).getReg(); - if (SeqI.getOperand(2 * SeqIdx + 2).getImm() != ExtractPos || - MRI.getType(OrigReg) != MRI.getType(ExtractReg)) { - AllDefsReplaced = false; - continue; - } - - assert(!TargetRegisterInfo::isPhysicalRegister(OrigReg) && - "unexpected physical register in G_SEQUENCE"); - - // Finally we can replace the uses. - MRI.replaceRegWith(ExtractReg, OrigReg); - } - - if (AllDefsReplaced) { - // If SeqI was the next instruction in the BB and we removed it, we'd break - // the outer iteration. - assert(std::next(MachineBasicBlock::iterator(MI)) != SeqI && - "G_SEQUENCE does not dominate G_EXTRACT"); - - MI.eraseFromParent(); - - if (MRI.use_empty(SrcReg)) - SeqI.eraseFromParent(); - Changed = true; - } - - return Changed; -} - bool Legalizer::combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI, - const TargetInstrInfo &TII) { + const TargetInstrInfo &TII, + MachineIRBuilder &MIRBuilder) { if (MI.getOpcode() != TargetOpcode::G_UNMERGE_VALUES) return false; @@ -125,18 +62,62 @@ bool Legalizer::combineMerges(MachineInstr &MI, MachineRegisterInfo &MRI, if (MergeI.getOpcode() != TargetOpcode::G_MERGE_VALUES) return false; - if (MergeI.getNumOperands() - 1 != NumDefs) - return false; + const unsigned NumMergeRegs = MergeI.getNumOperands() - 1; - // FIXME: is a COPY appropriate if the types mismatch? We know both registers - // are allocatable by now. - if (MRI.getType(MI.getOperand(0).getReg()) != - MRI.getType(MergeI.getOperand(1).getReg())) - return false; + if (NumMergeRegs < NumDefs) { + if (NumDefs % NumMergeRegs != 0) + return false; - for (unsigned Idx = 0; Idx < NumDefs; ++Idx) - MRI.replaceRegWith(MI.getOperand(Idx).getReg(), - MergeI.getOperand(Idx + 1).getReg()); + MIRBuilder.setInstr(MI); + // Transform to UNMERGEs, for example + // %1 = G_MERGE_VALUES %4, %5 + // %9, %10, %11, %12 = G_UNMERGE_VALUES %1 + // to + // %9, %10 = G_UNMERGE_VALUES %4 + // %11, %12 = G_UNMERGE_VALUES %5 + + const unsigned NewNumDefs = NumDefs / NumMergeRegs; + for (unsigned Idx = 0; Idx < NumMergeRegs; ++Idx) { + SmallVector DstRegs; + for (unsigned j = 0, DefIdx = Idx * NewNumDefs; j < NewNumDefs; + ++j, ++DefIdx) + DstRegs.push_back(MI.getOperand(DefIdx).getReg()); + + MIRBuilder.buildUnmerge(DstRegs, MergeI.getOperand(Idx + 1).getReg()); + } + + } else if (NumMergeRegs > NumDefs) { + if (NumMergeRegs % NumDefs != 0) + return false; + + MIRBuilder.setInstr(MI); + // Transform to MERGEs + // %6 = G_MERGE_VALUES %17, %18, %19, %20 + // %7, %8 = G_UNMERGE_VALUES %6 + // to + // %7 = G_MERGE_VALUES %17, %18 + // %8 = G_MERGE_VALUES %19, %20 + + const unsigned NumRegs = NumMergeRegs / NumDefs; + for (unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) { + SmallVector Regs; + for (unsigned j = 0, Idx = NumRegs * DefIdx + 1; j < NumRegs; ++j, ++Idx) + Regs.push_back(MergeI.getOperand(Idx).getReg()); + + MIRBuilder.buildMerge(MI.getOperand(DefIdx).getReg(), Regs); + } + + } else { + // FIXME: is a COPY appropriate if the types mismatch? We know both + // registers are allocatable by now. + if (MRI.getType(MI.getOperand(0).getReg()) != + MRI.getType(MergeI.getOperand(1).getReg())) + return false; + + for (unsigned Idx = 0; Idx < NumDefs; ++Idx) + MRI.replaceRegWith(MI.getOperand(Idx).getReg(), + MergeI.getOperand(Idx + 1).getReg()); + } MI.eraseFromParent(); if (MRI.use_empty(MergeI.getOperand(0).getReg())) @@ -226,13 +207,7 @@ bool Legalizer::runOnMachineFunction(MachineFunction &MF) { // Get the next Instruction before we try to legalize, because there's a // good chance MI will be deleted. NextMI = std::next(MI); - - // combineExtracts erases MI. - if (combineExtracts(*MI, MRI, TII)) { - Changed = true; - continue; - } - Changed |= combineMerges(*MI, MRI, TII); + Changed |= combineMerges(*MI, MRI, TII, Helper.MIRBuilder); } } diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp index 4d4591042296..595802f2228b 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp @@ -75,8 +75,7 @@ LegalizerInfo::getAction(const InstrAspect &Aspect) const { // FIXME: the long-term plan calls for expansion in terms of load/store (if // they're not legal). - if (Aspect.Opcode == TargetOpcode::G_SEQUENCE || - Aspect.Opcode == TargetOpcode::G_EXTRACT || + if (Aspect.Opcode == TargetOpcode::G_EXTRACT || Aspect.Opcode == TargetOpcode::G_MERGE_VALUES || Aspect.Opcode == TargetOpcode::G_UNMERGE_VALUES) return std::make_pair(Legal, Aspect.Type); diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp index 79d312fb52ca..3c70013ea296 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/MachineIRBuilder.cpp @@ -425,10 +425,8 @@ MachineInstrBuilder MachineIRBuilder::buildExtract(unsigned Res, unsigned Src, .addImm(Index); } -MachineInstrBuilder -MachineIRBuilder::buildSequence(unsigned Res, - ArrayRef Ops, - ArrayRef Indices) { +void MachineIRBuilder::buildSequence(unsigned Res, ArrayRef Ops, + ArrayRef Indices) { #ifndef NDEBUG assert(Ops.size() == Indices.size() && "incompatible args"); assert(!Ops.empty() && "invalid trivial sequence"); @@ -440,13 +438,31 @@ MachineIRBuilder::buildSequence(unsigned Res, assert(MRI->getType(Op).isValid() && "invalid operand type"); #endif - MachineInstrBuilder MIB = buildInstr(TargetOpcode::G_SEQUENCE); - MIB.addDef(Res); + LLT ResTy = MRI->getType(Res); + LLT OpTy = MRI->getType(Ops[0]); + unsigned OpSize = OpTy.getSizeInBits(); + bool MaybeMerge = true; for (unsigned i = 0; i < Ops.size(); ++i) { - MIB.addUse(Ops[i]); - MIB.addImm(Indices[i]); + if (MRI->getType(Ops[i]) != OpTy || Indices[i] != i * OpSize) { + MaybeMerge = false; + break; + } + } + + if (MaybeMerge && Ops.size() * OpSize == ResTy.getSizeInBits()) { + buildMerge(Res, Ops); + return; + } + + unsigned ResIn = MRI->createGenericVirtualRegister(ResTy); + buildUndef(ResIn); + + for (unsigned i = 0; i < Ops.size(); ++i) { + unsigned ResOut = + i + 1 == Ops.size() ? Res : MRI->createGenericVirtualRegister(ResTy); + buildInsert(ResOut, ResIn, Ops[i], Indices[i]); + ResIn = ResOut; } - return MIB; } MachineInstrBuilder MachineIRBuilder::buildUndef(unsigned Res) { diff --git a/contrib/llvm/lib/CodeGen/GlobalISel/Utils.cpp b/contrib/llvm/lib/CodeGen/GlobalISel/Utils.cpp index 254bdf10d804..5ecaf5c563f8 100644 --- a/contrib/llvm/lib/CodeGen/GlobalISel/Utils.cpp +++ b/contrib/llvm/lib/CodeGen/GlobalISel/Utils.cpp @@ -26,6 +26,23 @@ using namespace llvm; +unsigned llvm::constrainRegToClass(MachineRegisterInfo &MRI, + const TargetInstrInfo &TII, + const RegisterBankInfo &RBI, + MachineInstr &InsertPt, unsigned Reg, + const TargetRegisterClass &RegClass) { + if (!RBI.constrainGenericRegister(Reg, RegClass, MRI)) { + unsigned NewReg = MRI.createVirtualRegister(&RegClass); + BuildMI(*InsertPt.getParent(), InsertPt, InsertPt.getDebugLoc(), + TII.get(TargetOpcode::COPY), NewReg) + .addReg(Reg); + return NewReg; + } + + return Reg; +} + + unsigned llvm::constrainOperandRegClass( const MachineFunction &MF, const TargetRegisterInfo &TRI, MachineRegisterInfo &MRI, const TargetInstrInfo &TII, @@ -36,16 +53,7 @@ unsigned llvm::constrainOperandRegClass( "PhysReg not implemented"); const TargetRegisterClass *RegClass = TII.getRegClass(II, OpIdx, &TRI, MF); - - if (!RBI.constrainGenericRegister(Reg, *RegClass, MRI)) { - unsigned NewReg = MRI.createVirtualRegister(RegClass); - BuildMI(*InsertPt.getParent(), InsertPt, InsertPt.getDebugLoc(), - TII.get(TargetOpcode::COPY), NewReg) - .addReg(Reg); - return NewReg; - } - - return Reg; + return constrainRegToClass(MRI, TII, RBI, InsertPt, Reg, *RegClass); } bool llvm::isTriviallyDead(const MachineInstr &MI, diff --git a/contrib/llvm/lib/CodeGen/IfConversion.cpp b/contrib/llvm/lib/CodeGen/IfConversion.cpp index c98c9b68ac0e..ff8405366173 100644 --- a/contrib/llvm/lib/CodeGen/IfConversion.cpp +++ b/contrib/llvm/lib/CodeGen/IfConversion.cpp @@ -1474,8 +1474,11 @@ bool IfConverter::IfConvertSimple(BBInfo &BBI, IfcvtKind Kind) { DontKill.addLiveIns(NextMBB); } + // Remove the branches from the entry so we can add the contents of the true + // block to it. + BBI.NonPredSize -= TII->removeBranch(*BBI.BB); + if (CvtMBB.pred_size() > 1) { - BBI.NonPredSize -= TII->removeBranch(*BBI.BB); // Copy instructions in the true block, predicate them, and add them to // the entry block. CopyAndPredicateBlock(BBI, *CvtBBI, Cond); @@ -1484,11 +1487,11 @@ bool IfConverter::IfConvertSimple(BBInfo &BBI, IfcvtKind Kind) { // explicitly remove CvtBBI as a successor. BBI.BB->removeSuccessor(&CvtMBB, true); } else { + // Predicate the instructions in the true block. RemoveKills(CvtMBB.begin(), CvtMBB.end(), DontKill, *TRI); PredicateBlock(*CvtBBI, CvtMBB.end(), Cond); // Merge converted block into entry block. - BBI.NonPredSize -= TII->removeBranch(*BBI.BB); MergeBlocks(BBI, *CvtBBI); } @@ -1588,8 +1591,11 @@ bool IfConverter::IfConvertTriangle(BBInfo &BBI, IfcvtKind Kind) { BBCvt = MBPI->getEdgeProbability(BBI.BB, &CvtMBB); } + // Remove the branches from the entry so we can add the contents of the true + // block to it. + BBI.NonPredSize -= TII->removeBranch(*BBI.BB); + if (CvtMBB.pred_size() > 1) { - BBI.NonPredSize -= TII->removeBranch(*BBI.BB); // Copy instructions in the true block, predicate them, and add them to // the entry block. CopyAndPredicateBlock(BBI, *CvtBBI, Cond, true); @@ -1603,7 +1609,6 @@ bool IfConverter::IfConvertTriangle(BBInfo &BBI, IfcvtKind Kind) { PredicateBlock(*CvtBBI, CvtMBB.end(), Cond); // Now merge the entry of the triangle with the true block. - BBI.NonPredSize -= TII->removeBranch(*BBI.BB); MergeBlocks(BBI, *CvtBBI, false); } diff --git a/contrib/llvm/lib/CodeGen/ImplicitNullChecks.cpp b/contrib/llvm/lib/CodeGen/ImplicitNullChecks.cpp index b831ddfa601a..e308f49ec4e8 100644 --- a/contrib/llvm/lib/CodeGen/ImplicitNullChecks.cpp +++ b/contrib/llvm/lib/CodeGen/ImplicitNullChecks.cpp @@ -359,30 +359,15 @@ ImplicitNullChecks::isSuitableMemoryOp(MachineInstr &MI, unsigned PointerReg, Offset < PageSize)) return SR_Unsuitable; - // Finally, we need to make sure that the access instruction actually is - // accessing from PointerReg, and there isn't some re-definition of PointerReg - // between the compare and the memory access. - // If PointerReg has been redefined before then there is no sense to continue - // lookup due to this condition will fail for any further instruction. - SuitabilityResult Suitable = SR_Suitable; - for (auto *PrevMI : PrevInsts) - for (auto &PrevMO : PrevMI->operands()) { - if (PrevMO.isReg() && PrevMO.getReg() && PrevMO.isDef() && - TRI->regsOverlap(PrevMO.getReg(), PointerReg)) - return SR_Impossible; - - // Check whether the current memory access aliases with previous one. - // If we already found that it aliases then no need to continue. - // But we continue base pointer check as it can result in SR_Impossible. - if (Suitable == SR_Suitable) { - AliasResult AR = areMemoryOpsAliased(MI, PrevMI); - if (AR == AR_WillAliasEverything) - return SR_Impossible; - if (AR == AR_MayAlias) - Suitable = SR_Unsuitable; - } - } - return Suitable; + // Finally, check whether the current memory access aliases with previous one. + for (auto *PrevMI : PrevInsts) { + AliasResult AR = areMemoryOpsAliased(MI, PrevMI); + if (AR == AR_WillAliasEverything) + return SR_Impossible; + if (AR == AR_MayAlias) + return SR_Unsuitable; + } + return SR_Suitable; } bool ImplicitNullChecks::canHoistInst(MachineInstr *FaultingMI, @@ -569,6 +554,12 @@ bool ImplicitNullChecks::analyzeBlockForNullChecks( return true; } + // If MI re-defines the PointerReg then we cannot move further. + if (any_of(MI.operands(), [&](MachineOperand &MO) { + return MO.isReg() && MO.getReg() && MO.isDef() && + TRI->regsOverlap(MO.getReg(), PointerReg); + })) + return false; InstsSeenSoFar.push_back(&MI); } diff --git a/contrib/llvm/lib/CodeGen/LiveDebugVariables.cpp b/contrib/llvm/lib/CodeGen/LiveDebugVariables.cpp index bbd783367c9e..0c76478af551 100644 --- a/contrib/llvm/lib/CodeGen/LiveDebugVariables.cpp +++ b/contrib/llvm/lib/CodeGen/LiveDebugVariables.cpp @@ -1006,7 +1006,7 @@ bool LiveDebugVariables::doInitialization(Module &M) { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void LiveDebugVariables::dump() { +LLVM_DUMP_METHOD void LiveDebugVariables::dump() const { if (pImpl) static_cast(pImpl)->print(dbgs()); } diff --git a/contrib/llvm/lib/CodeGen/LiveDebugVariables.h b/contrib/llvm/lib/CodeGen/LiveDebugVariables.h index afe87a52544d..1d7e3d4371a2 100644 --- a/contrib/llvm/lib/CodeGen/LiveDebugVariables.h +++ b/contrib/llvm/lib/CodeGen/LiveDebugVariables.h @@ -59,7 +59,7 @@ class LLVM_LIBRARY_VISIBILITY LiveDebugVariables : public MachineFunctionPass { void emitDebugValues(VirtRegMap *VRM); /// dump - Print data structures to dbgs(). - void dump(); + void dump() const; private: diff --git a/contrib/llvm/lib/CodeGen/MachineBasicBlock.cpp b/contrib/llvm/lib/CodeGen/MachineBasicBlock.cpp index 590acc01008a..81597afe6b02 100644 --- a/contrib/llvm/lib/CodeGen/MachineBasicBlock.cpp +++ b/contrib/llvm/lib/CodeGen/MachineBasicBlock.cpp @@ -228,6 +228,12 @@ LLVM_DUMP_METHOD void MachineBasicBlock::dump() const { } #endif +bool MachineBasicBlock::isLegalToHoistInto() const { + if (isReturnBlock() || hasEHPadSuccessor()) + return false; + return true; +} + StringRef MachineBasicBlock::getName() const { if (const BasicBlock *LBB = getBasicBlock()) return LBB->getName(); diff --git a/contrib/llvm/lib/CodeGen/MachineInstr.cpp b/contrib/llvm/lib/CodeGen/MachineInstr.cpp index 2a6cb07dbd2d..81c6dace92e0 100644 --- a/contrib/llvm/lib/CodeGen/MachineInstr.cpp +++ b/contrib/llvm/lib/CodeGen/MachineInstr.cpp @@ -21,6 +21,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/Loads.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/CodeGen/GlobalISel/RegisterBank.h" #include "llvm/CodeGen/MachineBasicBlock.h" @@ -558,6 +559,23 @@ unsigned MachinePointerInfo::getAddrSpace() const { return cast(V.get()->getType())->getAddressSpace(); } +/// isDereferenceable - Return true if V is always dereferenceable for +/// Offset + Size byte. +bool MachinePointerInfo::isDereferenceable(unsigned Size, LLVMContext &C, + const DataLayout &DL) const { + if (!V.is()) + return false; + + const Value *BasePtr = V.get(); + if (BasePtr == nullptr) + return false; + + return isDereferenceableAndAlignedPointer(BasePtr, 1, + APInt(DL.getPointerSize(), + Offset + Size), + DL); +} + /// getConstantPool - Return a MachinePointerInfo record that refers to the /// constant pool. MachinePointerInfo MachinePointerInfo::getConstantPool(MachineFunction &MF) { diff --git a/contrib/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp b/contrib/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp index 4c81fd91cb82..22d519e5d88f 100644 --- a/contrib/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp +++ b/contrib/llvm/lib/CodeGen/MachineModuleInfoImpls.cpp @@ -23,7 +23,6 @@ using namespace llvm; // Out of line virtual method. void MachineModuleInfoMachO::anchor() {} void MachineModuleInfoELF::anchor() {} -void MachineModuleInfoWasm::anchor() {} static int SortSymbolPair(const void *LHS, const void *RHS) { typedef std::pair PairTy; diff --git a/contrib/llvm/lib/CodeGen/MachineScheduler.cpp b/contrib/llvm/lib/CodeGen/MachineScheduler.cpp index 01a2286b8d66..eaba9a58557c 100644 --- a/contrib/llvm/lib/CodeGen/MachineScheduler.cpp +++ b/contrib/llvm/lib/CodeGen/MachineScheduler.cpp @@ -542,10 +542,10 @@ void MachineSchedulerBase::print(raw_ostream &O, const Module* m) const { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void ReadyQueue::dump() { +LLVM_DUMP_METHOD void ReadyQueue::dump() const { dbgs() << "Queue " << Name << ": "; - for (unsigned i = 0, e = Queue.size(); i < e; ++i) - dbgs() << Queue[i]->NodeNum << " "; + for (const SUnit *SU : Queue) + dbgs() << SU->NodeNum << " "; dbgs() << "\n"; } #endif @@ -609,10 +609,8 @@ void ScheduleDAGMI::releaseSucc(SUnit *SU, SDep *SuccEdge) { /// releaseSuccessors - Call releaseSucc on each of SU's successors. void ScheduleDAGMI::releaseSuccessors(SUnit *SU) { - for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); - I != E; ++I) { - releaseSucc(SU, &*I); - } + for (SDep &Succ : SU->Succs) + releaseSucc(SU, &Succ); } /// ReleasePred - Decrement the NumSuccsLeft count of a predecessor. When @@ -648,10 +646,8 @@ void ScheduleDAGMI::releasePred(SUnit *SU, SDep *PredEdge) { /// releasePredecessors - Call releasePred on each of SU's predecessors. void ScheduleDAGMI::releasePredecessors(SUnit *SU) { - for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); - I != E; ++I) { - releasePred(SU, &*I); - } + for (SDep &Pred : SU->Preds) + releasePred(SU, &Pred); } /// enterRegion - Called back from MachineScheduler::runOnMachineFunction after @@ -724,8 +720,8 @@ void ScheduleDAGMI::schedule() { DEBUG( if (EntrySU.getInstr() != nullptr) EntrySU.dumpAll(this); - for (unsigned su = 0, e = SUnits.size(); su != e; ++su) - SUnits[su].dumpAll(this); + for (const SUnit &SU : SUnits) + SU.dumpAll(this); if (ExitSU.getInstr() != nullptr) ExitSU.dumpAll(this); ); @@ -786,28 +782,25 @@ void ScheduleDAGMI::schedule() { /// Apply each ScheduleDAGMutation step in order. void ScheduleDAGMI::postprocessDAG() { - for (unsigned i = 0, e = Mutations.size(); i < e; ++i) { - Mutations[i]->apply(this); - } + for (auto &m : Mutations) + m->apply(this); } void ScheduleDAGMI:: findRootsAndBiasEdges(SmallVectorImpl &TopRoots, SmallVectorImpl &BotRoots) { - for (std::vector::iterator - I = SUnits.begin(), E = SUnits.end(); I != E; ++I) { - SUnit *SU = &(*I); - assert(!SU->isBoundaryNode() && "Boundary node should not be in SUnits"); + for (SUnit &SU : SUnits) { + assert(!SU.isBoundaryNode() && "Boundary node should not be in SUnits"); // Order predecessors so DFSResult follows the critical path. - SU->biasCriticalPath(); + SU.biasCriticalPath(); // A SUnit is ready to top schedule if it has no predecessors. - if (!I->NumPredsLeft) - TopRoots.push_back(SU); + if (!SU.NumPredsLeft) + TopRoots.push_back(&SU); // A SUnit is ready to bottom schedule if it has no successors. - if (!I->NumSuccsLeft) - BotRoots.push_back(SU); + if (!SU.NumSuccsLeft) + BotRoots.push_back(&SU); } ExitSU.biasCriticalPath(); } @@ -822,10 +815,9 @@ void ScheduleDAGMI::initQueues(ArrayRef TopRoots, // // Nodes with unreleased weak edges can still be roots. // Release top roots in forward order. - for (SmallVectorImpl::const_iterator - I = TopRoots.begin(), E = TopRoots.end(); I != E; ++I) { - SchedImpl->releaseTopNode(*I); - } + for (SUnit *SU : TopRoots) + SchedImpl->releaseTopNode(SU); + // Release bottom roots in reverse order so the higher priority nodes appear // first. This is more natural and slightly more efficient. for (SmallVectorImpl::const_reverse_iterator @@ -1029,9 +1021,9 @@ void ScheduleDAGMILive::initRegPressure() { } } DEBUG(dbgs() << "Excess PSets: "; - for (unsigned i = 0, e = RegionCriticalPSets.size(); i != e; ++i) + for (const PressureChange &RCPS : RegionCriticalPSets) dbgs() << TRI->getRegPressureSetName( - RegionCriticalPSets[i].getPSet()) << " "; + RCPS.getPSet()) << " "; dbgs() << "\n"); } @@ -1040,11 +1032,10 @@ updateScheduledPressure(const SUnit *SU, const std::vector &NewMaxPressure) { const PressureDiff &PDiff = getPressureDiff(SU); unsigned CritIdx = 0, CritEnd = RegionCriticalPSets.size(); - for (PressureDiff::const_iterator I = PDiff.begin(), E = PDiff.end(); - I != E; ++I) { - if (!I->isValid()) + for (const PressureChange &PC : PDiff) { + if (!PC.isValid()) break; - unsigned ID = I->getPSet(); + unsigned ID = PC.getPSet(); while (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() < ID) ++CritIdx; if (CritIdx != CritEnd && RegionCriticalPSets[CritIdx].getPSet() == ID) { @@ -1508,8 +1499,7 @@ createStoreClusterDAGMutation(const TargetInstrInfo *TII, void BaseMemOpClusterMutation::clusterNeighboringMemOps( ArrayRef MemOps, ScheduleDAGMI *DAG) { SmallVector MemOpRecords; - for (unsigned Idx = 0, End = MemOps.size(); Idx != End; ++Idx) { - SUnit *SU = MemOps[Idx]; + for (SUnit *SU : MemOps) { unsigned BaseReg; int64_t Offset; if (TII->getMemOpBaseRegImmOfs(*SU->getInstr(), BaseReg, Offset, TRI)) @@ -1537,12 +1527,11 @@ void BaseMemOpClusterMutation::clusterNeighboringMemOps( // dependent on SUa can prevent load combining due to register reuse. // Predecessor edges do not need to be copied from SUb to SUa since nearby // loads should have effectively the same inputs. - for (SUnit::const_succ_iterator - SI = SUa->Succs.begin(), SE = SUa->Succs.end(); SI != SE; ++SI) { - if (SI->getSUnit() == SUb) + for (const SDep &Succ : SUa->Succs) { + if (Succ.getSUnit() == SUb) continue; - DEBUG(dbgs() << " Copy Succ SU(" << SI->getSUnit()->NodeNum << ")\n"); - DAG->addEdge(SI->getSUnit(), SDep(SUb, SDep::Artificial)); + DEBUG(dbgs() << " Copy Succ SU(" << Succ.getSUnit()->NodeNum << ")\n"); + DAG->addEdge(Succ.getSUnit(), SDep(SUb, SDep::Artificial)); } ++ClusterLength; } else @@ -1559,17 +1548,15 @@ void BaseMemOpClusterMutation::apply(ScheduleDAGInstrs *DAGInstrs) { DenseMap StoreChainIDs; // Map each store chain to a set of dependent MemOps. SmallVector, 32> StoreChainDependents; - for (unsigned Idx = 0, End = DAG->SUnits.size(); Idx != End; ++Idx) { - SUnit *SU = &DAG->SUnits[Idx]; - if ((IsLoad && !SU->getInstr()->mayLoad()) || - (!IsLoad && !SU->getInstr()->mayStore())) + for (SUnit &SU : DAG->SUnits) { + if ((IsLoad && !SU.getInstr()->mayLoad()) || + (!IsLoad && !SU.getInstr()->mayStore())) continue; unsigned ChainPredID = DAG->SUnits.size(); - for (SUnit::const_pred_iterator - PI = SU->Preds.begin(), PE = SU->Preds.end(); PI != PE; ++PI) { - if (PI->isCtrl()) { - ChainPredID = PI->getSUnit()->NodeNum; + for (const SDep &Pred : SU.Preds) { + if (Pred.isCtrl()) { + ChainPredID = Pred.getSUnit()->NodeNum; break; } } @@ -1580,12 +1567,12 @@ void BaseMemOpClusterMutation::apply(ScheduleDAGInstrs *DAGInstrs) { StoreChainIDs.insert(std::make_pair(ChainPredID, NumChains)); if (Result.second) StoreChainDependents.resize(NumChains + 1); - StoreChainDependents[Result.first->second].push_back(SU); + StoreChainDependents[Result.first->second].push_back(&SU); } // Iterate over the store chains. - for (unsigned Idx = 0, End = StoreChainDependents.size(); Idx != End; ++Idx) - clusterNeighboringMemOps(StoreChainDependents[Idx], DAG); + for (auto &SCD : StoreChainDependents) + clusterNeighboringMemOps(SCD, DAG); } //===----------------------------------------------------------------------===// @@ -1728,16 +1715,14 @@ void CopyConstrain::constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG) { const VNInfo *LastLocalVN = LocalLI->getVNInfoBefore(LocalLI->endIndex()); MachineInstr *LastLocalDef = LIS->getInstructionFromIndex(LastLocalVN->def); SUnit *LastLocalSU = DAG->getSUnit(LastLocalDef); - for (SUnit::const_succ_iterator - I = LastLocalSU->Succs.begin(), E = LastLocalSU->Succs.end(); - I != E; ++I) { - if (I->getKind() != SDep::Data || I->getReg() != LocalReg) + for (const SDep &Succ : LastLocalSU->Succs) { + if (Succ.getKind() != SDep::Data || Succ.getReg() != LocalReg) continue; - if (I->getSUnit() == GlobalSU) + if (Succ.getSUnit() == GlobalSU) continue; - if (!DAG->canAddEdge(GlobalSU, I->getSUnit())) + if (!DAG->canAddEdge(GlobalSU, Succ.getSUnit())) return; - LocalUses.push_back(I->getSUnit()); + LocalUses.push_back(Succ.getSUnit()); } // Open the top of the GlobalLI hole by constraining any earlier global uses // to precede the start of LocalLI. @@ -1745,15 +1730,14 @@ void CopyConstrain::constrainLocalCopy(SUnit *CopySU, ScheduleDAGMILive *DAG) { MachineInstr *FirstLocalDef = LIS->getInstructionFromIndex(LocalLI->beginIndex()); SUnit *FirstLocalSU = DAG->getSUnit(FirstLocalDef); - for (SUnit::const_pred_iterator - I = GlobalSU->Preds.begin(), E = GlobalSU->Preds.end(); I != E; ++I) { - if (I->getKind() != SDep::Anti || I->getReg() != GlobalReg) + for (const SDep &Pred : GlobalSU->Preds) { + if (Pred.getKind() != SDep::Anti || Pred.getReg() != GlobalReg) continue; - if (I->getSUnit() == FirstLocalSU) + if (Pred.getSUnit() == FirstLocalSU) continue; - if (!DAG->canAddEdge(FirstLocalSU, I->getSUnit())) + if (!DAG->canAddEdge(FirstLocalSU, Pred.getSUnit())) return; - GlobalUses.push_back(I->getSUnit()); + GlobalUses.push_back(Pred.getSUnit()); } DEBUG(dbgs() << "Constraining copy SU(" << CopySU->NodeNum << ")\n"); // Add the weak edges. @@ -1784,12 +1768,11 @@ void CopyConstrain::apply(ScheduleDAGInstrs *DAGInstrs) { RegionEndIdx = DAG->getLIS()->getInstructionIndex( *priorNonDebug(DAG->end(), DAG->begin())); - for (unsigned Idx = 0, End = DAG->SUnits.size(); Idx != End; ++Idx) { - SUnit *SU = &DAG->SUnits[Idx]; - if (!SU->getInstr()->isCopy()) + for (SUnit &SU : DAG->SUnits) { + if (!SU.getInstr()->isCopy()) continue; - constrainLocalCopy(SU, static_cast(DAG)); + constrainLocalCopy(&SU, static_cast(DAG)); } } @@ -1840,10 +1823,9 @@ init(ScheduleDAGMI *DAG, const TargetSchedModel *SchedModel) { if (!SchedModel->hasInstrSchedModel()) return; RemainingCounts.resize(SchedModel->getNumProcResourceKinds()); - for (std::vector::iterator - I = DAG->SUnits.begin(), E = DAG->SUnits.end(); I != E; ++I) { - const MCSchedClassDesc *SC = DAG->getSchedClass(&*I); - RemIssueCount += SchedModel->getNumMicroOps(I->getInstr(), SC) + for (SUnit &SU : DAG->SUnits) { + const MCSchedClassDesc *SC = DAG->getSchedClass(&SU); + RemIssueCount += SchedModel->getNumMicroOps(SU.getInstr(), SC) * SchedModel->getMicroOpFactor(); for (TargetSchedModel::ProcResIter PI = SchedModel->getWriteProcResBegin(SC), @@ -1957,12 +1939,11 @@ unsigned SchedBoundary:: findMaxLatency(ArrayRef ReadySUs) { SUnit *LateSU = nullptr; unsigned RemLatency = 0; - for (ArrayRef::iterator I = ReadySUs.begin(), E = ReadySUs.end(); - I != E; ++I) { - unsigned L = getUnscheduledLatency(*I); + for (SUnit *SU : ReadySUs) { + unsigned L = getUnscheduledLatency(SU); if (L > RemLatency) { RemLatency = L; - LateSU = *I; + LateSU = SU; } } if (LateSU) { @@ -2328,7 +2309,7 @@ SUnit *SchedBoundary::pickOnlyChoice() { #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) // This is useful information to dump after bumpNode. // Note that the Queue contents are more useful before pickNodeFromQueue. -LLVM_DUMP_METHOD void SchedBoundary::dumpScheduledState() { +LLVM_DUMP_METHOD void SchedBoundary::dumpScheduledState() const { unsigned ResFactor; unsigned ResCount; if (ZoneCritResIdx) { @@ -2667,7 +2648,7 @@ void GenericScheduler::initPolicy(MachineBasicBlock::iterator Begin, } } -void GenericScheduler::dumpPolicy() { +void GenericScheduler::dumpPolicy() const { // Cannot completely remove virtual function even in release mode. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) dbgs() << "GenericScheduler RegionPolicy: " @@ -2719,10 +2700,9 @@ void GenericScheduler::registerRoots() { Rem.CriticalPath = DAG->ExitSU.getDepth(); // Some roots may not feed into ExitSU. Check all of them in case. - for (std::vector::const_iterator - I = Bot.Available.begin(), E = Bot.Available.end(); I != E; ++I) { - if ((*I)->getDepth() > Rem.CriticalPath) - Rem.CriticalPath = (*I)->getDepth(); + for (const SUnit *SU : Bot.Available) { + if (SU->getDepth() > Rem.CriticalPath) + Rem.CriticalPath = SU->getDepth(); } DEBUG(dbgs() << "Critical Path(GS-RR ): " << Rem.CriticalPath << '\n'); if (DumpCriticalPathLength) { @@ -2969,10 +2949,10 @@ void GenericScheduler::pickNodeFromQueue(SchedBoundary &Zone, RegPressureTracker &TempTracker = const_cast(RPTracker); ReadyQueue &Q = Zone.Available; - for (ReadyQueue::iterator I = Q.begin(), E = Q.end(); I != E; ++I) { + for (SUnit *SU : Q) { SchedCandidate TryCand(ZonePolicy); - initCandidate(TryCand, *I, Zone.isTop(), RPTracker, TempTracker); + initCandidate(TryCand, SU, Zone.isTop(), RPTracker, TempTracker); // Pass SchedBoundary only when comparing nodes from the same boundary. SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr; tryCandidate(Cand, TryCand, ZoneArg); @@ -3118,18 +3098,17 @@ void GenericScheduler::reschedulePhysRegCopies(SUnit *SU, bool isTop) { // Find already scheduled copies with a single physreg dependence and move // them just above the scheduled instruction. - for (SmallVectorImpl::iterator I = Deps.begin(), E = Deps.end(); - I != E; ++I) { - if (I->getKind() != SDep::Data || !TRI->isPhysicalRegister(I->getReg())) + for (SDep &Dep : Deps) { + if (Dep.getKind() != SDep::Data || !TRI->isPhysicalRegister(Dep.getReg())) continue; - SUnit *DepSU = I->getSUnit(); + SUnit *DepSU = Dep.getSUnit(); if (isTop ? DepSU->Succs.size() > 1 : DepSU->Preds.size() > 1) continue; MachineInstr *Copy = DepSU->getInstr(); if (!Copy->isCopy()) continue; DEBUG(dbgs() << " Rescheduling physreg copy "; - I->getSUnit()->dump(DAG)); + Dep.getSUnit()->dump(DAG)); DAG->moveInstruction(Copy, InsertPos); } } @@ -3204,10 +3183,9 @@ void PostGenericScheduler::registerRoots() { Rem.CriticalPath = DAG->ExitSU.getDepth(); // Some roots may not feed into ExitSU. Check all of them in case. - for (SmallVectorImpl::const_iterator - I = BotRoots.begin(), E = BotRoots.end(); I != E; ++I) { - if ((*I)->getDepth() > Rem.CriticalPath) - Rem.CriticalPath = (*I)->getDepth(); + for (const SUnit *SU : BotRoots) { + if (SU->getDepth() > Rem.CriticalPath) + Rem.CriticalPath = SU->getDepth(); } DEBUG(dbgs() << "Critical Path: (PGS-RR) " << Rem.CriticalPath << '\n'); if (DumpCriticalPathLength) { @@ -3260,9 +3238,9 @@ void PostGenericScheduler::tryCandidate(SchedCandidate &Cand, void PostGenericScheduler::pickNodeFromQueue(SchedCandidate &Cand) { ReadyQueue &Q = Top.Available; - for (ReadyQueue::iterator I = Q.begin(), E = Q.end(); I != E; ++I) { + for (SUnit *SU : Q) { SchedCandidate TryCand(Cand.Policy); - TryCand.SU = *I; + TryCand.SU = SU; TryCand.AtTop = true; TryCand.initResourceDelta(DAG, SchedModel); tryCandidate(Cand, TryCand); diff --git a/contrib/llvm/lib/CodeGen/MacroFusion.cpp b/contrib/llvm/lib/CodeGen/MacroFusion.cpp new file mode 100644 index 000000000000..45ea0e4c39ab --- /dev/null +++ b/contrib/llvm/lib/CodeGen/MacroFusion.cpp @@ -0,0 +1,150 @@ +//===- MacroFusion.cpp - Macro Fusion ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file contains the implementation of the DAG scheduling mutation +/// to pair instructions back to back. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MacroFusion.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetInstrInfo.h" + +#define DEBUG_TYPE "misched" + +STATISTIC(NumFused, "Number of instr pairs fused"); + +using namespace llvm; + +static cl::opt EnableMacroFusion("misched-fusion", cl::Hidden, + cl::desc("Enable scheduling for macro fusion."), cl::init(true)); + +namespace { + +static void fuseInstructionPair(ScheduleDAGMI &DAG, SUnit &FirstSU, + SUnit &SecondSU) { + // Create a single weak edge between the adjacent instrs. The only effect is + // to cause bottom-up scheduling to heavily prioritize the clustered instrs. + DAG.addEdge(&SecondSU, SDep(&FirstSU, SDep::Cluster)); + + // Adjust the latency between the anchor instr and its + // predecessors. + for (SDep &IDep : SecondSU.Preds) + if (IDep.getSUnit() == &FirstSU) + IDep.setLatency(0); + + // Adjust the latency between the dependent instr and its + // predecessors. + for (SDep &IDep : FirstSU.Succs) + if (IDep.getSUnit() == &SecondSU) + IDep.setLatency(0); + + DEBUG(dbgs() << DAG.MF.getName() << "(): Macro fuse "; + FirstSU.print(dbgs(), &DAG); dbgs() << " - "; + SecondSU.print(dbgs(), &DAG); dbgs() << " / "; + dbgs() << DAG.TII->getName(FirstSU.getInstr()->getOpcode()) << " - " << + DAG.TII->getName(SecondSU.getInstr()->getOpcode()) << '\n'; ); + + if (&SecondSU != &DAG.ExitSU) + // Make instructions dependent on FirstSU also dependent on SecondSU to + // prevent them from being scheduled between FirstSU and and SecondSU. + for (const SDep &SI : FirstSU.Succs) { + if (SI.getSUnit() == &SecondSU) + continue; + DEBUG(dbgs() << " Copy Succ "; + SI.getSUnit()->print(dbgs(), &DAG); dbgs() << '\n';); + DAG.addEdge(SI.getSUnit(), SDep(&SecondSU, SDep::Artificial)); + } + + ++NumFused; +} + + +/// \brief Post-process the DAG to create cluster edges between instrs that may +/// be fused by the processor into a single operation. +class MacroFusion : public ScheduleDAGMutation { + ShouldSchedulePredTy shouldScheduleAdjacent; + bool FuseBlock; + bool scheduleAdjacentImpl(ScheduleDAGMI &DAG, SUnit &AnchorSU); + +public: + MacroFusion(ShouldSchedulePredTy shouldScheduleAdjacent, bool FuseBlock) + : shouldScheduleAdjacent(shouldScheduleAdjacent), FuseBlock(FuseBlock) {} + + void apply(ScheduleDAGInstrs *DAGInstrs) override; +}; + +void MacroFusion::apply(ScheduleDAGInstrs *DAGInstrs) { + ScheduleDAGMI *DAG = static_cast(DAGInstrs); + + if (FuseBlock) + // For each of the SUnits in the scheduling block, try to fuse the instr in + // it with one in its predecessors. + for (SUnit &ISU : DAG->SUnits) + scheduleAdjacentImpl(*DAG, ISU); + + if (DAG->ExitSU.getInstr()) + // Try to fuse the instr in the ExitSU with one in its predecessors. + scheduleAdjacentImpl(*DAG, DAG->ExitSU); +} + +/// \brief Implement the fusion of instr pairs in the scheduling DAG, +/// anchored at the instr in AnchorSU.. +bool MacroFusion::scheduleAdjacentImpl(ScheduleDAGMI &DAG, SUnit &AnchorSU) { + const MachineInstr &AnchorMI = *AnchorSU.getInstr(); + const TargetInstrInfo &TII = *DAG.TII; + const TargetSubtargetInfo &ST = DAG.MF.getSubtarget(); + + // Check if the anchor instr may be fused. + if (!shouldScheduleAdjacent(TII, ST, nullptr, AnchorMI)) + return false; + + // Explorer for fusion candidates among the dependencies of the anchor instr. + for (SDep &Dep : AnchorSU.Preds) { + // Ignore dependencies that don't enforce ordering. + if (Dep.getKind() == SDep::Anti || Dep.getKind() == SDep::Output || + Dep.isWeak()) + continue; + + SUnit &DepSU = *Dep.getSUnit(); + if (DepSU.isBoundaryNode()) + continue; + + const MachineInstr *DepMI = DepSU.getInstr(); + if (!shouldScheduleAdjacent(TII, ST, DepMI, AnchorMI)) + continue; + + fuseInstructionPair(DAG, DepSU, AnchorSU); + return true; + } + + return false; +} + +} // end anonymous namespace + + +namespace llvm { + +std::unique_ptr +createMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent) { + if(EnableMacroFusion) + return llvm::make_unique(shouldScheduleAdjacent, true); + return nullptr; +} + +std::unique_ptr +createBranchMacroFusionDAGMutation(ShouldSchedulePredTy shouldScheduleAdjacent) { + if(EnableMacroFusion) + return llvm::make_unique(shouldScheduleAdjacent, false); + return nullptr; +} + +} // end namespace llvm diff --git a/contrib/llvm/lib/CodeGen/RegisterScavenging.cpp b/contrib/llvm/lib/CodeGen/RegisterScavenging.cpp index 1aed58c36e17..05e641d9489d 100644 --- a/contrib/llvm/lib/CodeGen/RegisterScavenging.cpp +++ b/contrib/llvm/lib/CodeGen/RegisterScavenging.cpp @@ -35,6 +35,7 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" +#include #include #include #include @@ -260,6 +261,14 @@ void RegScavenger::backward() { const MachineInstr &MI = *MBBI; LiveUnits.stepBackward(MI); + // Expire scavenge spill frameindex uses. + for (ScavengedInfo &I : Scavenged) { + if (I.Restore == &MI) { + I.Reg = 0; + I.Restore = nullptr; + } + } + if (MBBI == MBB->begin()) { MBBI = MachineBasicBlock::iterator(nullptr); Tracking = false; @@ -356,6 +365,80 @@ unsigned RegScavenger::findSurvivorReg(MachineBasicBlock::iterator StartMI, return Survivor; } +/// Given the bitvector \p Available of free register units at position +/// \p From. Search backwards to find a register that is part of \p +/// Candidates and not used/clobbered until the point \p To. If there is +/// multiple candidates continue searching and pick the one that is not used/ +/// clobbered for the longest time. +/// Returns the register and the earliest position we know it to be free or +/// the position MBB.end() if no register is available. +static std::pair +findSurvivorBackwards(const MachineRegisterInfo &MRI, + MachineBasicBlock::iterator From, MachineBasicBlock::iterator To, + const LiveRegUnits &LiveOut, ArrayRef AllocationOrder) { + bool FoundTo = false; + MCPhysReg Survivor = 0; + MachineBasicBlock::iterator Pos; + MachineBasicBlock &MBB = *From->getParent(); + unsigned InstrLimit = 25; + unsigned InstrCountDown = InstrLimit; + const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); + LiveRegUnits Used(TRI); + + for (MachineBasicBlock::iterator I = From;; --I) { + const MachineInstr &MI = *I; + + Used.accumulateBackward(MI); + + if (I == To) { + // See if one of the registers in RC wasn't used so far. + for (MCPhysReg Reg : AllocationOrder) { + if (!MRI.isReserved(Reg) && Used.available(Reg) && + LiveOut.available(Reg)) + return std::make_pair(Reg, MBB.end()); + } + // Otherwise we will continue up to InstrLimit instructions to find + // the register which is not defined/used for the longest time. + FoundTo = true; + Pos = To; + } + if (FoundTo) { + if (Survivor == 0 || !Used.available(Survivor)) { + MCPhysReg AvilableReg = 0; + for (MCPhysReg Reg : AllocationOrder) { + if (!MRI.isReserved(Reg) && Used.available(Reg)) { + AvilableReg = Reg; + break; + } + } + if (AvilableReg == 0) + break; + Survivor = AvilableReg; + } + if (--InstrCountDown == 0) + break; + + // Keep searching when we find a vreg since the spilled register will + // be usefull for this other vreg as well later. + bool FoundVReg = false; + for (const MachineOperand &MO : MI.operands()) { + if (MO.isReg() && TargetRegisterInfo::isVirtualRegister(MO.getReg())) { + FoundVReg = true; + break; + } + } + if (FoundVReg) { + InstrCountDown = InstrLimit; + Pos = I; + } + if (I == MBB.begin()) + break; + } + } + + return std::make_pair(Survivor, Pos); +} + static unsigned getFrameIndexOperandNum(MachineInstr &MI) { unsigned i = 0; while (!MI.getOperand(i).isFI()) { @@ -365,6 +448,81 @@ static unsigned getFrameIndexOperandNum(MachineInstr &MI) { return i; } +RegScavenger::ScavengedInfo & +RegScavenger::spill(unsigned Reg, const TargetRegisterClass &RC, int SPAdj, + MachineBasicBlock::iterator Before, + MachineBasicBlock::iterator &UseMI) { + // Find an available scavenging slot with size and alignment matching + // the requirements of the class RC. + const MachineFunction &MF = *Before->getParent()->getParent(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); + unsigned NeedSize = TRI->getSpillSize(RC); + unsigned NeedAlign = TRI->getSpillAlignment(RC); + + unsigned SI = Scavenged.size(), Diff = std::numeric_limits::max(); + int FIB = MFI.getObjectIndexBegin(), FIE = MFI.getObjectIndexEnd(); + for (unsigned I = 0; I < Scavenged.size(); ++I) { + if (Scavenged[I].Reg != 0) + continue; + // Verify that this slot is valid for this register. + int FI = Scavenged[I].FrameIndex; + if (FI < FIB || FI >= FIE) + continue; + unsigned S = MFI.getObjectSize(FI); + unsigned A = MFI.getObjectAlignment(FI); + if (NeedSize > S || NeedAlign > A) + continue; + // Avoid wasting slots with large size and/or large alignment. Pick one + // that is the best fit for this register class (in street metric). + // Picking a larger slot than necessary could happen if a slot for a + // larger register is reserved before a slot for a smaller one. When + // trying to spill a smaller register, the large slot would be found + // first, thus making it impossible to spill the larger register later. + unsigned D = (S-NeedSize) + (A-NeedAlign); + if (D < Diff) { + SI = I; + Diff = D; + } + } + + if (SI == Scavenged.size()) { + // We need to scavenge a register but have no spill slot, the target + // must know how to do it (if not, we'll assert below). + Scavenged.push_back(ScavengedInfo(FIE)); + } + + // Avoid infinite regress + Scavenged[SI].Reg = Reg; + + // If the target knows how to save/restore the register, let it do so; + // otherwise, use the emergency stack spill slot. + if (!TRI->saveScavengerRegister(*MBB, Before, UseMI, &RC, Reg)) { + // Spill the scavenged register before \p Before. + int FI = Scavenged[SI].FrameIndex; + if (FI < FIB || FI >= FIE) { + std::string Msg = std::string("Error while trying to spill ") + + TRI->getName(Reg) + " from class " + TRI->getRegClassName(&RC) + + ": Cannot scavenge register without an emergency spill slot!"; + report_fatal_error(Msg.c_str()); + } + TII->storeRegToStackSlot(*MBB, Before, Reg, true, Scavenged[SI].FrameIndex, + &RC, TRI); + MachineBasicBlock::iterator II = std::prev(Before); + + unsigned FIOperandNum = getFrameIndexOperandNum(*II); + TRI->eliminateFrameIndex(II, SPAdj, FIOperandNum, this); + + // Restore the scavenged register before its use (or first terminator). + TII->loadRegFromStackSlot(*MBB, UseMI, Reg, Scavenged[SI].FrameIndex, + &RC, TRI); + II = std::prev(UseMI); + + FIOperandNum = getFrameIndexOperandNum(*II); + TRI->eliminateFrameIndex(II, SPAdj, FIOperandNum, this); + } + return Scavenged[SI]; +} + unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, MachineBasicBlock::iterator I, int SPAdj) { @@ -398,78 +556,8 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, return SReg; } - // Find an available scavenging slot with size and alignment matching - // the requirements of the class RC. - const MachineFrameInfo &MFI = MF.getFrameInfo(); - unsigned NeedSize = TRI->getSpillSize(*RC); - unsigned NeedAlign = TRI->getSpillAlignment(*RC); - - unsigned SI = Scavenged.size(), Diff = std::numeric_limits::max(); - int FIB = MFI.getObjectIndexBegin(), FIE = MFI.getObjectIndexEnd(); - for (unsigned I = 0; I < Scavenged.size(); ++I) { - if (Scavenged[I].Reg != 0) - continue; - // Verify that this slot is valid for this register. - int FI = Scavenged[I].FrameIndex; - if (FI < FIB || FI >= FIE) - continue; - unsigned S = MFI.getObjectSize(FI); - unsigned A = MFI.getObjectAlignment(FI); - if (NeedSize > S || NeedAlign > A) - continue; - // Avoid wasting slots with large size and/or large alignment. Pick one - // that is the best fit for this register class (in street metric). - // Picking a larger slot than necessary could happen if a slot for a - // larger register is reserved before a slot for a smaller one. When - // trying to spill a smaller register, the large slot would be found - // first, thus making it impossible to spill the larger register later. - unsigned D = (S-NeedSize) + (A-NeedAlign); - if (D < Diff) { - SI = I; - Diff = D; - } - } - - if (SI == Scavenged.size()) { - // We need to scavenge a register but have no spill slot, the target - // must know how to do it (if not, we'll assert below). - Scavenged.push_back(ScavengedInfo(FIE)); - } - - // Avoid infinite regress - Scavenged[SI].Reg = SReg; - - // If the target knows how to save/restore the register, let it do so; - // otherwise, use the emergency stack spill slot. - if (!TRI->saveScavengerRegister(*MBB, I, UseMI, RC, SReg)) { - // Spill the scavenged register before I. - int FI = Scavenged[SI].FrameIndex; - if (FI < FIB || FI >= FIE) { - std::string Msg = std::string("Error while trying to spill ") + - TRI->getName(SReg) + " from class " + TRI->getRegClassName(RC) + - ": Cannot scavenge register without an emergency spill slot!"; - report_fatal_error(Msg.c_str()); - } - TII->storeRegToStackSlot(*MBB, I, SReg, true, Scavenged[SI].FrameIndex, - RC, TRI); - MachineBasicBlock::iterator II = std::prev(I); - - unsigned FIOperandNum = getFrameIndexOperandNum(*II); - TRI->eliminateFrameIndex(II, SPAdj, FIOperandNum, this); - - // Restore the scavenged register before its use (or first terminator). - TII->loadRegFromStackSlot(*MBB, UseMI, SReg, Scavenged[SI].FrameIndex, - RC, TRI); - II = std::prev(UseMI); - - FIOperandNum = getFrameIndexOperandNum(*II); - TRI->eliminateFrameIndex(II, SPAdj, FIOperandNum, this); - } - - Scavenged[SI].Restore = &*std::prev(UseMI); - - // Doing this here leads to infinite regress. - // Scavenged[SI].Reg = SReg; + ScavengedInfo &Scavenged = spill(SReg, *RC, SPAdj, I, UseMI); + Scavenged.Restore = &*std::prev(UseMI); DEBUG(dbgs() << "Scavenged register (with spill): " << TRI->getName(SReg) << "\n"); @@ -477,85 +565,195 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC, return SReg; } +unsigned RegScavenger::scavengeRegisterBackwards(const TargetRegisterClass &RC, + MachineBasicBlock::iterator To, + bool RestoreAfter, int SPAdj) { + const MachineBasicBlock &MBB = *To->getParent(); + const MachineFunction &MF = *MBB.getParent(); + + // Find the register whose use is furthest away. + MachineBasicBlock::iterator UseMI; + ArrayRef AllocationOrder = RC.getRawAllocationOrder(MF); + std::pair P = + findSurvivorBackwards(*MRI, MBBI, To, LiveUnits, AllocationOrder); + MCPhysReg Reg = P.first; + MachineBasicBlock::iterator SpillBefore = P.second; + assert(Reg != 0 && "No register left to scavenge!"); + // Found an available register? + if (SpillBefore != MBB.end()) { + MachineBasicBlock::iterator ReloadAfter = + RestoreAfter ? std::next(MBBI) : MBBI; + MachineBasicBlock::iterator ReloadBefore = std::next(ReloadAfter); + DEBUG(dbgs() << "Reload before: " << *ReloadBefore << '\n'); + ScavengedInfo &Scavenged = spill(Reg, RC, SPAdj, SpillBefore, ReloadBefore); + Scavenged.Restore = &*std::prev(SpillBefore); + LiveUnits.removeReg(Reg); + DEBUG(dbgs() << "Scavenged register with spill: " << PrintReg(Reg, TRI) + << " until " << *SpillBefore); + } else { + DEBUG(dbgs() << "Scavenged free register: " << PrintReg(Reg, TRI) << '\n'); + } + return Reg; +} + +/// Allocate a register for the virtual register \p VReg. The last use of +/// \p VReg is around the current position of the register scavenger \p RS. +/// \p ReserveAfter controls whether the scavenged register needs to be reserved +/// after the current instruction, otherwise it will only be reserved before the +/// current instruction. +static unsigned scavengeVReg(MachineRegisterInfo &MRI, RegScavenger &RS, + unsigned VReg, bool ReserveAfter) { + const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); +#ifndef NDEBUG + // Verify that all definitions and uses are in the same basic block. + const MachineBasicBlock *CommonMBB = nullptr; + // Real definition for the reg, re-definitions are not considered. + const MachineInstr *RealDef = nullptr; + for (MachineOperand &MO : MRI.reg_nodbg_operands(VReg)) { + MachineBasicBlock *MBB = MO.getParent()->getParent(); + if (CommonMBB == nullptr) + CommonMBB = MBB; + assert(MBB == CommonMBB && "All defs+uses must be in the same basic block"); + if (MO.isDef()) { + const MachineInstr &MI = *MO.getParent(); + if (!MI.readsRegister(VReg, &TRI)) { + assert((!RealDef || RealDef == &MI) && + "Can have at most one definition which is not a redefinition"); + RealDef = &MI; + } + } + } + assert(RealDef != nullptr && "Must have at least 1 Def"); +#endif + + // We should only have one definition of the register. However to accomodate + // the requirements of two address code we also allow definitions in + // subsequent instructions provided they also read the register. That way + // we get a single contiguous lifetime. + // + // Definitions in MRI.def_begin() are unordered, search for the first. + MachineRegisterInfo::def_iterator FirstDef = + std::find_if(MRI.def_begin(VReg), MRI.def_end(), + [VReg, &TRI](const MachineOperand &MO) { + return !MO.getParent()->readsRegister(VReg, &TRI); + }); + assert(FirstDef != MRI.def_end() && + "Must have one definition that does not redefine vreg"); + MachineInstr &DefMI = *FirstDef->getParent(); + + // The register scavenger will report a free register inserting an emergency + // spill/reload if necessary. + int SPAdj = 0; + const TargetRegisterClass &RC = *MRI.getRegClass(VReg); + unsigned SReg = RS.scavengeRegisterBackwards(RC, DefMI.getIterator(), + ReserveAfter, SPAdj); + MRI.replaceRegWith(VReg, SReg); + ++NumScavengedRegs; + return SReg; +} + +/// Allocate (scavenge) vregs inside a single basic block. +/// Returns true if the target spill callback created new vregs and a 2nd pass +/// is necessary. +static bool scavengeFrameVirtualRegsInBlock(MachineRegisterInfo &MRI, + RegScavenger &RS, + MachineBasicBlock &MBB) { + const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo(); + RS.enterBasicBlockEnd(MBB); + + unsigned InitialNumVirtRegs = MRI.getNumVirtRegs(); + bool NextInstructionReadsVReg = false; + for (MachineBasicBlock::iterator I = MBB.end(); I != MBB.begin(); ) { + --I; + // Move RegScavenger to the position between *I and *std::next(I). + RS.backward(I); + + // Look for unassigned vregs in the uses of *std::next(I). + if (NextInstructionReadsVReg) { + MachineBasicBlock::iterator N = std::next(I); + const MachineInstr &NMI = *N; + for (const MachineOperand &MO : NMI.operands()) { + if (!MO.isReg()) + continue; + unsigned Reg = MO.getReg(); + // We only care about virtual registers and ignore virtual registers + // created by the target callbacks in the process (those will be handled + // in a scavenging round). + if (!TargetRegisterInfo::isVirtualRegister(Reg) || + TargetRegisterInfo::virtReg2Index(Reg) >= InitialNumVirtRegs) + continue; + if (!MO.readsReg()) + continue; + + unsigned SReg = scavengeVReg(MRI, RS, Reg, true); + N->addRegisterKilled(SReg, &TRI, false); + RS.setRegUsed(SReg); + } + } + + // Look for unassigned vregs in the defs of *I. + NextInstructionReadsVReg = false; + const MachineInstr &MI = *I; + for (const MachineOperand &MO : MI.operands()) { + if (!MO.isReg()) + continue; + unsigned Reg = MO.getReg(); + // Only vregs, no newly created vregs (see above). + if (!TargetRegisterInfo::isVirtualRegister(Reg) || + TargetRegisterInfo::virtReg2Index(Reg) >= InitialNumVirtRegs) + continue; + // We have to look at all operands anyway so we can precalculate here + // whether there is a reading operand. This allows use to skip the use + // step in the next iteration if there was none. + assert(!MO.isInternalRead() && "Cannot assign inside bundles"); + assert((!MO.isUndef() || MO.isDef()) && "Cannot handle undef uses"); + if (MO.readsReg()) { + NextInstructionReadsVReg = true; + } + if (MO.isDef()) { + unsigned SReg = scavengeVReg(MRI, RS, Reg, false); + I->addRegisterDead(SReg, &TRI, false); + } + } + } +#ifndef NDEBUG + for (const MachineOperand &MO : MBB.front().operands()) { + if (!MO.isReg() || !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + continue; + assert(!MO.isInternalRead() && "Cannot assign inside bundles"); + assert((!MO.isUndef() || MO.isDef()) && "Cannot handle undef uses"); + assert(!MO.readsReg() && "Vreg use in first instruction not allowed"); + } +#endif + + return MRI.getNumVirtRegs() != InitialNumVirtRegs; +} + void llvm::scavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger &RS) { // FIXME: Iterating over the instruction stream is unnecessary. We can simply // iterate over the vreg use list, which at this point only contains machine // operands for which eliminateFrameIndex need a new scratch reg. + MachineRegisterInfo &MRI = MF.getRegInfo(); + // Shortcut. + if (MRI.getNumVirtRegs() == 0) { + MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs); + return; + } // Run through the instructions and find any virtual registers. - MachineRegisterInfo &MRI = MF.getRegInfo(); for (MachineBasicBlock &MBB : MF) { - RS.enterBasicBlock(MBB); + if (MBB.empty()) + continue; - int SPAdj = 0; - - // The instruction stream may change in the loop, so check MBB.end() - // directly. - for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) { - // We might end up here again with a NULL iterator if we scavenged a - // register for which we inserted spill code for definition by what was - // originally the first instruction in MBB. - if (I == MachineBasicBlock::iterator(nullptr)) - I = MBB.begin(); - - const MachineInstr &MI = *I; - MachineBasicBlock::iterator J = std::next(I); - MachineBasicBlock::iterator P = - I == MBB.begin() ? MachineBasicBlock::iterator(nullptr) - : std::prev(I); - - // RS should process this instruction before we might scavenge at this - // location. This is because we might be replacing a virtual register - // defined by this instruction, and if so, registers killed by this - // instruction are available, and defined registers are not. - RS.forward(I); - - for (const MachineOperand &MO : MI.operands()) { - if (!MO.isReg()) - continue; - unsigned Reg = MO.getReg(); - if (!TargetRegisterInfo::isVirtualRegister(Reg)) - continue; - - // When we first encounter a new virtual register, it - // must be a definition. - assert(MO.isDef() && "frame index virtual missing def!"); - // Scavenge a new scratch register - const TargetRegisterClass *RC = MRI.getRegClass(Reg); - unsigned ScratchReg = RS.scavengeRegister(RC, J, SPAdj); - - ++NumScavengedRegs; - - // Replace this reference to the virtual register with the - // scratch register. - assert(ScratchReg && "Missing scratch register!"); - MRI.replaceRegWith(Reg, ScratchReg); - - // Because this instruction was processed by the RS before this - // register was allocated, make sure that the RS now records the - // register as being used. - RS.setRegUsed(ScratchReg); - } - - // If the scavenger needed to use one of its spill slots, the - // spill code will have been inserted in between I and J. This is a - // problem because we need the spill code before I: Move I to just - // prior to J. - if (I != std::prev(J)) { - MBB.splice(J, &MBB, I); - - // Before we move I, we need to prepare the RS to visit I again. - // Specifically, RS will assert if it sees uses of registers that - // it believes are undefined. Because we have already processed - // register kills in I, when it visits I again, it will believe that - // those registers are undefined. To avoid this situation, unprocess - // the instruction I. - assert(RS.getCurrentPosition() == I && - "The register scavenger has an unexpected position"); - I = P; - RS.unprocess(P); - } else - ++I; + bool Again = scavengeFrameVirtualRegsInBlock(MRI, RS, MBB); + if (Again) { + DEBUG(dbgs() << "Warning: Required two scavenging passes for block " + << MBB.getName() << '\n'); + Again = scavengeFrameVirtualRegsInBlock(MRI, RS, MBB); + // The target required a 2nd run (because it created new vregs while + // spilling). Refuse to do another pass to keep compiletime in check. + if (Again) + report_fatal_error("Incomplete scavenging after 2nd pass"); } } diff --git a/contrib/llvm/lib/CodeGen/RegisterUsageInfo.cpp b/contrib/llvm/lib/CodeGen/RegisterUsageInfo.cpp index d7a3ac080823..30757f070cad 100644 --- a/contrib/llvm/lib/CodeGen/RegisterUsageInfo.cpp +++ b/contrib/llvm/lib/CodeGen/RegisterUsageInfo.cpp @@ -1,4 +1,4 @@ -//===- RegisterUsageInfo.cpp - Register Usage Informartion Storage --------===// +//===- RegisterUsageInfo.cpp - Register Usage Information Storage ---------===// // // The LLVM Compiler Infrastructure // @@ -38,7 +38,7 @@ static cl::opt DumpRegUsage( cl::desc("print register usage details collected for analysis.")); INITIALIZE_PASS(PhysicalRegisterUsageInfo, "reg-usage-info", - "Register Usage Informartion Stroage", false, true) + "Register Usage Information Storage", false, true) char PhysicalRegisterUsageInfo::ID = 0; diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 2d4422d94a17..d02dcb6f4439 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -25,6 +25,7 @@ #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGAddressAnalysis.h" #include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" @@ -469,7 +470,8 @@ namespace { /// \return True if a merged store was created. bool MergeStoresOfConstantsOrVecElts(SmallVectorImpl &StoreNodes, EVT MemVT, unsigned NumStores, - bool IsConstantSrc, bool UseVector); + bool IsConstantSrc, bool UseVector, + bool UseTrunc); /// This is a helper function for MergeConsecutiveStores. /// Stores that may be merged are placed in StoreNodes. @@ -2549,14 +2551,14 @@ SDValue DAGCombiner::visitMUL(SDNode *N) { !DAG.isConstantIntBuildVectorOrConstantInt(N1)) return DAG.getNode(ISD::MUL, SDLoc(N), VT, N1, N0); // fold (mul x, 0) -> 0 - if (N1IsConst && ConstValue1 == 0) + if (N1IsConst && ConstValue1.isNullValue()) return N1; // We require a splat of the entire scalar bit width for non-contiguous // bit patterns. bool IsFullSplat = ConstValue1.getBitWidth() == VT.getScalarSizeInBits(); // fold (mul x, 1) -> x - if (N1IsConst && ConstValue1 == 1 && IsFullSplat) + if (N1IsConst && ConstValue1.isOneValue() && IsFullSplat) return N0; if (SDValue NewSel = foldBinOpIntoSelect(N)) @@ -3685,7 +3687,7 @@ SDValue DAGCombiner::visitAND(SDNode *N) { // fold (and (or x, C), D) -> D if (C & D) == D if (N1C && N0.getOpcode() == ISD::OR) if (ConstantSDNode *ORI = isConstOrConstSplat(N0.getOperand(1))) - if ((ORI->getAPIntValue() & N1C->getAPIntValue()) == N1C->getAPIntValue()) + if (N1C->getAPIntValue().isSubsetOf(ORI->getAPIntValue())) return N1; // fold (and (any_ext V), c) -> (zero_ext V) if 'and' only clears top bits. if (N1C && N0.getOpcode() == ISD::ANY_EXTEND) { @@ -4693,110 +4695,6 @@ SDNode *DAGCombiner::MatchRotate(SDValue LHS, SDValue RHS, const SDLoc &DL) { return nullptr; } -namespace { -/// Helper struct to parse and store a memory address as base + index + offset. -/// We ignore sign extensions when it is safe to do so. -/// The following two expressions are not equivalent. To differentiate we need -/// to store whether there was a sign extension involved in the index -/// computation. -/// (load (i64 add (i64 copyfromreg %c) -/// (i64 signextend (add (i8 load %index) -/// (i8 1)))) -/// vs -/// -/// (load (i64 add (i64 copyfromreg %c) -/// (i64 signextend (i32 add (i32 signextend (i8 load %index)) -/// (i32 1))))) -struct BaseIndexOffset { - SDValue Base; - SDValue Index; - int64_t Offset; - bool IsIndexSignExt; - - BaseIndexOffset() : Offset(0), IsIndexSignExt(false) {} - - BaseIndexOffset(SDValue Base, SDValue Index, int64_t Offset, - bool IsIndexSignExt) : - Base(Base), Index(Index), Offset(Offset), IsIndexSignExt(IsIndexSignExt) {} - - bool equalBaseIndex(const BaseIndexOffset &Other) { - return Other.Base == Base && Other.Index == Index && - Other.IsIndexSignExt == IsIndexSignExt; - } - - /// Parses tree in Ptr for base, index, offset addresses. - static BaseIndexOffset match(SDValue Ptr, SelectionDAG &DAG, - int64_t PartialOffset = 0) { - bool IsIndexSignExt = false; - - // Split up a folded GlobalAddress+Offset into its component parts. - if (GlobalAddressSDNode *GA = dyn_cast(Ptr)) - if (GA->getOpcode() == ISD::GlobalAddress && GA->getOffset() != 0) { - return BaseIndexOffset(DAG.getGlobalAddress(GA->getGlobal(), - SDLoc(GA), - GA->getValueType(0), - /*Offset=*/PartialOffset, - /*isTargetGA=*/false, - GA->getTargetFlags()), - SDValue(), - GA->getOffset(), - IsIndexSignExt); - } - - // We only can pattern match BASE + INDEX + OFFSET. If Ptr is not an ADD - // instruction, then it could be just the BASE or everything else we don't - // know how to handle. Just use Ptr as BASE and give up. - if (Ptr->getOpcode() != ISD::ADD) - return BaseIndexOffset(Ptr, SDValue(), PartialOffset, IsIndexSignExt); - - // We know that we have at least an ADD instruction. Try to pattern match - // the simple case of BASE + OFFSET. - if (isa(Ptr->getOperand(1))) { - int64_t Offset = cast(Ptr->getOperand(1))->getSExtValue(); - return match(Ptr->getOperand(0), DAG, Offset + PartialOffset); - } - - // Inside a loop the current BASE pointer is calculated using an ADD and a - // MUL instruction. In this case Ptr is the actual BASE pointer. - // (i64 add (i64 %array_ptr) - // (i64 mul (i64 %induction_var) - // (i64 %element_size))) - if (Ptr->getOperand(1)->getOpcode() == ISD::MUL) - return BaseIndexOffset(Ptr, SDValue(), PartialOffset, IsIndexSignExt); - - // Look at Base + Index + Offset cases. - SDValue Base = Ptr->getOperand(0); - SDValue IndexOffset = Ptr->getOperand(1); - - // Skip signextends. - if (IndexOffset->getOpcode() == ISD::SIGN_EXTEND) { - IndexOffset = IndexOffset->getOperand(0); - IsIndexSignExt = true; - } - - // Either the case of Base + Index (no offset) or something else. - if (IndexOffset->getOpcode() != ISD::ADD) - return BaseIndexOffset(Base, IndexOffset, PartialOffset, IsIndexSignExt); - - // Now we have the case of Base + Index + offset. - SDValue Index = IndexOffset->getOperand(0); - SDValue Offset = IndexOffset->getOperand(1); - - if (!isa(Offset)) - return BaseIndexOffset(Ptr, SDValue(), PartialOffset, IsIndexSignExt); - - // Ignore signextends. - if (Index->getOpcode() == ISD::SIGN_EXTEND) { - Index = Index->getOperand(0); - IsIndexSignExt = true; - } else IsIndexSignExt = false; - - int64_t Off = cast(Offset)->getSExtValue(); - return BaseIndexOffset(Base, Index, Off + PartialOffset, IsIndexSignExt); - } -}; -} // namespace - namespace { /// Represents known origin of an individual byte in load combine pattern. The /// value of the byte is either constant zero or comes from memory. @@ -5017,14 +4915,15 @@ SDValue DAGCombiner::MatchLoadCombine(SDNode *N) { return SDValue(); // Loads must share the same base address - BaseIndexOffset Ptr = BaseIndexOffset::match(L->getBasePtr(), DAG); + BaseIndexOffset Ptr = BaseIndexOffset::match(L->getBasePtr()); + int64_t ByteOffsetFromBase = 0; if (!Base) Base = Ptr; - else if (!Base->equalBaseIndex(Ptr)) + else if (!Base->equalBaseIndex(Ptr, DAG, ByteOffsetFromBase)) return SDValue(); // Calculate the offset of the current byte from the base address - int64_t ByteOffsetFromBase = Ptr.Offset + MemoryByteOffset(*P); + ByteOffsetFromBase += MemoryByteOffset(*P); ByteOffsets[i] = ByteOffsetFromBase; // Remember the first byte load @@ -12378,8 +12277,8 @@ SDValue DAGCombiner::getMergeStoreChains(SmallVectorImpl &StoreNodes, } bool DAGCombiner::MergeStoresOfConstantsOrVecElts( - SmallVectorImpl &StoreNodes, EVT MemVT, - unsigned NumStores, bool IsConstantSrc, bool UseVector) { + SmallVectorImpl &StoreNodes, EVT MemVT, unsigned NumStores, + bool IsConstantSrc, bool UseVector, bool UseTrunc) { // Make sure we have something to merge. if (NumStores < 2) return false; @@ -12464,7 +12363,7 @@ bool DAGCombiner::MergeStoresOfConstantsOrVecElts( // make sure we use trunc store if it's necessary to be legal. SDValue NewStore; - if (TLI.isTypeLegal(StoredVal.getValueType())) { + if (UseVector || !UseTrunc) { NewStore = DAG.getStore(NewChain, DL, StoredVal, FirstInChain->getBasePtr(), FirstInChain->getPointerInfo(), FirstInChain->getAlignment()); @@ -12495,15 +12394,15 @@ void DAGCombiner::getStoreMergeCandidates( StoreSDNode *St, SmallVectorImpl &StoreNodes) { // This holds the base pointer, index, and the offset in bytes from the base // pointer. - BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr(), DAG); + BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr()); EVT MemVT = St->getMemoryVT(); // We must have a base and an offset. - if (!BasePtr.Base.getNode()) + if (!BasePtr.getBase().getNode()) return; // Do not handle stores to undef base pointers. - if (BasePtr.Base.isUndef()) + if (BasePtr.getBase().isUndef()) return; bool IsConstantSrc = isa(St->getValue()) || @@ -12515,10 +12414,11 @@ void DAGCombiner::getStoreMergeCandidates( BaseIndexOffset LBasePtr; // Match on loadbaseptr if relevant. if (IsLoadSrc) - LBasePtr = BaseIndexOffset::match( - cast(St->getValue())->getBasePtr(), DAG); + LBasePtr = + BaseIndexOffset::match(cast(St->getValue())->getBasePtr()); - auto CandidateMatch = [&](StoreSDNode *Other, BaseIndexOffset &Ptr) -> bool { + auto CandidateMatch = [&](StoreSDNode *Other, BaseIndexOffset &Ptr, + int64_t &Offset) -> bool { if (Other->isVolatile() || Other->isIndexed()) return false; // We can merge constant floats to equivalent integers @@ -12529,8 +12429,8 @@ void DAGCombiner::getStoreMergeCandidates( if (IsLoadSrc) { // The Load's Base Ptr must also match if (LoadSDNode *OtherLd = dyn_cast(Other->getValue())) { - auto LPtr = BaseIndexOffset::match(OtherLd->getBasePtr(), DAG); - if (!(LBasePtr.equalBaseIndex(LPtr))) + auto LPtr = BaseIndexOffset::match(OtherLd->getBasePtr()); + if (!(LBasePtr.equalBaseIndex(LPtr, DAG))) return false; } else return false; @@ -12543,8 +12443,8 @@ void DAGCombiner::getStoreMergeCandidates( if (!(Other->getValue().getOpcode() == ISD::EXTRACT_VECTOR_ELT || Other->getValue().getOpcode() == ISD::EXTRACT_SUBVECTOR)) return false; - Ptr = BaseIndexOffset::match(Other->getBasePtr(), DAG); - return (Ptr.equalBaseIndex(BasePtr)); + Ptr = BaseIndexOffset::match(Other->getBasePtr()); + return (BasePtr.equalBaseIndex(Ptr, DAG, Offset)); }; // We looking for a root node which is an ancestor to all mergable // stores. We search up through a load, to our root and then down @@ -12572,16 +12472,18 @@ void DAGCombiner::getStoreMergeCandidates( if (I2.getOperandNo() == 0) if (StoreSDNode *OtherST = dyn_cast(*I2)) { BaseIndexOffset Ptr; - if (CandidateMatch(OtherST, Ptr)) - StoreNodes.push_back(MemOpLink(OtherST, Ptr.Offset)); + int64_t PtrDiff; + if (CandidateMatch(OtherST, Ptr, PtrDiff)) + StoreNodes.push_back(MemOpLink(OtherST, PtrDiff)); } } else for (auto I = RootNode->use_begin(), E = RootNode->use_end(); I != E; ++I) if (I.getOperandNo() == 0) if (StoreSDNode *OtherST = dyn_cast(*I)) { BaseIndexOffset Ptr; - if (CandidateMatch(OtherST, Ptr)) - StoreNodes.push_back(MemOpLink(OtherST, Ptr.Offset)); + int64_t PtrDiff; + if (CandidateMatch(OtherST, Ptr, PtrDiff)) + StoreNodes.push_back(MemOpLink(OtherST, PtrDiff)); } } @@ -12721,8 +12623,9 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { LSBaseSDNode *FirstInChain = StoreNodes[0].MemNode; unsigned FirstStoreAS = FirstInChain->getAddressSpace(); unsigned FirstStoreAlign = FirstInChain->getAlignment(); - unsigned LastLegalType = 0; - unsigned LastLegalVectorType = 0; + unsigned LastLegalType = 1; + unsigned LastLegalVectorType = 1; + bool LastIntegerTrunc = false; bool NonZero = false; for (unsigned i = 0; i < NumConsecutiveStores; ++i) { StoreSDNode *ST = cast(StoreNodes[i].MemNode); @@ -12747,6 +12650,7 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { TLI.allowsMemoryAccess(Context, DL, StoreTy, FirstStoreAS, FirstStoreAlign, &IsFast) && IsFast) { + LastIntegerTrunc = false; LastLegalType = i + 1; // Or check whether a truncstore is legal. } else if (TLI.getTypeAction(Context, StoreTy) == @@ -12758,6 +12662,7 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { TLI.allowsMemoryAccess(Context, DL, LegalizedStoredValueTy, FirstStoreAS, FirstStoreAlign, &IsFast) && IsFast) { + LastIntegerTrunc = true; LastLegalType = i + 1; } } @@ -12787,8 +12692,8 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { bool UseVector = (LastLegalVectorType > LastLegalType) && !NoVectors; unsigned NumElem = (UseVector) ? LastLegalVectorType : LastLegalType; - bool Merged = MergeStoresOfConstantsOrVecElts(StoreNodes, MemVT, NumElem, - true, UseVector); + bool Merged = MergeStoresOfConstantsOrVecElts( + StoreNodes, MemVT, NumElem, true, UseVector, LastIntegerTrunc); if (!Merged) { StoreNodes.erase(StoreNodes.begin(), StoreNodes.begin() + NumElem); continue; @@ -12836,7 +12741,7 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { } bool Merged = MergeStoresOfConstantsOrVecElts( - StoreNodes, MemVT, NumStoresToMerge, false, true); + StoreNodes, MemVT, NumStoresToMerge, false, true, false); if (!Merged) { StoreNodes.erase(StoreNodes.begin(), StoreNodes.begin() + NumStoresToMerge); @@ -12881,11 +12786,12 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { if (Ld->getMemoryVT() != MemVT) break; - BaseIndexOffset LdPtr = BaseIndexOffset::match(Ld->getBasePtr(), DAG); + BaseIndexOffset LdPtr = BaseIndexOffset::match(Ld->getBasePtr()); // If this is not the first ptr that we check. - if (LdBasePtr.Base.getNode()) { + int64_t LdOffset = 0; + if (LdBasePtr.getBase().getNode()) { // The base ptr must be the same. - if (!LdPtr.equalBaseIndex(LdBasePtr)) + if (!LdBasePtr.equalBaseIndex(LdPtr, DAG, LdOffset)) break; } else { // Check that all other base pointers are the same as this one. @@ -12893,7 +12799,7 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { } // We found a potential memory operand to merge. - LoadNodes.push_back(MemOpLink(Ld, LdPtr.Offset)); + LoadNodes.push_back(MemOpLink(Ld, LdOffset)); } if (LoadNodes.size() < 2) { @@ -12919,10 +12825,11 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { // Scan the memory operations on the chain and find the first // non-consecutive load memory address. These variables hold the index in // the store node array. - unsigned LastConsecutiveLoad = 0; + unsigned LastConsecutiveLoad = 1; // This variable refers to the size and not index in the array. - unsigned LastLegalVectorType = 0; - unsigned LastLegalIntegerType = 0; + unsigned LastLegalVectorType = 1; + unsigned LastLegalIntegerType = 1; + bool DoIntegerTruncate = false; StartAddress = LoadNodes[0].OffsetFromBase; SDValue FirstChain = FirstLoad->getChain(); for (unsigned i = 1; i < LoadNodes.size(); ++i) { @@ -12958,11 +12865,12 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { IsFastSt && TLI.allowsMemoryAccess(Context, DL, StoreTy, FirstLoadAS, FirstLoadAlign, &IsFastLd) && - IsFastLd) + IsFastLd) { LastLegalIntegerType = i + 1; - // Or check whether a truncstore and extload is legal. - else if (TLI.getTypeAction(Context, StoreTy) == - TargetLowering::TypePromoteInteger) { + DoIntegerTruncate = false; + // Or check whether a truncstore and extload is legal. + } else if (TLI.getTypeAction(Context, StoreTy) == + TargetLowering::TypePromoteInteger) { EVT LegalizedStoredValueTy = TLI.getTypeToTransformTo(Context, StoreTy); if (TLI.isTruncStoreLegal(LegalizedStoredValueTy, StoreTy) && TLI.canMergeStoresTo(FirstStoreAS, LegalizedStoredValueTy) && @@ -12976,8 +12884,10 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { IsFastSt && TLI.allowsMemoryAccess(Context, DL, StoreTy, FirstLoadAS, FirstLoadAlign, &IsFastLd) && - IsFastLd) + IsFastLd) { LastLegalIntegerType = i + 1; + DoIntegerTruncate = true; + } } } @@ -13012,17 +12922,31 @@ bool DAGCombiner::MergeConsecutiveStores(StoreSDNode *St) { // The merged loads are required to have the same incoming chain, so // using the first's chain is acceptable. - SDValue NewLoad = DAG.getLoad(JointMemOpVT, LoadDL, FirstLoad->getChain(), - FirstLoad->getBasePtr(), - FirstLoad->getPointerInfo(), FirstLoadAlign); SDValue NewStoreChain = getMergeStoreChains(StoreNodes, NumElem); - AddToWorklist(NewStoreChain.getNode()); - SDValue NewStore = DAG.getStore( - NewStoreChain, StoreDL, NewLoad, FirstInChain->getBasePtr(), - FirstInChain->getPointerInfo(), FirstStoreAlign); + SDValue NewLoad, NewStore; + if (UseVectorTy || !DoIntegerTruncate) { + NewLoad = DAG.getLoad(JointMemOpVT, LoadDL, FirstLoad->getChain(), + FirstLoad->getBasePtr(), + FirstLoad->getPointerInfo(), FirstLoadAlign); + NewStore = DAG.getStore(NewStoreChain, StoreDL, NewLoad, + FirstInChain->getBasePtr(), + FirstInChain->getPointerInfo(), FirstStoreAlign); + } else { // This must be the truncstore/extload case + EVT ExtendedTy = + TLI.getTypeToTransformTo(*DAG.getContext(), JointMemOpVT); + NewLoad = + DAG.getExtLoad(ISD::EXTLOAD, LoadDL, ExtendedTy, FirstLoad->getChain(), + FirstLoad->getBasePtr(), FirstLoad->getPointerInfo(), + JointMemOpVT, FirstLoadAlign); + NewStore = DAG.getTruncStore(NewStoreChain, StoreDL, NewLoad, + FirstInChain->getBasePtr(), + FirstInChain->getPointerInfo(), JointMemOpVT, + FirstInChain->getAlignment(), + FirstInChain->getMemOperand()->getFlags()); + } // Transfer chain users from old loads to the new load. for (unsigned i = 0; i < NumElem; ++i) { @@ -13285,7 +13209,8 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { // Only perform this optimization before the types are legal, because we // don't want to perform this optimization on every DAGCombine invocation. - if (!LegalTypes) { + if ((TLI.mergeStoresAfterLegalization()) ? Level == AfterLegalizeDAG + : !LegalTypes) { for (;;) { // There can be multiple store sequences on the same chain. // Keep trying to merge store sequences until we are unable to do so @@ -14035,6 +13960,11 @@ SDValue DAGCombiner::createBuildVecShuffle(const SDLoc &DL, SDNode *N, // when we start sorting the vectors by type. return SDValue(); } + } else if (InVT2.getSizeInBits() * 2 == VT.getSizeInBits() && + InVT1.getSizeInBits() == VT.getSizeInBits()) { + SmallVector ConcatOps(2, DAG.getUNDEF(InVT2)); + ConcatOps[0] = VecIn2; + VecIn2 = DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, ConcatOps); } else { // TODO: Support cases where the length mismatch isn't exactly by a // factor of 2. @@ -16610,11 +16540,11 @@ bool DAGCombiner::isAlias(LSBaseSDNode *Op0, LSBaseSDNode *Op1) const { unsigned NumBytes1 = Op1->getMemoryVT().getSizeInBits() >> 3; // Check for BaseIndexOffset matching. - BaseIndexOffset BasePtr0 = BaseIndexOffset::match(Op0->getBasePtr(), DAG); - BaseIndexOffset BasePtr1 = BaseIndexOffset::match(Op1->getBasePtr(), DAG); - if (BasePtr0.equalBaseIndex(BasePtr1)) - return !((BasePtr0.Offset + NumBytes0 <= BasePtr1.Offset) || - (BasePtr1.Offset + NumBytes1 <= BasePtr0.Offset)); + BaseIndexOffset BasePtr0 = BaseIndexOffset::match(Op0->getBasePtr()); + BaseIndexOffset BasePtr1 = BaseIndexOffset::match(Op1->getBasePtr()); + int64_t PtrDiff; + if (BasePtr0.equalBaseIndex(BasePtr1, DAG, PtrDiff)) + return !((NumBytes0 <= PtrDiff) || (PtrDiff + NumBytes1 <= 0)); // FIXME: findBaseOffset and ConstantValue/GlobalValue/FrameIndex analysis // modified to use BaseIndexOffset. @@ -16821,14 +16751,14 @@ SDValue DAGCombiner::FindBetterChain(SDNode *N, SDValue OldChain) { bool DAGCombiner::findBetterNeighborChains(StoreSDNode *St) { // This holds the base pointer, index, and the offset in bytes from the base // pointer. - BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr(), DAG); + BaseIndexOffset BasePtr = BaseIndexOffset::match(St->getBasePtr()); // We must have a base and an offset. - if (!BasePtr.Base.getNode()) + if (!BasePtr.getBase().getNode()) return false; // Do not handle stores to undef base pointers. - if (BasePtr.Base.isUndef()) + if (BasePtr.getBase().isUndef()) return false; SmallVector ChainedStores; @@ -16847,10 +16777,10 @@ bool DAGCombiner::findBetterNeighborChains(StoreSDNode *St) { break; // Find the base pointer and offset for this memory node. - BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr(), DAG); + BaseIndexOffset Ptr = BaseIndexOffset::match(Index->getBasePtr()); // Check that the base pointer is the same as the original one. - if (!Ptr.equalBaseIndex(BasePtr)) + if (!BasePtr.equalBaseIndex(Ptr, DAG)) break; // Walk up the chain to find the next store node, ignoring any diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 15e87b7af18d..873b2bd48f1e 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -3530,17 +3530,24 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) { LC = RTLIB::MUL_I128; assert(LC != RTLIB::UNKNOWN_LIBCALL && "Cannot expand this operation!"); - // The high part is obtained by SRA'ing all but one of the bits of low - // part. - unsigned LoSize = VT.getSizeInBits(); - SDValue HiLHS = - DAG.getNode(ISD::SRA, dl, VT, LHS, - DAG.getConstant(LoSize - 1, dl, - TLI.getPointerTy(DAG.getDataLayout()))); - SDValue HiRHS = - DAG.getNode(ISD::SRA, dl, VT, RHS, - DAG.getConstant(LoSize - 1, dl, - TLI.getPointerTy(DAG.getDataLayout()))); + SDValue HiLHS; + SDValue HiRHS; + if (isSigned) { + // The high part is obtained by SRA'ing all but one of the bits of low + // part. + unsigned LoSize = VT.getSizeInBits(); + HiLHS = + DAG.getNode(ISD::SRA, dl, VT, LHS, + DAG.getConstant(LoSize - 1, dl, + TLI.getPointerTy(DAG.getDataLayout()))); + HiRHS = + DAG.getNode(ISD::SRA, dl, VT, RHS, + DAG.getConstant(LoSize - 1, dl, + TLI.getPointerTy(DAG.getDataLayout()))); + } else { + HiLHS = DAG.getConstant(0, dl, VT); + HiRHS = DAG.getConstant(0, dl, VT); + } // Here we're passing the 2 arguments explicitly as 4 arguments that are // pre-lowered to the correct types. This all depends upon WideVT not diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index a3ba52a148ee..75fec7bd1d48 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -615,9 +615,8 @@ SDValue DAGTypeLegalizer::PromoteIntRes_SETCC(SDNode *N) { SDValue SetCC = DAG.getNode(N->getOpcode(), dl, SVT, LHS, RHS, N->getOperand(2)); - assert(NVT.bitsLE(SVT) && "Integer type overpromoted?"); // Convert to the expected type. - return DAG.getNode(ISD::TRUNCATE, dl, NVT, SetCC); + return DAG.getSExtOrTrunc(SetCC, dl, NVT); } SDValue DAGTypeLegalizer::PromoteIntRes_SHL(SDNode *N) { diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp index 593efc5121f9..70b1fa77a099 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp @@ -1861,28 +1861,68 @@ static int checkSpecialNodes(const SUnit *left, const SUnit *right) { /// Smaller number is the higher priority. static unsigned CalcNodeSethiUllmanNumber(const SUnit *SU, std::vector &SUNumbers) { - unsigned &SethiUllmanNumber = SUNumbers[SU->NodeNum]; - if (SethiUllmanNumber != 0) - return SethiUllmanNumber; + if (SUNumbers[SU->NodeNum] != 0) + return SUNumbers[SU->NodeNum]; - unsigned Extra = 0; - for (const SDep &Pred : SU->Preds) { - if (Pred.isCtrl()) continue; // ignore chain preds - SUnit *PredSU = Pred.getSUnit(); - unsigned PredSethiUllman = CalcNodeSethiUllmanNumber(PredSU, SUNumbers); - if (PredSethiUllman > SethiUllmanNumber) { - SethiUllmanNumber = PredSethiUllman; - Extra = 0; - } else if (PredSethiUllman == SethiUllmanNumber) - ++Extra; + // Use WorkList to avoid stack overflow on excessively large IRs. + struct WorkState { + WorkState(const SUnit *SU) : SU(SU) {} + const SUnit *SU; + unsigned PredsProcessed = 0; + }; + + SmallVector WorkList; + WorkList.push_back(SU); + while (!WorkList.empty()) { + auto &Temp = WorkList.back(); + auto *TempSU = Temp.SU; + bool AllPredsKnown = true; + // Try to find a non-evaluated pred and push it into the processing stack. + for (unsigned P = Temp.PredsProcessed; P < TempSU->Preds.size(); ++P) { + auto &Pred = TempSU->Preds[P]; + if (Pred.isCtrl()) continue; // ignore chain preds + SUnit *PredSU = Pred.getSUnit(); + if (SUNumbers[PredSU->NodeNum] == 0) { +#ifndef NDEBUG + // In debug mode, check that we don't have such element in the stack. + for (auto It : WorkList) + assert(It.SU != PredSU && "Trying to push an element twice?"); +#endif + // Next time start processing this one starting from the next pred. + Temp.PredsProcessed = P + 1; + WorkList.push_back(PredSU); + AllPredsKnown = false; + break; + } + } + + if (!AllPredsKnown) + continue; + + // Once all preds are known, we can calculate the answer for this one. + unsigned SethiUllmanNumber = 0; + unsigned Extra = 0; + for (const SDep &Pred : TempSU->Preds) { + if (Pred.isCtrl()) continue; // ignore chain preds + SUnit *PredSU = Pred.getSUnit(); + unsigned PredSethiUllman = SUNumbers[PredSU->NodeNum]; + assert(PredSethiUllman > 0 && "We should have evaluated this pred!"); + if (PredSethiUllman > SethiUllmanNumber) { + SethiUllmanNumber = PredSethiUllman; + Extra = 0; + } else if (PredSethiUllman == SethiUllmanNumber) + ++Extra; + } + + SethiUllmanNumber += Extra; + if (SethiUllmanNumber == 0) + SethiUllmanNumber = 1; + SUNumbers[TempSU->NodeNum] = SethiUllmanNumber; + WorkList.pop_back(); } - SethiUllmanNumber += Extra; - - if (SethiUllmanNumber == 0) - SethiUllmanNumber = 1; - - return SethiUllmanNumber; + assert(SUNumbers[SU->NodeNum] > 0 && "SethiUllman should never be zero!"); + return SUNumbers[SU->NodeNum]; } /// CalculateSethiUllmanNumbers - Calculate Sethi-Ullman numbers of all diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 7abdc76cb004..98553152117d 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -4897,6 +4897,8 @@ static SDValue getMemcpyLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, // TODO: In the AlwaysInline case, if the size is big then generate a loop // rather than maybe a humongous number of loads and stores. const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + const DataLayout &DL = DAG.getDataLayout(); + LLVMContext &C = *DAG.getContext(); std::vector MemOps; bool DstAlignCanChange = false; MachineFunction &MF = DAG.getMachineFunction(); @@ -4923,15 +4925,15 @@ static SDValue getMemcpyLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, return SDValue(); if (DstAlignCanChange) { - Type *Ty = MemOps[0].getTypeForEVT(*DAG.getContext()); - unsigned NewAlign = (unsigned)DAG.getDataLayout().getABITypeAlignment(Ty); + Type *Ty = MemOps[0].getTypeForEVT(C); + unsigned NewAlign = (unsigned)DL.getABITypeAlignment(Ty); // Don't promote to an alignment that would require dynamic stack // realignment. const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo(); if (!TRI->needsStackRealignment(MF)) while (NewAlign > Align && - DAG.getDataLayout().exceedsNaturalStackAlignment(NewAlign)) + DL.exceedsNaturalStackAlignment(NewAlign)) NewAlign /= 2; if (NewAlign > Align) { @@ -4991,12 +4993,19 @@ static SDValue getMemcpyLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, // thing to do is generate a LoadExt/StoreTrunc pair. These simplify // to Load/Store if NVT==VT. // FIXME does the case above also need this? - EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); + EVT NVT = TLI.getTypeToTransformTo(C, VT); assert(NVT.bitsGE(VT)); + + bool isDereferenceable = + SrcPtrInfo.getWithOffset(SrcOff).isDereferenceable(VTSize, C, DL); + MachineMemOperand::Flags SrcMMOFlags = MMOFlags; + if (isDereferenceable) + SrcMMOFlags |= MachineMemOperand::MODereferenceable; + Value = DAG.getExtLoad(ISD::EXTLOAD, dl, NVT, Chain, DAG.getMemBasePlusOffset(Src, SrcOff, dl), SrcPtrInfo.getWithOffset(SrcOff), VT, - MinAlign(SrcAlign, SrcOff), MMOFlags); + MinAlign(SrcAlign, SrcOff), SrcMMOFlags); OutChains.push_back(Value.getValue(1)); Store = DAG.getTruncStore( Chain, dl, Value, DAG.getMemBasePlusOffset(Dst, DstOff, dl), @@ -5024,6 +5033,8 @@ static SDValue getMemmoveLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, // Expand memmove to a series of load and store ops if the size operand falls // below a certain threshold. const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + const DataLayout &DL = DAG.getDataLayout(); + LLVMContext &C = *DAG.getContext(); std::vector MemOps; bool DstAlignCanChange = false; MachineFunction &MF = DAG.getMachineFunction(); @@ -5046,8 +5057,8 @@ static SDValue getMemmoveLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, return SDValue(); if (DstAlignCanChange) { - Type *Ty = MemOps[0].getTypeForEVT(*DAG.getContext()); - unsigned NewAlign = (unsigned)DAG.getDataLayout().getABITypeAlignment(Ty); + Type *Ty = MemOps[0].getTypeForEVT(C); + unsigned NewAlign = (unsigned)DL.getABITypeAlignment(Ty); if (NewAlign > Align) { // Give the stack frame object a larger alignment if needed. if (MFI.getObjectAlignment(FI->getIndex()) < NewAlign) @@ -5068,9 +5079,15 @@ static SDValue getMemmoveLoadsAndStores(SelectionDAG &DAG, const SDLoc &dl, unsigned VTSize = VT.getSizeInBits() / 8; SDValue Value; + bool isDereferenceable = + SrcPtrInfo.getWithOffset(SrcOff).isDereferenceable(VTSize, C, DL); + MachineMemOperand::Flags SrcMMOFlags = MMOFlags; + if (isDereferenceable) + SrcMMOFlags |= MachineMemOperand::MODereferenceable; + Value = DAG.getLoad(VT, dl, Chain, DAG.getMemBasePlusOffset(Src, SrcOff, dl), - SrcPtrInfo.getWithOffset(SrcOff), SrcAlign, MMOFlags); + SrcPtrInfo.getWithOffset(SrcOff), SrcAlign, SrcMMOFlags); LoadValues.push_back(Value); LoadChains.push_back(Value.getValue(1)); SrcOff += VTSize; diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGAddressAnalysis.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGAddressAnalysis.cpp new file mode 100644 index 000000000000..d2e0dbbf88ec --- /dev/null +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGAddressAnalysis.cpp @@ -0,0 +1,95 @@ +//===-- llvm/CodeGen/SelectionDAGAddressAnalysis.cpp ------- DAG Address +//Analysis ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// + +#include "llvm/CodeGen/SelectionDAGAddressAnalysis.h" +#include "llvm/CodeGen/ISDOpcodes.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" + +namespace llvm { + +bool BaseIndexOffset::equalBaseIndex(BaseIndexOffset &Other, + const SelectionDAG &DAG, int64_t &Off) { + // Obvious equivalent + Off = Other.Offset - Offset; + if (Other.Base == Base && Other.Index == Index && + Other.IsIndexSignExt == IsIndexSignExt) + return true; + + // Match GlobalAddresses + if (Index == Other.Index) + if (GlobalAddressSDNode *A = dyn_cast(Base)) + if (GlobalAddressSDNode *B = dyn_cast(Other.Base)) + if (A->getGlobal() == B->getGlobal()) { + Off += B->getOffset() - A->getOffset(); + return true; + } + + // TODO: we should be able to add FrameIndex analysis improvements here. + + return false; +} + +/// Parses tree in Ptr for base, index, offset addresses. +BaseIndexOffset BaseIndexOffset::match(SDValue Ptr) { + // (((B + I*M) + c)) + c ... + SDValue Base = Ptr; + SDValue Index = SDValue(); + int64_t Offset = 0; + bool IsIndexSignExt = false; + + // Consume constant adds + while (Base->getOpcode() == ISD::ADD && + isa(Base->getOperand(1))) { + int64_t POffset = cast(Base->getOperand(1))->getSExtValue(); + Offset += POffset; + Base = Base->getOperand(0); + } + + if (Base->getOpcode() == ISD::ADD) { + // TODO: The following code appears to be needless as it just + // bails on some Ptrs early, reducing the cases where we + // find equivalence. We should be able to remove this. + // Inside a loop the current BASE pointer is calculated using an ADD and a + // MUL instruction. In this case Base is the actual BASE pointer. + // (i64 add (i64 %array_ptr) + // (i64 mul (i64 %induction_var) + // (i64 %element_size))) + if (Base->getOperand(1)->getOpcode() == ISD::MUL) + return BaseIndexOffset(Base, Index, Offset, IsIndexSignExt); + + // Look at Base + Index + Offset cases. + Index = Base->getOperand(1); + SDValue PotentialBase = Base->getOperand(0); + + // Skip signextends. + if (Index->getOpcode() == ISD::SIGN_EXTEND) { + Index = Index->getOperand(0); + IsIndexSignExt = true; + } + + // Check if Index Offset pattern + if (Index->getOpcode() != ISD::ADD || + !isa(Index->getOperand(1))) + return BaseIndexOffset(PotentialBase, Index, Offset, IsIndexSignExt); + + Offset += cast(Index->getOperand(1))->getSExtValue(); + Index = Index->getOperand(0); + if (Index->getOpcode() == ISD::SIGN_EXTEND) { + Index = Index->getOperand(0); + IsIndexSignExt = true; + } else + IsIndexSignExt = false; + Base = PotentialBase; + } + return BaseIndexOffset(Base, Index, Offset, IsIndexSignExt); +} +} // end namespace llvm diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index dcccd17bb98e..f711ca71f79f 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -337,12 +337,13 @@ void SelectionDAGISel::getAnalysisUsage(AnalysisUsage &AU) const { /// SplitCriticalSideEffectEdges - Look for critical edges with a PHI value that /// may trap on it. In this case we have to split the edge so that the path /// through the predecessor block that doesn't go to the phi block doesn't -/// execute the possibly trapping instruction. If available, we pass a -/// dominator tree to be updated when we split critical edges. This is because -/// SelectionDAGISel preserves the DominatorTree. +/// execute the possibly trapping instruction. If available, we pass domtree +/// and loop info to be updated when we split critical edges. This is because +/// SelectionDAGISel preserves these analyses. /// This is required for correctness, so it must be done at -O0. /// -static void SplitCriticalSideEffectEdges(Function &Fn, DominatorTree *DT) { +static void SplitCriticalSideEffectEdges(Function &Fn, DominatorTree *DT, + LoopInfo *LI) { // Loop for blocks with phi nodes. for (BasicBlock &BB : Fn) { PHINode *PN = dyn_cast(BB.begin()); @@ -368,7 +369,7 @@ static void SplitCriticalSideEffectEdges(Function &Fn, DominatorTree *DT) { // Okay, we have to split this edge. SplitCriticalEdge( Pred->getTerminator(), GetSuccessorNumber(Pred, &BB), - CriticalEdgeSplittingOptions(DT).setMergeIdenticalEdges()); + CriticalEdgeSplittingOptions(DT, LI).setMergeIdenticalEdges()); goto ReprocessBlock; } } @@ -406,10 +407,12 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { ORE = make_unique(&Fn); auto *DTWP = getAnalysisIfAvailable(); DominatorTree *DT = DTWP ? &DTWP->getDomTree() : nullptr; + auto *LIWP = getAnalysisIfAvailable(); + LoopInfo *LI = LIWP ? &LIWP->getLoopInfo() : nullptr; DEBUG(dbgs() << "\n\n\n=== " << Fn.getName() << "\n"); - SplitCriticalSideEffectEdges(const_cast(Fn), DT); + SplitCriticalSideEffectEdges(const_cast(Fn), DT, LI); CurDAG->init(*MF, *ORE); FuncInfo->set(Fn, *MF, CurDAG); diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index cfda0fffd031..8652df7bbd70 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -365,10 +365,10 @@ bool TargetLowering::ShrinkDemandedConstant(SDValue Op, const APInt &Demanded, // If this is a 'not' op, don't touch it because that's a canonical form. const APInt &C = Op1C->getAPIntValue(); - if (Opcode == ISD::XOR && (C | ~Demanded).isAllOnesValue()) + if (Opcode == ISD::XOR && Demanded.isSubsetOf(C)) return false; - if (C.intersects(~Demanded)) { + if (!C.isSubsetOf(Demanded)) { EVT VT = Op.getValueType(); SDValue NewC = DAG.getConstant(Demanded & C, DL, VT); SDValue NewOp = DAG.getNode(Opcode, DL, VT, Op.getOperand(0), NewC); @@ -919,7 +919,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, // always convert this into a logical shr, even if the shift amount is // variable. The low bit of the shift cannot be an input sign bit unless // the shift amount is >= the size of the datatype, which is undefined. - if (NewMask == 1) + if (NewMask.isOneValue()) return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::SRL, dl, Op.getValueType(), Op.getOperand(0), Op.getOperand(1))); @@ -1349,7 +1349,7 @@ bool TargetLowering::isConstTrueVal(const SDNode *N) const { case UndefinedBooleanContent: return CVal[0]; case ZeroOrOneBooleanContent: - return CVal == 1; + return CVal.isOneValue(); case ZeroOrNegativeOneBooleanContent: return CVal.isAllOnesValue(); } @@ -1506,7 +1506,7 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, // If the LHS is '(srl (ctlz x), 5)', the RHS is 0/1, and this is an // equality comparison, then we're just comparing whether X itself is // zero. - if (N0.getOpcode() == ISD::SRL && (C1 == 0 || C1 == 1) && + if (N0.getOpcode() == ISD::SRL && (C1.isNullValue() || C1.isOneValue()) && N0.getOperand(0).getOpcode() == ISD::CTLZ && N0.getOperand(1).getOpcode() == ISD::Constant) { const APInt &ShAmt @@ -1666,7 +1666,7 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, for (unsigned width = origWidth / 2; width>=8; width /= 2) { APInt newMask = APInt::getLowBitsSet(maskWidth, width); for (unsigned offset=0; offsetisNullValue() || N1C->getAPIntValue() == 1) && + } else if ((N1C->isNullValue() || N1C->isOne()) && (Cond == ISD::SETEQ || Cond == ISD::SETNE)) { // SETCC (SETCC), [0|1], [EQ|NE] -> SETCC if (N0.getOpcode() == ISD::SETCC && isTypeLegal(VT) && VT.bitsLE(N0.getValueType())) { - bool TrueWhenTrue = (Cond == ISD::SETEQ) ^ (N1C->getAPIntValue() != 1); + bool TrueWhenTrue = (Cond == ISD::SETEQ) ^ (!N1C->isOne()); if (TrueWhenTrue) return DAG.getNode(ISD::TRUNCATE, dl, VT, N0); // Invert the condition. @@ -1807,7 +1807,7 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, N0.getOperand(0).getOpcode() == ISD::XOR && N0.getOperand(1) == N0.getOperand(0).getOperand(1))) && isa(N0.getOperand(1)) && - cast(N0.getOperand(1))->getAPIntValue() == 1) { + cast(N0.getOperand(1))->isOne()) { // If this is (X^1) == 0/1, swap the RHS and eliminate the xor. We // can only do this if the top bits are known zero. unsigned BitWidth = N0.getValueSizeInBits(); @@ -1830,7 +1830,7 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, return DAG.getSetCC(dl, VT, Val, N1, Cond == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ); } - } else if (N1C->getAPIntValue() == 1 && + } else if (N1C->isOne() && (VT == MVT::i1 || getBooleanContents(N0->getValueType(0)) == ZeroOrOneBooleanContent)) { @@ -1848,7 +1848,7 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, } if (Op0.getOpcode() == ISD::AND && isa(Op0.getOperand(1)) && - cast(Op0.getOperand(1))->getAPIntValue() == 1) { + cast(Op0.getOperand(1))->isOne()) { // If this is (X&1) == / != 1, normalize it to (X&1) != / == 0. if (Op0.getValueType().bitsGT(VT)) Op0 = DAG.getNode(ISD::AND, dl, VT, @@ -2482,7 +2482,7 @@ void TargetLowering::LowerAsmOperandForConstraint(SDValue Op, // gcc prints these as sign extended. Sign extend value to 64 bits // now; without this it would get ZExt'd later in // ScheduleDAGSDNodes::EmitNode, which is very generic. - Ops.push_back(DAG.getTargetConstant(C->getAPIntValue().getSExtValue(), + Ops.push_back(DAG.getTargetConstant(C->getSExtValue(), SDLoc(C), MVT::i64)); } return; diff --git a/contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp b/contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp index c8537ad2f313..eeb00a784b0d 100644 --- a/contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp +++ b/contrib/llvm/lib/CodeGen/TargetRegisterInfo.cpp @@ -1,4 +1,4 @@ -//===- TargetRegisterInfo.cpp - Target Register Information Implementation ===// +//==- TargetRegisterInfo.cpp - Target Register Information Implementation --==// // // The LLVM Compiler Infrastructure // @@ -11,17 +11,27 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/MachineValueType.h" #include "llvm/CodeGen/VirtRegMap.h" +#include "llvm/IR/Attributes.h" #include "llvm/IR/Function.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Printable.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" +#include +#include #define DEBUG_TYPE "target-reg-info" @@ -38,7 +48,7 @@ TargetRegisterInfo::TargetRegisterInfo(const TargetRegisterInfoDesc *ID, CoveringLanes(SRICoveringLanes) { } -TargetRegisterInfo::~TargetRegisterInfo() {} +TargetRegisterInfo::~TargetRegisterInfo() = default; void TargetRegisterInfo::markSuperRegs(BitVector &RegisterSet, unsigned Reg) const { @@ -126,7 +136,7 @@ Printable PrintVRegOrUnit(unsigned Unit, const TargetRegisterInfo *TRI) { }); } -} // End of llvm namespace +} // end namespace llvm /// getAllocatableClass - Return the maximal subclass of the given register /// class that is alloctable, or NULL. diff --git a/contrib/llvm/lib/CodeGen/TargetSubtargetInfo.cpp b/contrib/llvm/lib/CodeGen/TargetSubtargetInfo.cpp index 82e85bab1474..f6d5bc80ddff 100644 --- a/contrib/llvm/lib/CodeGen/TargetSubtargetInfo.cpp +++ b/contrib/llvm/lib/CodeGen/TargetSubtargetInfo.cpp @@ -1,4 +1,4 @@ -//===-- TargetSubtargetInfo.cpp - General Target Information ---------------==// +//===- TargetSubtargetInfo.cpp - General Target Information ----------------==// // // The LLVM Compiler Infrastructure // @@ -11,15 +11,17 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Target/TargetSubtargetInfo.h" +#include "llvm/ADT/Optional.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/TargetSchedule.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Target/TargetSubtargetInfo.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" +#include + using namespace llvm; -//--------------------------------------------------------------------------- -// TargetSubtargetInfo Class -// TargetSubtargetInfo::TargetSubtargetInfo( const Triple &TT, StringRef CPU, StringRef FS, ArrayRef PF, ArrayRef PD, @@ -29,7 +31,7 @@ TargetSubtargetInfo::TargetSubtargetInfo( : MCSubtargetInfo(TT, CPU, FS, PF, PD, ProcSched, WPR, WL, RA, IS, OC, FP) { } -TargetSubtargetInfo::~TargetSubtargetInfo() {} +TargetSubtargetInfo::~TargetSubtargetInfo() = default; bool TargetSubtargetInfo::enableAtomicExpand() const { return true; diff --git a/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index f0debd9e9702..22f166a2335d 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -12,8 +12,6 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/TypeCollection.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeServerHandler.h" diff --git a/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp b/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp index 334c5e002bbc..d69eca018e0c 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp @@ -53,12 +53,16 @@ DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder( std::shared_ptr Subsection, CodeViewContainer Container) : Subsection(std::move(Subsection)), Container(Container) {} +DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder( + const DebugSubsectionRecord &Contents, CodeViewContainer Container) + : Contents(Contents), Container(Container) {} + uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() { - // The length of the entire subsection is always padded to 4 bytes, regardless - // of the container kind. - uint32_t Size = sizeof(DebugSubsectionHeader) + - alignTo(Subsection->calculateSerializedSize(), 4); - return Size; + uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize() + : Contents.getRecordData().getLength(); + // The length of the entire subsection is always padded to 4 bytes, + // regardless of the container kind. + return sizeof(DebugSubsectionHeader) + alignTo(DataSize, 4); } Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) const { @@ -66,16 +70,22 @@ Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer) const { "Debug Subsection not properly aligned"); DebugSubsectionHeader Header; - Header.Kind = uint32_t(Subsection->kind()); + Header.Kind = uint32_t(Subsection ? Subsection->kind() : Contents.kind()); // The value written into the Header's Length field is only padded to the // container's alignment - Header.Length = - alignTo(Subsection->calculateSerializedSize(), alignOf(Container)); + uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize() + : Contents.getRecordData().getLength(); + Header.Length = alignTo(DataSize, alignOf(Container)); if (auto EC = Writer.writeObject(Header)) return EC; - if (auto EC = Subsection->commit(Writer)) - return EC; + if (Subsection) { + if (auto EC = Subsection->commit(Writer)) + return EC; + } else { + if (auto EC = Writer.writeStreamRef(Contents.getRecordData())) + return EC; + } if (auto EC = Writer.padToAlignment(4)) return EC; diff --git a/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp b/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp index 01d8ccf2d31e..ec00af28395e 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/EnumTables.cpp @@ -82,6 +82,13 @@ static const EnumEntry RegisterNames[] = { CV_ENUM_CLASS_ENT(RegisterId, R15), }; +static const EnumEntry PublicSymFlagNames[] = { + CV_ENUM_CLASS_ENT(PublicSymFlags, Code), + CV_ENUM_CLASS_ENT(PublicSymFlags, Function), + CV_ENUM_CLASS_ENT(PublicSymFlags, Managed), + CV_ENUM_CLASS_ENT(PublicSymFlags, MSIL), +}; + static const EnumEntry ProcSymFlagNames[] = { CV_ENUM_CLASS_ENT(ProcSymFlags, HasFP), CV_ENUM_CLASS_ENT(ProcSymFlags, HasIRET), @@ -338,6 +345,9 @@ ArrayRef> getRegisterNames() { return makeArrayRef(RegisterNames); } +ArrayRef> getPublicSymFlagNames() { + return makeArrayRef(PublicSymFlagNames); +} ArrayRef> getProcSymFlagNames() { return makeArrayRef(ProcSymFlagNames); } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp index 39eb4099ce9e..20f7e72c3af3 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp @@ -11,7 +11,7 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeName.h" #include "llvm/DebugInfo/CodeView/TypeServerHandler.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" @@ -31,15 +31,13 @@ LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint) LazyRandomTypeCollection::LazyRandomTypeCollection( const CVTypeArray &Types, uint32_t RecordCountHint, PartialOffsetArray PartialOffsets) - : Database(RecordCountHint), Types(Types), DatabaseVisitor(Database), - PartialOffsets(PartialOffsets) { - KnownOffsets.resize(Database.capacity()); + : NameStorage(Allocator), Types(Types), PartialOffsets(PartialOffsets) { + Records.resize(RecordCountHint); } LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef Data, uint32_t RecordCountHint) : LazyRandomTypeCollection(RecordCountHint) { - reset(Data); } LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data, @@ -52,50 +50,88 @@ LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t NumRecords) : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {} -void LazyRandomTypeCollection::reset(StringRef Data) { - reset(makeArrayRef(Data.bytes_begin(), Data.bytes_end())); -} - -void LazyRandomTypeCollection::reset(ArrayRef Data) { +void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) { + Count = 0; PartialOffsets = PartialOffsetArray(); BinaryStreamReader Reader(Data, support::little); error(Reader.readArray(Types, Reader.getLength())); - KnownOffsets.resize(Database.capacity()); + // Clear and then resize, to make sure existing data gets destroyed. + Records.clear(); + Records.resize(RecordCountHint); +} + +void LazyRandomTypeCollection::reset(ArrayRef Data, + uint32_t RecordCountHint) { + reset(toStringRef(Data), RecordCountHint); +} + +uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) { + error(ensureTypeExists(Index)); + assert(contains(Index)); + + return Records[Index.toArrayIndex()].Offset; } CVType LazyRandomTypeCollection::getType(TypeIndex Index) { error(ensureTypeExists(Index)); - return Database.getTypeRecord(Index); + assert(contains(Index)); + + return Records[Index.toArrayIndex()].Type; } StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) { - if (!Index.isSimple()) { - // Try to make sure the type exists. Even if it doesn't though, it may be - // because we're dumping a symbol stream with no corresponding type stream - // present, in which case we still want to be able to print - // for the type names. - consumeError(ensureTypeExists(Index)); + if (Index.isNoneType() || Index.isSimple()) + return TypeIndex::simpleTypeName(Index); + + // Try to make sure the type exists. Even if it doesn't though, it may be + // because we're dumping a symbol stream with no corresponding type stream + // present, in which case we still want to be able to print + // for the type names. + if (auto EC = ensureTypeExists(Index)) { + consumeError(std::move(EC)); + return ""; } - return Database.getTypeName(Index); + uint32_t I = Index.toArrayIndex(); + ensureCapacityFor(Index); + if (Records[I].Name.data() == nullptr) { + StringRef Result = NameStorage.save(computeTypeName(*this, Index)); + Records[I].Name = Result; + } + return Records[I].Name; } bool LazyRandomTypeCollection::contains(TypeIndex Index) { - return Database.contains(Index); + if (Records.size() <= Index.toArrayIndex()) + return false; + if (!Records[Index.toArrayIndex()].Type.valid()) + return false; + return true; } -uint32_t LazyRandomTypeCollection::size() { return Database.size(); } +uint32_t LazyRandomTypeCollection::size() { return Count; } -uint32_t LazyRandomTypeCollection::capacity() { return Database.capacity(); } +uint32_t LazyRandomTypeCollection::capacity() { return Records.size(); } Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) { - if (!Database.contains(TI)) { - if (auto EC = visitRangeForType(TI)) - return EC; - } - return Error::success(); + if (contains(TI)) + return Error::success(); + + return visitRangeForType(TI); +} + +void LazyRandomTypeCollection::ensureCapacityFor(TypeIndex Index) { + uint32_t MinSize = Index.toArrayIndex() + 1; + + if (MinSize <= capacity()) + return; + + uint32_t NewCapacity = MinSize * 3 / 2; + + assert(NewCapacity > capacity()); + Records.resize(NewCapacity); } Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) { @@ -111,7 +147,7 @@ Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) { auto Prev = std::prev(Next); TypeIndex TIB = Prev->Type; - if (Database.contains(TIB)) { + if (contains(TIB)) { // They've asked us to fetch a type index, but the entry we found in the // partial offsets array has already been visited. Since we visit an entire // block every time, that means this record should have been previously @@ -122,13 +158,12 @@ Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) { TypeIndex TIE; if (Next == PartialOffsets.end()) { - TIE = TypeIndex::fromArrayIndex(Database.capacity()); + TIE = TypeIndex::fromArrayIndex(capacity()); } else { TIE = Next->Type; } - if (auto EC = visitRange(TIB, Prev->Offset, TIE)) - return EC; + visitRange(TIB, Prev->Offset, TIE); return Error::success(); } @@ -157,34 +192,31 @@ Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) { assert(PartialOffsets.empty()); TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0); - uint32_t Offset = 0; auto Begin = Types.begin(); - if (!Database.empty()) { + if (Count > 0) { // In the case of type streams which we don't know the number of records of, // it's possible to search for a type index triggering a full scan, but then // later additional records are added since we didn't know how many there // would be until we did a full visitation, then you try to access the new // type triggering another full scan. To avoid this, we assume that if the - // database has some records, this must be what's going on. So we ask the - // database for the largest type index less than the one we're searching for - // and only do the forward scan from there. - auto Prev = Database.largestTypeIndexLessThan(TI); - assert(Prev.hasValue() && "Empty database with valid types?"); - Offset = KnownOffsets[Prev->toArrayIndex()]; - CurrentTI = *Prev; - ++CurrentTI; + // database has some records, this must be what's going on. We can also + // assume that this index must be larger than the largest type index we've + // visited, so we start from there and scan forward. + uint32_t Offset = Records[LargestTypeIndex.toArrayIndex()].Offset; + CurrentTI = LargestTypeIndex + 1; Begin = Types.at(Offset); ++Begin; - Offset = Begin.offset(); } auto End = Types.end(); while (Begin != End) { - if (auto EC = visitOneRecord(CurrentTI, Offset, *Begin)) - return EC; - - Offset += Begin.getRecordLength(); + ensureCapacityFor(CurrentTI); + LargestTypeIndex = std::max(LargestTypeIndex, CurrentTI); + auto Idx = CurrentTI.toArrayIndex(); + Records[Idx].Type = *Begin; + Records[Idx].Offset = Begin.offset(); + ++Count; ++Begin; ++CurrentTI; } @@ -194,36 +226,19 @@ Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) { return Error::success(); } -Error LazyRandomTypeCollection::visitRange(TypeIndex Begin, - uint32_t BeginOffset, - TypeIndex End) { - +void LazyRandomTypeCollection::visitRange(TypeIndex Begin, uint32_t BeginOffset, + TypeIndex End) { auto RI = Types.at(BeginOffset); assert(RI != Types.end()); + ensureCapacityFor(End); while (Begin != End) { - if (auto EC = visitOneRecord(Begin, BeginOffset, *RI)) - return EC; - - BeginOffset += RI.getRecordLength(); + LargestTypeIndex = std::max(LargestTypeIndex, Begin); + auto Idx = Begin.toArrayIndex(); + Records[Idx].Type = *RI; + Records[Idx].Offset = RI.offset(); + ++Count; ++Begin; ++RI; } - - return Error::success(); -} - -Error LazyRandomTypeCollection::visitOneRecord(TypeIndex TI, uint32_t Offset, - CVType &Record) { - assert(!Database.contains(TI)); - if (auto EC = codeview::visitTypeRecord(Record, TI, DatabaseVisitor)) - return EC; - // Keep the KnownOffsets array the same size as the Database's capacity. Since - // we don't always know how many records are in the type stream, we need to be - // prepared for the database growing and receicing a type index that can't fit - // in our current buffer. - if (KnownOffsets.size() < Database.capacity()) - KnownOffsets.resize(Database.capacity()); - KnownOffsets[TI.toArrayIndex()] = Offset; - return Error::success(); } diff --git a/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp b/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp index 36abafc079ed..b9fa9b6a6ad7 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp @@ -524,7 +524,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) { DictScope S(W, "PublicSym"); - printTypeIndex("Type", Public.Index); + W.printFlags("Flags", uint32_t(Public.Flags), getPublicSymFlagNames()); W.printNumber("Seg", Public.Segment); W.printNumber("Off", Public.Offset); W.printString("Name", Public.Name); diff --git a/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp index d731dc1b0a37..923837a45d9f 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp @@ -361,7 +361,7 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) { - error(IO.mapInteger(Public.Index)); + error(IO.mapEnum(Public.Flags)); error(IO.mapInteger(Public.Offset)); error(IO.mapInteger(Public.Segment)); error(IO.mapStringZ(Public.Name)); diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp deleted file mode 100644 index 08f848b36a9d..000000000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp +++ /dev/null @@ -1,146 +0,0 @@ -//===- TypeDatabase.cpp --------------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" - -using namespace llvm; -using namespace llvm::codeview; - -TypeDatabase::TypeDatabase(uint32_t Capacity) : TypeNameStorage(Allocator) { - CVUDTNames.resize(Capacity); - TypeRecords.resize(Capacity); - ValidRecords.resize(Capacity); -} - -TypeIndex TypeDatabase::appendType(StringRef Name, const CVType &Data) { - LargestTypeIndex = getAppendIndex(); - if (LargestTypeIndex.toArrayIndex() >= capacity()) - grow(); - recordType(Name, LargestTypeIndex, Data); - return LargestTypeIndex; -} - -void TypeDatabase::recordType(StringRef Name, TypeIndex Index, - const CVType &Data) { - LargestTypeIndex = empty() ? Index : std::max(Index, LargestTypeIndex); - - if (LargestTypeIndex.toArrayIndex() >= capacity()) - grow(Index); - - uint32_t AI = Index.toArrayIndex(); - - assert(!contains(Index)); - assert(AI < capacity()); - - CVUDTNames[AI] = Name; - TypeRecords[AI] = Data; - ValidRecords.set(AI); - ++Count; -} - -/// Saves the name in a StringSet and creates a stable StringRef. -StringRef TypeDatabase::saveTypeName(StringRef TypeName) { - return TypeNameStorage.save(TypeName); -} - -StringRef TypeDatabase::getTypeName(TypeIndex Index) const { - if (Index.isNoneType() || Index.isSimple()) - return TypeIndex::simpleTypeName(Index); - - if (contains(Index)) - return CVUDTNames[Index.toArrayIndex()]; - - return ""; -} - -const CVType &TypeDatabase::getTypeRecord(TypeIndex Index) const { - assert(contains(Index)); - return TypeRecords[Index.toArrayIndex()]; -} - -CVType &TypeDatabase::getTypeRecord(TypeIndex Index) { - assert(contains(Index)); - return TypeRecords[Index.toArrayIndex()]; -} - -bool TypeDatabase::contains(TypeIndex Index) const { - uint32_t AI = Index.toArrayIndex(); - if (AI >= capacity()) - return false; - - return ValidRecords.test(AI); -} - -uint32_t TypeDatabase::size() const { return Count; } - -uint32_t TypeDatabase::capacity() const { return TypeRecords.size(); } - -CVType TypeDatabase::getType(TypeIndex Index) { return getTypeRecord(Index); } - -StringRef TypeDatabase::getTypeName(TypeIndex Index) { - return static_cast(this)->getTypeName(Index); -} - -bool TypeDatabase::contains(TypeIndex Index) { - return static_cast(this)->contains(Index); -} - -uint32_t TypeDatabase::size() { - return static_cast(this)->size(); -} - -uint32_t TypeDatabase::capacity() { - return static_cast(this)->capacity(); -} - -void TypeDatabase::grow() { grow(LargestTypeIndex + 1); } - -void TypeDatabase::grow(TypeIndex NewIndex) { - uint32_t NewSize = NewIndex.toArrayIndex() + 1; - - if (NewSize <= capacity()) - return; - - uint32_t NewCapacity = NewSize * 3 / 2; - - TypeRecords.resize(NewCapacity); - CVUDTNames.resize(NewCapacity); - ValidRecords.resize(NewCapacity); -} - -bool TypeDatabase::empty() const { return size() == 0; } - -Optional TypeDatabase::largestTypeIndexLessThan(TypeIndex TI) const { - uint32_t AI = TI.toArrayIndex(); - int N = ValidRecords.find_prev(AI); - if (N == -1) - return None; - return TypeIndex::fromArrayIndex(N); -} - -TypeIndex TypeDatabase::getAppendIndex() const { - if (empty()) - return TypeIndex::fromArrayIndex(0); - - return LargestTypeIndex + 1; -} - -Optional TypeDatabase::getFirst() { - int N = ValidRecords.find_first(); - if (N == -1) - return None; - return TypeIndex::fromArrayIndex(N); -} - -Optional TypeDatabase::getNext(TypeIndex Prev) { - int N = ValidRecords.find_next(Prev.toArrayIndex()); - if (N == -1) - return None; - return TypeIndex::fromArrayIndex(N); -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp deleted file mode 100644 index 8d97f8b1cb40..000000000000 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeDatabaseVisitor.cpp +++ /dev/null @@ -1,330 +0,0 @@ -//===- TypeDatabaseVisitor.cpp -------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" - -#include "llvm/ADT/SmallString.h" - -using namespace llvm; - -using namespace llvm::codeview; - -Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record) { - assert(!IsInFieldList); - // Reset Name to the empty string. If the visitor sets it, we know it. - Name = ""; - - if (Record.Type == LF_FIELDLIST) { - // Record that we're in a field list so that members do not get assigned - // type indices. - IsInFieldList = true; - } - return Error::success(); -} - -Error TypeDatabaseVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) { - if (auto EC = visitTypeBegin(Record)) - return EC; - - CurrentTypeIndex = Index; - return Error::success(); -} - -StringRef TypeDatabaseVisitor::getTypeName(TypeIndex Index) const { - return TypeDB->getTypeName(Index); -} - -StringRef TypeDatabaseVisitor::saveTypeName(StringRef Name) { - return TypeDB->saveTypeName(Name); -} - -Error TypeDatabaseVisitor::visitTypeEnd(CVType &CVR) { - if (CVR.Type == LF_FIELDLIST) { - assert(IsInFieldList); - IsInFieldList = false; - } - assert(!IsInFieldList); - - // Record every type that is not a field list member, even if Name is empty. - // CVUDTNames is indexed by type index, and must have one entry for every - // type. Field list members are not recorded, and are only referenced by - // their containing field list record. - if (CurrentTypeIndex) - TypeDB->recordType(Name, *CurrentTypeIndex, CVR); - else - TypeDB->appendType(Name, CVR); - - CurrentTypeIndex.reset(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitMemberBegin(CVMemberRecord &Record) { - assert(IsInFieldList); - // Reset Name to the empty string. If the visitor sets it, we know it. - Name = ""; - return Error::success(); -} - -Error TypeDatabaseVisitor::visitMemberEnd(CVMemberRecord &Record) { - assert(IsInFieldList); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, - FieldListRecord &FieldList) { - Name = ""; - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVRecord &CVR, - StringIdRecord &String) { - // Put this in the database so it gets printed with LF_UDT_SRC_LINE. - Name = String.getString(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { - auto Indices = Args.getIndices(); - uint32_t Size = Indices.size(); - SmallString<256> TypeName("("); - for (uint32_t I = 0; I < Size; ++I) { - StringRef ArgTypeName = getTypeName(Indices[I]); - TypeName.append(ArgTypeName); - if (I + 1 != Size) - TypeName.append(", "); - } - TypeName.push_back(')'); - Name = saveTypeName(TypeName); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, - StringListRecord &Strings) { - auto Indices = Strings.getIndices(); - uint32_t Size = Indices.size(); - SmallString<256> TypeName("\""); - for (uint32_t I = 0; I < Size; ++I) { - StringRef ArgTypeName = getTypeName(Indices[I]); - TypeName.append(ArgTypeName); - if (I + 1 != Size) - TypeName.append("\" \""); - } - TypeName.push_back('\"'); - Name = saveTypeName(TypeName); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) { - Name = Class.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) { - Name = Union.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { - Name = Enum.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { - Name = AT.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { - Name = VFT.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, - MemberFuncIdRecord &Id) { - Name = Id.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, - ProcedureRecord &Proc) { - StringRef ReturnTypeName = getTypeName(Proc.getReturnType()); - StringRef ArgListTypeName = getTypeName(Proc.getArgumentList()); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ArgListTypeName); - Name = saveTypeName(TypeName); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, - MemberFunctionRecord &MF) { - StringRef ReturnTypeName = getTypeName(MF.getReturnType()); - StringRef ClassTypeName = getTypeName(MF.getClassType()); - StringRef ArgListTypeName = getTypeName(MF.getArgumentList()); - SmallString<256> TypeName(ReturnTypeName); - TypeName.push_back(' '); - TypeName.append(ClassTypeName); - TypeName.append("::"); - TypeName.append(ArgListTypeName); - Name = saveTypeName(TypeName); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { - Name = Func.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, - TypeServer2Record &TS) { - Name = TS.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { - - if (Ptr.isPointerToMember()) { - const MemberPointerInfo &MI = Ptr.getMemberInfo(); - - StringRef PointeeName = getTypeName(Ptr.getReferentType()); - StringRef ClassName = getTypeName(MI.getContainingType()); - SmallString<256> TypeName(PointeeName); - TypeName.push_back(' '); - TypeName.append(ClassName); - TypeName.append("::*"); - Name = saveTypeName(TypeName); - } else { - SmallString<256> TypeName; - if (Ptr.isConst()) - TypeName.append("const "); - if (Ptr.isVolatile()) - TypeName.append("volatile "); - if (Ptr.isUnaligned()) - TypeName.append("__unaligned "); - - TypeName.append(getTypeName(Ptr.getReferentType())); - - if (Ptr.getMode() == PointerMode::LValueReference) - TypeName.append("&"); - else if (Ptr.getMode() == PointerMode::RValueReference) - TypeName.append("&&"); - else if (Ptr.getMode() == PointerMode::Pointer) - TypeName.append("*"); - - if (!TypeName.empty()) - Name = saveTypeName(TypeName); - } - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { - uint16_t Mods = static_cast(Mod.getModifiers()); - - StringRef ModifiedName = getTypeName(Mod.getModifiedType()); - SmallString<256> TypeName; - if (Mods & uint16_t(ModifierOptions::Const)) - TypeName.append("const "); - if (Mods & uint16_t(ModifierOptions::Volatile)) - TypeName.append("volatile "); - if (Mods & uint16_t(ModifierOptions::Unaligned)) - TypeName.append("__unaligned "); - TypeName.append(ModifiedName); - Name = saveTypeName(TypeName); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, - VFTableShapeRecord &Shape) { - Name = - saveTypeName(""); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - NestedTypeRecord &Nested) { - Name = Nested.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - OneMethodRecord &Method) { - Name = Method.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - OverloadedMethodRecord &Method) { - Name = Method.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - DataMemberRecord &Field) { - Name = Field.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - StaticDataMemberRecord &Field) { - Name = Field.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - EnumeratorRecord &Enum) { - Name = Enum.getName(); - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - BaseClassRecord &Base) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - VirtualBaseClassRecord &VBase) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - ListContinuationRecord &Cont) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord( - CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, - UdtSourceLineRecord &SourceLine) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord( - CVType &CVR, MethodOverloadListRecord &Overloads) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) { - return Error::success(); -} - -Error TypeDatabaseVisitor::visitKnownMember(CVMemberRecord &CVR, - VFPtrRecord &VFP) { - return Error::success(); -} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp index 04b0384d8190..589966705015 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -13,8 +13,6 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/Formatters.h" #include "llvm/DebugInfo/CodeView/TypeCollection.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/Support/BinaryByteStream.h" diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp index 8704cea60786..1226d5be3f3c 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp @@ -357,6 +357,82 @@ static void discoverTypeIndices(ArrayRef Content, TypeLeafKind Kind, } } +static bool discoverTypeIndices(ArrayRef Content, SymbolKind Kind, + SmallVectorImpl &Refs) { + uint32_t Count; + // FIXME: In the future it would be nice if we could avoid hardcoding these + // values. One idea is to define some structures representing these types + // that would allow the use of offsetof(). + switch (Kind) { + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_LPROC32_DPC: + case SymbolKind::S_LPROC32_DPC_ID: + Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID + break; + case SymbolKind::S_UDT: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT + break; + case SymbolKind::S_GDATA32: + case SymbolKind::S_LDATA32: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_BUILDINFO: + Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags + break; + case SymbolKind::S_LOCAL: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_CONSTANT: + Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type + break; + case SymbolKind::S_REGREL32: + Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type + break; + case SymbolKind::S_CALLSITEINFO: + Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature + break; + case SymbolKind::S_CALLERS: + case SymbolKind::S_CALLEES: + // The record is a count followed by an array of type indices. + Count = *reinterpret_cast(Content.data()); + Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees + break; + case SymbolKind::S_INLINESITE: + Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee + break; + + // Defranges don't have types, just registers and code offsets. + case SymbolKind::S_DEFRANGE_REGISTER: + case SymbolKind::S_DEFRANGE_REGISTER_REL: + case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL: + case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER: + case SymbolKind::S_DEFRANGE_SUBFIELD: + break; + + // No type refernces. + case SymbolKind::S_LABEL32: + case SymbolKind::S_OBJNAME: + case SymbolKind::S_COMPILE: + case SymbolKind::S_COMPILE2: + case SymbolKind::S_COMPILE3: + case SymbolKind::S_BLOCK32: + case SymbolKind::S_FRAMEPROC: + break; + // Scope ending symbols. + case SymbolKind::S_END: + case SymbolKind::S_INLINESITE_END: + case SymbolKind::S_PROC_ID_END: + break; + default: + return false; // Unknown symbol. + } + return true; +} + void llvm::codeview::discoverTypeIndices(const CVType &Type, SmallVectorImpl &Refs) { ::discoverTypeIndices(Type.content(), Type.kind(), Refs); @@ -369,3 +445,9 @@ void llvm::codeview::discoverTypeIndices(ArrayRef RecordData, TypeLeafKind K = static_cast(uint16_t(P->RecordKind)); ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs); } + +bool llvm::codeview::discoverTypeIndices(const CVSymbol &Sym, + SmallVectorImpl &Refs) { + SymbolKind K = Sym.kind(); + return ::discoverTypeIndices(Sym.content(), K, Refs); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeName.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeName.cpp new file mode 100644 index 000000000000..2eb8b81862f3 --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeName.cpp @@ -0,0 +1,243 @@ +//===- TypeName.cpp ------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/CodeView/TypeName.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; + +namespace { +class TypeNameComputer : public TypeVisitorCallbacks { + /// The type collection. Used to calculate names of nested types. + TypeCollection &Types; + TypeIndex CurrentTypeIndex = TypeIndex::None(); + + /// Name of the current type. Only valid before visitTypeEnd. + SmallString<256> Name; + +public: + explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {} + + StringRef name() const { return Name; } + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(CVType &Record) override; + Error visitTypeBegin(CVType &Record, TypeIndex Index) override; + Error visitTypeEnd(CVType &Record) override; + +#define TYPE_RECORD(EnumName, EnumVal, Name) \ + Error visitKnownRecord(CVType &CVR, Name##Record &Record) override; +#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) +#define MEMBER_RECORD(EnumName, EnumVal, Name) +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +}; +} // namespace + +Error TypeNameComputer::visitTypeBegin(CVType &Record) { + llvm_unreachable("Must call visitTypeBegin with a TypeIndex!"); + return Error::success(); +} + +Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) { + // Reset Name to the empty string. If the visitor sets it, we know it. + Name = ""; + CurrentTypeIndex = Index; + return Error::success(); +} + +Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); } + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + FieldListRecord &FieldList) { + Name = ""; + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVRecord &CVR, + StringIdRecord &String) { + Name = String.getString(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) { + auto Indices = Args.getIndices(); + uint32_t Size = Indices.size(); + Name = "("; + for (uint32_t I = 0; I < Size; ++I) { + assert(Indices[I] < CurrentTypeIndex); + + Name.append(Types.getTypeName(Indices[I])); + if (I + 1 != Size) + Name.append(", "); + } + Name.push_back(')'); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + StringListRecord &Strings) { + auto Indices = Strings.getIndices(); + uint32_t Size = Indices.size(); + Name = "\""; + for (uint32_t I = 0; I < Size; ++I) { + Name.append(Types.getTypeName(Indices[I])); + if (I + 1 != Size) + Name.append("\" \""); + } + Name.push_back('\"'); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) { + Name = Class.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) { + Name = Union.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) { + Name = Enum.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) { + Name = AT.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) { + Name = VFT.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) { + Name = Id.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) { + StringRef Ret = Types.getTypeName(Proc.getReturnType()); + StringRef Params = Types.getTypeName(Proc.getArgumentList()); + Name = formatv("{0} {1}", Ret, Params).sstr<256>(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &MF) { + StringRef Ret = Types.getTypeName(MF.getReturnType()); + StringRef Class = Types.getTypeName(MF.getClassType()); + StringRef Params = Types.getTypeName(MF.getArgumentList()); + Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) { + Name = Func.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) { + Name = TS.getName(); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) { + + if (Ptr.isPointerToMember()) { + const MemberPointerInfo &MI = Ptr.getMemberInfo(); + + StringRef Pointee = Types.getTypeName(Ptr.getReferentType()); + StringRef Class = Types.getTypeName(MI.getContainingType()); + Name = formatv("{0} {1}::*", Pointee, Class); + } else { + if (Ptr.isConst()) + Name.append("const "); + if (Ptr.isVolatile()) + Name.append("volatile "); + if (Ptr.isUnaligned()) + Name.append("__unaligned "); + + Name.append(Types.getTypeName(Ptr.getReferentType())); + + if (Ptr.getMode() == PointerMode::LValueReference) + Name.append("&"); + else if (Ptr.getMode() == PointerMode::RValueReference) + Name.append("&&"); + else if (Ptr.getMode() == PointerMode::Pointer) + Name.append("*"); + } + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) { + uint16_t Mods = static_cast(Mod.getModifiers()); + + SmallString<256> TypeName; + if (Mods & uint16_t(ModifierOptions::Const)) + Name.append("const "); + if (Mods & uint16_t(ModifierOptions::Volatile)) + Name.append("volatile "); + if (Mods & uint16_t(ModifierOptions::Unaligned)) + Name.append("__unaligned "); + Name.append(Types.getTypeName(Mod.getModifiedType())); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Shape) { + Name = formatv("", Shape.getEntryCount()); + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord( + CVType &CVR, UdtModSourceLineRecord &ModSourceLine) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &SourceLine) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &Overloads) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) { + return Error::success(); +} + +Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) { + return Error::success(); +} + +std::string llvm::codeview::computeTypeName(TypeCollection &Types, + TypeIndex Index) { + TypeNameComputer Computer(Types); + CVType Record = Types.getType(Index); + if (auto EC = visitTypeRecord(Record, Index, Computer)) { + consumeError(std::move(EC)); + return ""; + } + return Computer.name(); +} diff --git a/contrib/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp b/contrib/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp index 8d974d522f28..4eca5aeaa0ae 100644 --- a/contrib/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp +++ b/contrib/llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp @@ -10,7 +10,7 @@ #include "llvm/DebugInfo/CodeView/TypeTableCollection.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeName.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/BinaryStreamReader.h" @@ -18,14 +18,10 @@ using namespace llvm; using namespace llvm::codeview; -static void error(Error &&EC) { - assert(!static_cast(EC)); - if (EC) - consumeError(std::move(EC)); -} - TypeTableCollection::TypeTableCollection(ArrayRef> Records) - : Records(Records), Database(Records.size()) {} + : NameStorage(Allocator), Records(Records) { + Names.resize(Records.size()); +} Optional TypeTableCollection::getFirst() { if (empty()) @@ -34,50 +30,38 @@ Optional TypeTableCollection::getFirst() { } Optional TypeTableCollection::getNext(TypeIndex Prev) { + assert(contains(Prev)); ++Prev; - assert(Prev.toArrayIndex() <= size()); if (Prev.toArrayIndex() == size()) return None; return Prev; } -void TypeTableCollection::ensureTypeExists(TypeIndex Index) { - assert(hasCapacityFor(Index)); - - if (Database.contains(Index)) - return; - - BinaryByteStream Bytes(Records[Index.toArrayIndex()], support::little); - - CVType Type; - uint32_t Len; - VarStreamArrayExtractor Extract; - error(Extract(Bytes, Len, Type)); - - TypeDatabaseVisitor DBV(Database); - error(codeview::visitTypeRecord(Type, Index, DBV)); - assert(Database.contains(Index)); -} - CVType TypeTableCollection::getType(TypeIndex Index) { - ensureTypeExists(Index); - return Database.getTypeRecord(Index); + assert(Index.toArrayIndex() < Records.size()); + ArrayRef Bytes = Records[Index.toArrayIndex()]; + const RecordPrefix *Prefix = + reinterpret_cast(Bytes.data()); + TypeLeafKind Kind = static_cast(uint16_t(Prefix->RecordKind)); + return CVType(Kind, Bytes); } StringRef TypeTableCollection::getTypeName(TypeIndex Index) { - if (!Index.isSimple()) - ensureTypeExists(Index); - return Database.getTypeName(Index); + if (Index.isNoneType() || Index.isSimple()) + return TypeIndex::simpleTypeName(Index); + + uint32_t I = Index.toArrayIndex(); + if (Names[I].data() == nullptr) { + StringRef Result = NameStorage.save(computeTypeName(*this, Index)); + Names[I] = Result; + } + return Names[I]; } bool TypeTableCollection::contains(TypeIndex Index) { - return Database.contains(Index); + return Index.toArrayIndex() <= size(); } uint32_t TypeTableCollection::size() { return Records.size(); } uint32_t TypeTableCollection::capacity() { return Records.size(); } - -bool TypeTableCollection::hasCapacityFor(TypeIndex Index) const { - return Index.toArrayIndex() < Records.size(); -} diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp index 57eac91f8c19..bb475a669efb 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp @@ -65,46 +65,52 @@ DWARFAbbreviationDeclaration::extract(DataExtractor Data, if (A && F) { Optional V; bool IsImplicitConst = (F == DW_FORM_implicit_const); - if (IsImplicitConst) + if (IsImplicitConst) { V = Data.getSLEB128(OffsetPtr); - else if (auto Size = DWARFFormValue::getFixedByteSize(F)) - V = *Size; - AttributeSpecs.push_back(AttributeSpec(A, F, V)); - if (IsImplicitConst) + AttributeSpecs.push_back(AttributeSpec(A, F, V)); continue; + } // If this abbrevation still has a fixed byte size, then update the // FixedAttributeSize as needed. - if (FixedAttributeSize) { - if (V) - FixedAttributeSize->NumBytes += *V; - else { - switch (F) { - case DW_FORM_addr: - ++FixedAttributeSize->NumAddrs; - break; + switch (F) { + case DW_FORM_addr: + if (FixedAttributeSize) + ++FixedAttributeSize->NumAddrs; + break; - case DW_FORM_ref_addr: - ++FixedAttributeSize->NumRefAddrs; - break; + case DW_FORM_ref_addr: + if (FixedAttributeSize) + ++FixedAttributeSize->NumRefAddrs; + break; - case DW_FORM_strp: - case DW_FORM_GNU_ref_alt: - case DW_FORM_GNU_strp_alt: - case DW_FORM_line_strp: - case DW_FORM_sec_offset: - case DW_FORM_strp_sup: - ++FixedAttributeSize->NumDwarfOffsets; - break; + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + case DW_FORM_GNU_strp_alt: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: + case DW_FORM_strp_sup: + if (FixedAttributeSize) + ++FixedAttributeSize->NumDwarfOffsets; + break; - default: - // Indicate we no longer have a fixed byte size for this - // abbreviation by clearing the FixedAttributeSize optional value - // so it doesn't have a value. - FixedAttributeSize.reset(); - break; - } + default: + // The form has a byte size that doesn't depend on Params. + // If it's a fixed size, keep track of it. + if (auto Size = + DWARFFormValue::getFixedByteSize(F, DWARFFormParams())) { + V = *Size; + if (FixedAttributeSize) + FixedAttributeSize->NumBytes += *V; + break; } + // Indicate we no longer have a fixed byte size for this + // abbreviation by clearing the FixedAttributeSize optional value + // so it doesn't have a value. + FixedAttributeSize.reset(); + break; } + // Record this attribute and its fixed size if it has one. + AttributeSpecs.push_back(AttributeSpec(A, F, V)); } else if (A == 0 && F == 0) { // We successfully reached the end of this abbreviation declaration // since both attribute and form are zero. @@ -186,7 +192,8 @@ Optional DWARFAbbreviationDeclaration::getAttributeValue( if (auto FixedSize = Spec.getByteSize(U)) Offset += *FixedSize; else - DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, &U); + DWARFFormValue::skipValue(Spec.Form, DebugInfoData, &Offset, + U.getFormParams()); ++AttrIndex; } return None; @@ -211,7 +218,8 @@ Optional DWARFAbbreviationDeclaration::AttributeSpec::getByteSize( if (ByteSizeOrValue) return ByteSizeOrValue; Optional S; - auto FixedByteSize = DWARFFormValue::getFixedByteSize(Form, &U); + auto FixedByteSize = + DWARFFormValue::getFixedByteSize(Form, U.getFormParams()); if (FixedByteSize) S = *FixedByteSize; return S; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp index 9bafcde57f0a..381479461750 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h" @@ -36,7 +37,6 @@ #include "llvm/Object/RelocVisitor.h" #include "llvm/Support/Casting.h" #include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" #include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" @@ -44,8 +44,8 @@ #include #include #include -#include #include +#include #include #include @@ -55,9 +55,9 @@ using namespace object; #define DEBUG_TYPE "dwarf" -typedef DWARFDebugLine::LineTable DWARFLineTable; -typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; -typedef DILineInfoSpecifier::FunctionNameKind FunctionNameKind; +using DWARFLineTable = DWARFDebugLine::LineTable; +using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; +using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind; uint64_t llvm::getRelocatedValue(const DataExtractor &Data, uint32_t Size, uint32_t *Off, const RelocAddrMap *Relocs, @@ -201,8 +201,7 @@ static void dumpStringOffsetsSection(raw_ostream &OS, StringRef SectionName, } } -void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){ - +void DWARFContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) { DIDumpType DumpType = DumpOpts.DumpType; bool DumpEH = DumpOpts.DumpEH; bool SummarizeTypes = DumpOpts.SummarizeTypes; @@ -1068,7 +1067,7 @@ DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, errs() << "error: failed to compute relocation: " << Name << "\n"; continue; } - llvm::RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val}; + RelocAddrEntry Rel = {SymInfoOrErr->SectionIndex, Val}; Map->insert({Reloc.getOffset(), Rel}); } } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp index cf9fec2b3254..475cf25b781b 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" - #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Optional.h" @@ -71,7 +70,7 @@ class llvm::FrameEntry { /// An entry may contain CFI instructions. An instruction consists of an /// opcode and an optional sequence of operands. - typedef std::vector Operands; + using Operands = std::vector; struct Instruction { Instruction(uint8_t Opcode) : Opcode(Opcode) @@ -518,14 +517,13 @@ static uint64_t readPointer(const DataExtractor &Data, uint32_t &Offset, // noreturn attribute usage in lambdas. Once the support for those // compilers are phased out, we can remove this and return back to // a ReportError lambda: [StartOffset](const char *ErrorMsg). -#define ReportError(ErrorMsg) ReportErrorImpl(StartOffset,ErrorMsg) -static void LLVM_ATTRIBUTE_NORETURN -ReportErrorImpl(uint32_t StartOffset, const char *ErrorMsg) { - std::string Str; - raw_string_ostream OS(Str); - OS << format(ErrorMsg, StartOffset); - OS.flush(); - report_fatal_error(Str); +static void LLVM_ATTRIBUTE_NORETURN ReportError(uint32_t StartOffset, + const char *ErrorMsg) { + std::string Str; + raw_string_ostream OS(Str); + OS << format(ErrorMsg, StartOffset); + OS.flush(); + report_fatal_error(Str); } void DWARFDebugFrame::parse(DataExtractor Data) { @@ -590,13 +588,15 @@ void DWARFDebugFrame::parse(DataExtractor Data) { for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) { switch (AugmentationString[i]) { default: - ReportError("Unknown augmentation character in entry at %lx"); + ReportError(StartOffset, + "Unknown augmentation character in entry at %lx"); case 'L': LSDAPointerEncoding = Data.getU8(&Offset); break; case 'P': { if (Personality) - ReportError("Duplicate personality in entry at %lx"); + ReportError(StartOffset, + "Duplicate personality in entry at %lx"); PersonalityEncoding = Data.getU8(&Offset); Personality = readPointer(Data, Offset, *PersonalityEncoding); break; @@ -606,7 +606,8 @@ void DWARFDebugFrame::parse(DataExtractor Data) { break; case 'z': if (i) - ReportError("'z' must be the first character at %lx"); + ReportError(StartOffset, + "'z' must be the first character at %lx"); // Parse the augmentation length first. We only parse it if // the string contains a 'z'. AugmentationLength = Data.getULEB128(&Offset); @@ -618,7 +619,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) { if (AugmentationLength.hasValue()) { if (Offset != EndAugmentationOffset) - ReportError("Parsing augmentation data at %lx failed"); + ReportError(StartOffset, "Parsing augmentation data at %lx failed"); AugmentationData = Data.getData().slice(StartAugmentationOffset, EndAugmentationOffset); @@ -645,7 +646,8 @@ void DWARFDebugFrame::parse(DataExtractor Data) { if (IsEH) { // The address size is encoded in the CIE we reference. if (!Cie) - ReportError("Parsing FDE data at %lx failed due to missing CIE"); + ReportError(StartOffset, + "Parsing FDE data at %lx failed due to missing CIE"); InitialLocation = readPointer(Data, Offset, Cie->getFDEPointerEncoding()); @@ -665,7 +667,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) { readPointer(Data, Offset, Cie->getLSDAPointerEncoding()); if (Offset != EndAugmentationOffset) - ReportError("Parsing augmentation data at %lx failed"); + ReportError(StartOffset, "Parsing augmentation data at %lx failed"); } } else { InitialLocation = Data.getAddress(&Offset); @@ -680,7 +682,7 @@ void DWARFDebugFrame::parse(DataExtractor Data) { Entries.back()->parseInstructions(Data, &Offset, EndStructureOffset); if (Offset != EndStructureOffset) - ReportError("Parsing entry instructions at %lx failed"); + ReportError(StartOffset, "Parsing entry instructions at %lx failed"); } } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp index dbcc64fc0832..1551974b822a 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp @@ -59,7 +59,7 @@ bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint32_t *OffsetPtr, // Attribute byte size if fixed, just add the size to the offset. *OffsetPtr += *FixedSize; } else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData, - OffsetPtr, &U)) { + OffsetPtr, U.getFormParams())) { // We failed to skip this attribute's value, restore the original offset // and return the failure status. *OffsetPtr = Offset; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp index cda3e75fbc3e..ad5647f3e03d 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp @@ -9,6 +9,8 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" @@ -26,23 +28,27 @@ using namespace llvm; using namespace dwarf; -typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; +using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind; + namespace { + struct ContentDescriptor { dwarf::LineNumberEntryFormat Type; dwarf::Form Form; }; -typedef SmallVector ContentDescriptors; + +using ContentDescriptors = SmallVector; + } // end anonmyous namespace DWARFDebugLine::Prologue::Prologue() { clear(); } void DWARFDebugLine::Prologue::clear() { - TotalLength = Version = PrologueLength = 0; - AddressSize = SegSelectorSize = 0; + TotalLength = PrologueLength = 0; + SegSelectorSize = 0; MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0; OpcodeBase = 0; - IsDWARF64 = false; + FormParams = DWARFFormParams({0, 0, DWARF32}); StandardOpcodeLengths.clear(); IncludeDirectories.clear(); FileNames.clear(); @@ -51,12 +57,13 @@ void DWARFDebugLine::Prologue::clear() { void DWARFDebugLine::Prologue::dump(raw_ostream &OS) const { OS << "Line table prologue:\n" << format(" total_length: 0x%8.8" PRIx64 "\n", TotalLength) - << format(" version: %u\n", Version) - << format(Version >= 5 ? " address_size: %u\n" : "", AddressSize) - << format(Version >= 5 ? " seg_select_size: %u\n" : "", SegSelectorSize) - << format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength) + << format(" version: %u\n", getVersion()); + if (getVersion() >= 5) + OS << format(" address_size: %u\n", getAddressSize()) + << format(" seg_select_size: %u\n", SegSelectorSize); + OS << format(" prologue_length: 0x%8.8" PRIx64 "\n", PrologueLength) << format(" min_inst_length: %u\n", MinInstLength) - << format(Version >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst) + << format(getVersion() >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst) << format(" default_is_stmt: %u\n", DefaultIsStmt) << format(" line_base: %i\n", LineBase) << format(" line_range: %u\n", LineRange) @@ -137,6 +144,7 @@ parseV5EntryFormat(DataExtractor DebugLineData, uint32_t *OffsetPtr, static bool parseV5DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr, uint64_t EndPrologueOffset, + const DWARFFormParams &FormParams, std::vector &IncludeDirectories, std::vector &FileNames) { // Get the directory entry description. @@ -159,7 +167,7 @@ parseV5DirFileTables(DataExtractor DebugLineData, uint32_t *OffsetPtr, IncludeDirectories.push_back(Value.getAsCString().getValue()); break; default: - if (!Value.skipValue(DebugLineData, OffsetPtr, nullptr)) + if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams)) return false; } } @@ -211,24 +219,26 @@ bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData, clear(); TotalLength = DebugLineData.getU32(OffsetPtr); if (TotalLength == UINT32_MAX) { - IsDWARF64 = true; + FormParams.Format = dwarf::DWARF64; TotalLength = DebugLineData.getU64(OffsetPtr); - } else if (TotalLength > 0xffffff00) { + } else if (TotalLength >= 0xffffff00) { return false; } - Version = DebugLineData.getU16(OffsetPtr); - if (Version < 2) + FormParams.Version = DebugLineData.getU16(OffsetPtr); + if (getVersion() < 2) return false; - if (Version >= 5) { - AddressSize = DebugLineData.getU8(OffsetPtr); + if (getVersion() >= 5) { + FormParams.AddrSize = DebugLineData.getU8(OffsetPtr); + assert(getAddressSize() == DebugLineData.getAddressSize() && + "Line table header and data extractor disagree"); SegSelectorSize = DebugLineData.getU8(OffsetPtr); } PrologueLength = DebugLineData.getUnsigned(OffsetPtr, sizeofPrologueLength()); const uint64_t EndPrologueOffset = PrologueLength + *OffsetPtr; MinInstLength = DebugLineData.getU8(OffsetPtr); - if (Version >= 4) + if (getVersion() >= 4) MaxOpsPerInst = DebugLineData.getU8(OffsetPtr); DefaultIsStmt = DebugLineData.getU8(OffsetPtr); LineBase = DebugLineData.getU8(OffsetPtr); @@ -241,9 +251,9 @@ bool DWARFDebugLine::Prologue::parse(DataExtractor DebugLineData, StandardOpcodeLengths.push_back(OpLen); } - if (Version >= 5) { + if (getVersion() >= 5) { if (!parseV5DirFileTables(DebugLineData, OffsetPtr, EndPrologueOffset, - IncludeDirectories, FileNames)) { + getFormParams(), IncludeDirectories, FileNames)) { fprintf(stderr, "warning: parsing line table prologue at 0x%8.8" PRIx64 " found an invalid directory or file table description at" @@ -333,7 +343,7 @@ void DWARFDebugLine::LineTable::clear() { } DWARFDebugLine::ParsingState::ParsingState(struct LineTable *LT) - : LineTable(LT), RowNumber(0) { + : LineTable(LT) { resetRowAndSequence(); } diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp index ed1f5f46dcfb..861114bde1f2 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -59,48 +59,13 @@ static const DWARFFormValue::FormClass DWARF4FormClasses[] = { DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present }; -namespace { - -/// A helper class that can be used in DWARFFormValue.cpp functions that need -/// to know the byte size of DW_FORM values that vary in size depending on the -/// DWARF version, address byte size, or DWARF32 or DWARF64. -class FormSizeHelper { - uint16_t Version; - uint8_t AddrSize; - llvm::dwarf::DwarfFormat Format; - -public: - FormSizeHelper(uint16_t V, uint8_t A, llvm::dwarf::DwarfFormat F) - : Version(V), AddrSize(A), Format(F) {} - - uint8_t getAddressByteSize() const { return AddrSize; } - - uint8_t getRefAddrByteSize() const { - if (Version == 2) - return AddrSize; - return getDwarfOffsetByteSize(); - } - - uint8_t getDwarfOffsetByteSize() const { - switch (Format) { - case dwarf::DwarfFormat::DWARF32: - return 4; - case dwarf::DwarfFormat::DWARF64: - return 8; - } - llvm_unreachable("Invalid Format value"); - } -}; - -} // end anonymous namespace - -template -static Optional getFixedByteSize(dwarf::Form Form, const T *U) { +Optional +DWARFFormValue::getFixedByteSize(dwarf::Form Form, + const DWARFFormParams Params) { switch (Form) { case DW_FORM_addr: - if (U) - return U->getAddressByteSize(); - return None; + assert(Params.Version && Params.AddrSize && "Invalid Params for form"); + return Params.AddrSize; case DW_FORM_block: // ULEB128 length L followed by L bytes. case DW_FORM_block1: // 1 byte length L followed by L bytes. @@ -121,9 +86,8 @@ static Optional getFixedByteSize(dwarf::Form Form, const T *U) { return None; case DW_FORM_ref_addr: - if (U) - return U->getRefAddrByteSize(); - return None; + assert(Params.Version && Params.AddrSize && "Invalid Params for form"); + return Params.getRefAddrByteSize(); case DW_FORM_flag: case DW_FORM_data1: @@ -138,6 +102,9 @@ static Optional getFixedByteSize(dwarf::Form Form, const T *U) { case DW_FORM_addrx2: return 2; + case DW_FORM_strx3: + return 3; + case DW_FORM_data4: case DW_FORM_ref4: case DW_FORM_ref_sup4: @@ -151,9 +118,8 @@ static Optional getFixedByteSize(dwarf::Form Form, const T *U) { case DW_FORM_line_strp: case DW_FORM_sec_offset: case DW_FORM_strp_sup: - if (U) - return U->getDwarfOffsetByteSize(); - return None; + assert(Params.Version && Params.AddrSize && "Invalid Params for form"); + return Params.getDwarfOffsetByteSize(); case DW_FORM_data8: case DW_FORM_ref8: @@ -178,9 +144,9 @@ static Optional getFixedByteSize(dwarf::Form Form, const T *U) { return None; } -template -static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, - uint32_t *OffsetPtr, const T *U) { +bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, + uint32_t *OffsetPtr, + const DWARFFormParams Params) { bool Indirect = false; do { switch (Form) { @@ -240,7 +206,8 @@ static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, case DW_FORM_line_strp: case DW_FORM_GNU_ref_alt: case DW_FORM_GNU_strp_alt: - if (Optional FixedSize = ::getFixedByteSize(Form, U)) { + if (Optional FixedSize = + DWARFFormValue::getFixedByteSize(Form, Params)) { *OffsetPtr += *FixedSize; return true; } @@ -274,19 +241,6 @@ static bool skipFormValue(dwarf::Form Form, const DataExtractor &DebugInfoData, return true; } -Optional DWARFFormValue::getFixedByteSize(dwarf::Form Form, - const DWARFUnit *U) { - return ::getFixedByteSize(Form, U); -} - -Optional -DWARFFormValue::getFixedByteSize(dwarf::Form Form, uint16_t Version, - uint8_t AddrSize, - llvm::dwarf::DwarfFormat Format) { - FormSizeHelper FSH(Version, AddrSize, Format); - return ::getFixedByteSize(Form, &FSH); -} - bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { // First, check DWARF4 form classes. if (Form < makeArrayRef(DWARF4FormClasses).size() && @@ -302,6 +256,10 @@ bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const { case DW_FORM_GNU_str_index: case DW_FORM_GNU_strp_alt: case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: return (FC == FC_String); case DW_FORM_implicit_const: return (FC == FC_Constant); @@ -368,6 +326,9 @@ bool DWARFFormValue::extractValue(const DataExtractor &Data, case DW_FORM_addrx2: Value.uval = Data.getU16(OffsetPtr); break; + case DW_FORM_strx3: + Value.uval = Data.getU24(OffsetPtr); + break; case DW_FORM_data4: case DW_FORM_ref4: case DW_FORM_ref_sup4: @@ -438,24 +399,6 @@ bool DWARFFormValue::extractValue(const DataExtractor &Data, return true; } -bool DWARFFormValue::skipValue(DataExtractor DebugInfoData, uint32_t *OffsetPtr, - const DWARFUnit *U) const { - return DWARFFormValue::skipValue(Form, DebugInfoData, OffsetPtr, U); -} - -bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, - uint32_t *OffsetPtr, const DWARFUnit *U) { - return skipFormValue(Form, DebugInfoData, OffsetPtr, U); -} - -bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData, - uint32_t *OffsetPtr, uint16_t Version, - uint8_t AddrSize, - llvm::dwarf::DwarfFormat Format) { - FormSizeHelper FSH(Version, AddrSize, Format); - return skipFormValue(Form, DebugInfoData, OffsetPtr, &FSH); -} - void DWARFFormValue::dump(raw_ostream &OS) const { uint64_t UValue = Value.uval; bool CURelativeOffset = false; @@ -545,6 +488,10 @@ void DWARFFormValue::dump(raw_ostream &OS) const { dumpString(OS); break; case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: case DW_FORM_GNU_str_index: OS << format(" indexed (%8.8x) string = ", (uint32_t)UValue); dumpString(OS); @@ -623,7 +570,9 @@ Optional DWARFFormValue::getAsCString() const { if (Form == DW_FORM_GNU_strp_alt || U == nullptr) return None; uint32_t Offset = Value.uval; - if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx) { + if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx || + Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 || + Form == DW_FORM_strx4) { uint64_t StrOffset; if (!U->getStringOffsetSectionItem(Offset, StrOffset)) return None; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index 09e6a292e5fe..fd9c7c2b1d46 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -1,4 +1,4 @@ -//===-- DWARFUnit.cpp -----------------------------------------------------===// +//===- DWARFUnit.cpp ------------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFUnit.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h" @@ -17,8 +16,6 @@ #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" #include "llvm/DebugInfo/DWARF/DWARFDie.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Casting.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Path.h" #include @@ -26,6 +23,7 @@ #include #include #include +#include #include using namespace llvm; @@ -55,8 +53,8 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, const DWARFUnitIndex::Entry *IndexEntry) : Context(DC), InfoSection(Section), Abbrev(DA), RangeSection(RS), LineSection(LS), StringSection(SS), StringOffsetSection(SOS), - StringOffsetSectionBase(0), AddrOffsetSection(AOS), isLittleEndian(LE), - isDWO(IsDWO), UnitSection(UnitSection), IndexEntry(IndexEntry) { + AddrOffsetSection(AOS), isLittleEndian(LE), isDWO(IsDWO), + UnitSection(UnitSection), IndexEntry(IndexEntry) { clear(); } @@ -64,11 +62,13 @@ DWARFUnit::~DWARFUnit() = default; bool DWARFUnit::getAddrOffsetSectionItem(uint32_t Index, uint64_t &Result) const { - uint32_t Offset = AddrOffsetSectionBase + Index * AddrSize; - if (AddrOffsetSection->Data.size() < Offset + AddrSize) + uint32_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize(); + if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize()) return false; - DataExtractor DA(AddrOffsetSection->Data, isLittleEndian, AddrSize); - Result = getRelocatedValue(DA, AddrSize, &Offset, &AddrOffsetSection->Relocs); + DataExtractor DA(AddrOffsetSection->Data, isLittleEndian, + getAddressByteSize()); + Result = getRelocatedValue(DA, getAddressByteSize(), &Offset, + &AddrOffsetSection->Relocs); return true; } @@ -94,15 +94,17 @@ uint64_t DWARFUnit::getStringOffsetSectionRelocation(uint32_t Index) const { bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { Length = debug_info.getU32(offset_ptr); - Version = debug_info.getU16(offset_ptr); + // FIXME: Support DWARF64. + FormParams.Format = DWARF32; + FormParams.Version = debug_info.getU16(offset_ptr); uint64_t AbbrOffset; - if (Version >= 5) { + if (FormParams.Version >= 5) { UnitType = debug_info.getU8(offset_ptr); - AddrSize = debug_info.getU8(offset_ptr); + FormParams.AddrSize = debug_info.getU8(offset_ptr); AbbrOffset = debug_info.getU32(offset_ptr); } else { AbbrOffset = debug_info.getU32(offset_ptr); - AddrSize = debug_info.getU8(offset_ptr); + FormParams.AddrSize = debug_info.getU8(offset_ptr); } if (IndexEntry) { if (AbbrOffset) @@ -117,14 +119,14 @@ bool DWARFUnit::extractImpl(DataExtractor debug_info, uint32_t *offset_ptr) { } bool LengthOK = debug_info.isValidOffset(getNextUnitOffset() - 1); - bool VersionOK = DWARFContext::isSupportedVersion(Version); - bool AddrSizeOK = AddrSize == 4 || AddrSize == 8; + bool VersionOK = DWARFContext::isSupportedVersion(getVersion()); + bool AddrSizeOK = getAddressByteSize() == 4 || getAddressByteSize() == 8; if (!LengthOK || !VersionOK || !AddrSizeOK) return false; // Keep track of the highest DWARF version we encounter across all units. - Context.setMaxVersionIfGreater(Version); + Context.setMaxVersionIfGreater(getVersion()); Abbrevs = Abbrev->getAbbreviationDeclarationSet(AbbrOffset); return Abbrevs != nullptr; @@ -150,7 +152,8 @@ bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, DWARFDebugRangeList &RangeList) const { // Require that compile unit is extracted. assert(!DieArray.empty()); - DataExtractor RangesData(RangeSection->Data, isLittleEndian, AddrSize); + DataExtractor RangesData(RangeSection->Data, isLittleEndian, + getAddressByteSize()); uint32_t ActualRangeListOffset = RangeSectionBase + RangeListOffset; return RangeList.extract(RangesData, &ActualRangeListOffset, RangeSection->Relocs); @@ -159,9 +162,8 @@ bool DWARFUnit::extractRangeList(uint32_t RangeListOffset, void DWARFUnit::clear() { Offset = 0; Length = 0; - Version = 0; Abbrevs = nullptr; - AddrSize = 0; + FormParams = DWARFFormParams({0, 0, DWARF32}); BaseAddr = 0; RangeSectionBase = 0; AddrOffsetSectionBase = 0; diff --git a/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp index a6240fb60143..41907e570563 100644 --- a/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ b/contrib/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -279,7 +279,6 @@ bool DWARFVerifier::handleDebugLine() { bool DWARFVerifier::handleAppleNames() { NumAppleNamesErrors = 0; - OS << "Verifying .apple_names...\n"; DataExtractor AppleNamesSection(DCtx.getAppleNamesSection().Data, DCtx.isLittleEndian(), 0); @@ -288,10 +287,11 @@ bool DWARFVerifier::handleAppleNames() { DCtx.getAppleNamesSection().Relocs); if (!AppleNames.extract()) { - OS << "error: cannot extract .apple_names accelerator table\n"; - return false; + return true; } + OS << "Verifying .apple_names...\n"; + // Verify that all buckets have a valid hash index or are empty uint32_t NumBuckets = AppleNames.getNumBuckets(); uint32_t NumHashes = AppleNames.getNumHashes(); diff --git a/contrib/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp b/contrib/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp index 5b1b5d8dc4d5..0f4f785abf55 100644 --- a/contrib/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp @@ -1,3 +1,4 @@ +//===- MSFBuilder.cpp -----------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -6,22 +7,30 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFError.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include +#include +#include +#include +#include +#include +#include using namespace llvm; using namespace llvm::msf; using namespace llvm::support; -namespace { -const uint32_t kSuperBlockBlock = 0; -const uint32_t kFreePageMap0Block = 1; -const uint32_t kFreePageMap1Block = 2; -const uint32_t kNumReservedPages = 3; +static const uint32_t kSuperBlockBlock = 0; +static const uint32_t kFreePageMap0Block = 1; +static const uint32_t kFreePageMap1Block = 2; +static const uint32_t kNumReservedPages = 3; -const uint32_t kDefaultFreePageMap = kFreePageMap0Block; -const uint32_t kDefaultBlockMapAddr = kNumReservedPages; -} +static const uint32_t kDefaultFreePageMap = kFreePageMap0Block; +static const uint32_t kDefaultBlockMapAddr = kNumReservedPages; MSFBuilder::MSFBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, BumpPtrAllocator &Allocator) @@ -263,7 +272,7 @@ Expected MSFBuilder::build() { // The stream sizes should be re-allocated as a stable pointer and the stream // map should have each of its entries allocated as a separate stable pointer. - if (StreamData.size() > 0) { + if (!StreamData.empty()) { ulittle32_t *Sizes = Allocator.Allocate(StreamData.size()); L.StreamSizes = ArrayRef(Sizes, StreamData.size()); L.StreamMap.resize(StreamData.size()); diff --git a/contrib/llvm/lib/DebugInfo/MSF/MSFCommon.cpp b/contrib/llvm/lib/DebugInfo/MSF/MSFCommon.cpp index fdab7884646e..1facf5efb4bb 100644 --- a/contrib/llvm/lib/DebugInfo/MSF/MSFCommon.cpp +++ b/contrib/llvm/lib/DebugInfo/MSF/MSFCommon.cpp @@ -1,4 +1,4 @@ -//===- MSFCommon.cpp - Common types and functions for MSF files -*- C++ -*-===// +//===- MSFCommon.cpp - Common types and functions for MSF files -----------===// // // The LLVM Compiler Infrastructure // @@ -9,6 +9,10 @@ #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/MSF/MSFError.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include +#include using namespace llvm; using namespace llvm::msf; diff --git a/contrib/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp b/contrib/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp index faf2442bc94b..e45f4ae0ed94 100644 --- a/contrib/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp +++ b/contrib/llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp @@ -8,23 +8,33 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/MSF/MappedBlockStream.h" - -#include "llvm/DebugInfo/MSF/IMSFFile.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" -#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include +#include +#include +#include +#include +#include using namespace llvm; using namespace llvm::msf; namespace { + template class MappedBlockStreamImpl : public Base { public: template MappedBlockStreamImpl(Args &&... Params) : Base(std::forward(Params)...) {} }; -} + +} // end anonymous namespace static void initializeFpmStreamLayout(const MSFLayout &Layout, MSFStreamLayout &FpmLayout) { @@ -39,7 +49,8 @@ static void initializeFpmStreamLayout(const MSFLayout &Layout, FpmLayout.Length = msf::getFullFpmByteSize(Layout); } -typedef std::pair Interval; +using Interval = std::pair; + static Interval intersect(const Interval &I1, const Interval &I2) { return std::make_pair(std::max(I1.first, I2.first), std::min(I1.second, I2.second)); @@ -214,7 +225,7 @@ bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, uint32_t OffsetInBlock = Offset % BlockSize; uint32_t BytesFromFirstBlock = std::min(Size, BlockSize - OffsetInBlock); uint32_t NumAdditionalBlocks = - llvm::alignTo(Size - BytesFromFirstBlock, BlockSize) / BlockSize; + alignTo(Size - BytesFromFirstBlock, BlockSize) / BlockSize; uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; uint32_t E = StreamLayout.Blocks[BlockNum]; diff --git a/contrib/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp b/contrib/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp index ef47b92b4f2f..ef9390cda312 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/DIA/DIASession.cpp @@ -151,7 +151,7 @@ void DIASession::setLoadAddress(uint64_t Address) { Session->put_loadAddress(Address); } -std::unique_ptr DIASession::getGlobalScope() const { +std::unique_ptr DIASession::getGlobalScope() { CComPtr GlobalScope; if (S_OK != Session->get_globalScope(&GlobalScope)) return nullptr; diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp index 81a9d3eeec61..745dd742aadc 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp @@ -51,6 +51,7 @@ DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName, uint32_t ModIndex, msf::MSFBuilder &Msf) : MSF(Msf), ModuleName(ModuleName) { + ::memset(&Layout, 0, sizeof(Layout)); Layout.Mod = ModIndex; } @@ -102,6 +103,7 @@ template struct Foo { template Foo makeFoo(T &&t) { return Foo(std::move(t)); } void DbiModuleDescriptorBuilder::finalize() { + Layout.SC.ModuleIndex = Layout.Mod; Layout.FileNameOffs = 0; // TODO: Fix this Layout.Flags = 0; // TODO: Fix this Layout.C11Bytes = 0; @@ -182,3 +184,9 @@ void DbiModuleDescriptorBuilder::addDebugSubsection( C13Builders.push_back(llvm::make_unique( std::move(Subsection), CodeViewContainer::Pdb)); } + +void DbiModuleDescriptorBuilder::addDebugSubsection( + const DebugSubsectionRecord &SubsectionContents) { + C13Builders.push_back(llvm::make_unique( + SubsectionContents, CodeViewContainer::Pdb)); +} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp index 24322d942fac..a1f0671dec3e 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -99,29 +99,27 @@ Error DbiStream::reload() { return make_error(raw_error_code::corrupt_file, "DBI type server substream not aligned."); - BinaryStreamRef ModInfoSubstream; - BinaryStreamRef FileInfoSubstream; - if (auto EC = - Reader.readStreamRef(ModInfoSubstream, Header->ModiSubstreamSize)) + if (auto EC = Reader.readSubstream(ModiSubstream, Header->ModiSubstreamSize)) return EC; - if (auto EC = Reader.readStreamRef(SecContrSubstream, + if (auto EC = Reader.readSubstream(SecContrSubstream, Header->SecContrSubstreamSize)) return EC; - if (auto EC = Reader.readStreamRef(SecMapSubstream, Header->SectionMapSize)) + if (auto EC = Reader.readSubstream(SecMapSubstream, Header->SectionMapSize)) return EC; - if (auto EC = Reader.readStreamRef(FileInfoSubstream, Header->FileInfoSize)) + if (auto EC = Reader.readSubstream(FileInfoSubstream, Header->FileInfoSize)) return EC; if (auto EC = - Reader.readStreamRef(TypeServerMapSubstream, Header->TypeServerSize)) + Reader.readSubstream(TypeServerMapSubstream, Header->TypeServerSize)) return EC; - if (auto EC = Reader.readStreamRef(ECSubstream, Header->ECSubstreamSize)) + if (auto EC = Reader.readSubstream(ECSubstream, Header->ECSubstreamSize)) return EC; if (auto EC = Reader.readArray( DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t))) return EC; - if (auto EC = Modules.initialize(ModInfoSubstream, FileInfoSubstream)) + if (auto EC = Modules.initialize(ModiSubstream.StreamData, + FileInfoSubstream.StreamData)) return EC; if (auto EC = initializeSectionContributionData()) @@ -137,8 +135,8 @@ Error DbiStream::reload() { return make_error(raw_error_code::corrupt_file, "Found unexpected bytes in DBI Stream."); - if (ECSubstream.getLength() > 0) { - BinaryStreamReader ECReader(ECSubstream); + if (!ECSubstream.empty()) { + BinaryStreamReader ECReader(ECSubstream.StreamData); if (auto EC = ECNames.reload(ECReader)) return EC; } @@ -228,10 +226,10 @@ void DbiStream::visitSectionContributions( } Error DbiStream::initializeSectionContributionData() { - if (SecContrSubstream.getLength() == 0) + if (SecContrSubstream.empty()) return Error::success(); - BinaryStreamReader SCReader(SecContrSubstream); + BinaryStreamReader SCReader(SecContrSubstream.StreamData); if (auto EC = SCReader.readEnum(SectionContribVersion)) return EC; @@ -302,11 +300,33 @@ Error DbiStream::initializeFpoRecords() { return Error::success(); } +BinarySubstreamRef DbiStream::getSectionContributionData() const { + return SecContrSubstream; +} + +BinarySubstreamRef DbiStream::getSecMapSubstreamData() const { + return SecMapSubstream; +} + +BinarySubstreamRef DbiStream::getModiSubstreamData() const { + return ModiSubstream; +} + +BinarySubstreamRef DbiStream::getFileInfoSubstreamData() const { + return FileInfoSubstream; +} + +BinarySubstreamRef DbiStream::getTypeServerMapSubstreamData() const { + return TypeServerMapSubstream; +} + +BinarySubstreamRef DbiStream::getECSubstreamData() const { return ECSubstream; } + Error DbiStream::initializeSectionMapData() { - if (SecMapSubstream.getLength() == 0) + if (SecMapSubstream.empty()) return Error::success(); - BinaryStreamReader SMReader(SecMapSubstream); + BinaryStreamReader SMReader(SecMapSubstream.StreamData); const SecMapHeader *Header; if (auto EC = SMReader.readObject(Header)) return EC; diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp index e7304b444f23..aad247ea185f 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -90,10 +90,14 @@ Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) { if (ModIter == ModiMap.end()) return make_error(raw_error_code::no_entry, "The specified module was not found"); + return addModuleSourceFile(*ModIter->second, File); +} + +Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module, + StringRef File) { uint32_t Index = SourceFileNames.size(); SourceFileNames.insert(std::make_pair(File, Index)); - auto &ModEntry = *ModIter; - ModEntry.second->addSourceFile(File); + Module.addSourceFile(File); return Error::success(); } @@ -233,6 +237,7 @@ Error DbiStreamBuilder::finalize() { return EC; DbiStreamHeader *H = Allocator.Allocate(); + ::memset(H, 0, sizeof(DbiStreamHeader)); H->VersionHeader = *VerHeader; H->VersionSignature = -1; H->Age = Age; diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp index a3979d480bf4..21b66b3e7bcf 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -57,6 +57,10 @@ Error InfoStream::reload() { uint32_t NewOffset = Reader.getOffset(); NamedStreamMapByteSize = NewOffset - Offset; + Reader.setOffset(Offset); + if (auto EC = Reader.readSubstream(SubNamedStreams, NamedStreamMapByteSize)) + return EC; + bool Stop = false; while (!Stop && !Reader.empty()) { PdbRaw_FeatureSig Sig; @@ -129,3 +133,7 @@ ArrayRef InfoStream::getFeatureSignatures() const { const NamedStreamMap &InfoStream::getNamedStreams() const { return NamedStreams; } + +BinarySubstreamRef InfoStream::getNamedStreamsBuffer() const { + return SubNamedStreams; +} diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp index 4186f2eb6ba0..83c56574a16e 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp @@ -47,15 +47,19 @@ Error ModuleDebugStreamRef::reload() { if (auto EC = Reader.readInteger(Signature)) return EC; - if (auto EC = Reader.readArray(SymbolsSubstream, SymbolSize - 4)) + if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize - 4)) + return EC; + if (auto EC = Reader.readSubstream(C11LinesSubstream, C11Size)) + return EC; + if (auto EC = Reader.readSubstream(C13LinesSubstream, C13Size)) return EC; - if (auto EC = Reader.readStreamRef(C11LinesSubstream, C11Size)) - return EC; - if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) + BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData); + if (auto EC = + SymbolReader.readArray(SymbolArray, SymbolReader.bytesRemaining())) return EC; - BinaryStreamReader SubsectionsReader(C13LinesSubstream); + BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData); if (auto EC = SubsectionsReader.readArray(Subsections, SubsectionsReader.bytesRemaining())) return EC; @@ -63,7 +67,7 @@ Error ModuleDebugStreamRef::reload() { uint32_t GlobalRefsSize; if (auto EC = Reader.readInteger(GlobalRefsSize)) return EC; - if (auto EC = Reader.readStreamRef(GlobalRefsSubstream, GlobalRefsSize)) + if (auto EC = Reader.readSubstream(GlobalRefsSubstream, GlobalRefsSize)) return EC; if (Reader.bytesRemaining() > 0) return make_error(raw_error_code::corrupt_file, @@ -72,9 +76,25 @@ Error ModuleDebugStreamRef::reload() { return Error::success(); } +BinarySubstreamRef ModuleDebugStreamRef::getSymbolsSubstream() const { + return SymbolsSubstream; +} + +BinarySubstreamRef ModuleDebugStreamRef::getC11LinesSubstream() const { + return C11LinesSubstream; +} + +BinarySubstreamRef ModuleDebugStreamRef::getC13LinesSubstream() const { + return C13LinesSubstream; +} + +BinarySubstreamRef ModuleDebugStreamRef::getGlobalRefsSubstream() const { + return GlobalRefsSubstream; +} + iterator_range ModuleDebugStreamRef::symbols(bool *HadError) const { - return make_range(SymbolsSubstream.begin(HadError), SymbolsSubstream.end()); + return make_range(SymbolArray.begin(HadError), SymbolArray.end()); } llvm::iterator_range @@ -83,7 +103,7 @@ ModuleDebugStreamRef::subsections() const { } bool ModuleDebugStreamRef::hasDebugSubsections() const { - return C13LinesSubstream.getLength() > 0; + return !C13LinesSubstream.empty(); } Error ModuleDebugStreamRef::commit() { return Error::success(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp index c7ba32b82bc6..4f90cd9cd8ac 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp @@ -23,6 +23,14 @@ using namespace llvm; using namespace llvm::pdb; +// FIXME: This shouldn't be necessary, but if we insert the strings in any +// other order, cvdump cannot read the generated name map. This suggests that +// we may be using the wrong hash function. A closer inspection of the cvdump +// source code may reveal something, but for now this at least makes us work, +// even if only by accident. +static constexpr const char *OrderedStreamNames[] = {"/LinkInfo", "/names", + "/src/headerblock"}; + NamedStreamMap::NamedStreamMap() = default; Error NamedStreamMap::load(BinaryStreamReader &Stream) { @@ -73,9 +81,10 @@ Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes)) return EC; - // Now all of the string data itself. - for (const auto &Item : Mapping) { - if (auto EC = Writer.writeCString(Item.getKey())) + for (const auto &Name : OrderedStreamNames) { + auto Item = Mapping.find(Name); + assert(Item != Mapping.end()); + if (auto EC = Writer.writeCString(Item->getKey())) return EC; } @@ -93,9 +102,12 @@ uint32_t NamedStreamMap::finalize() { // Build the finalized hash table. FinalizedHashTable.clear(); FinalizedInfo.emplace(); - for (const auto &Item : Mapping) { - FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item.getValue()); - FinalizedInfo->StringDataBytes += Item.getKeyLength() + 1; + + for (const auto &Name : OrderedStreamNames) { + auto Item = Mapping.find(Name); + assert(Item != Mapping.end()); + FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue()); + FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1; } // Number of bytes of string data. diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp index 77f832582f82..180c169ec209 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp @@ -9,17 +9,24 @@ #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/ADT/STLExtras.h" + namespace llvm { namespace pdb { NativeCompilandSymbol::NativeCompilandSymbol(NativeSession &Session, + uint32_t SymbolId, DbiModuleDescriptor MI) - : NativeRawSymbol(Session), Module(MI) {} + : NativeRawSymbol(Session, SymbolId), Module(MI) {} PDB_SymType NativeCompilandSymbol::getSymTag() const { return PDB_SymType::Compiland; } +std::unique_ptr NativeCompilandSymbol::clone() const { + return llvm::make_unique(Session, SymbolId, Module); +} + bool NativeCompilandSymbol::isEditAndContinueEnabled() const { return Module.hasECInfo(); } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp index 97319fd77d11..c23120041164 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp @@ -34,7 +34,7 @@ NativeEnumModules::getChildAtIndex(uint32_t Index) const { return nullptr; return std::unique_ptr(new PDBSymbolCompiland( Session, std::unique_ptr(new NativeCompilandSymbol( - Session, Modules.getModuleDescriptor(Index))))); + Session, 0, Modules.getModuleDescriptor(Index))))); } std::unique_ptr NativeEnumModules::getNext() { diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp index bb52560be167..6206155b9fb6 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h" @@ -17,8 +18,12 @@ namespace llvm { namespace pdb { -NativeExeSymbol::NativeExeSymbol(NativeSession &Session) - : NativeRawSymbol(Session), File(Session.getPDBFile()) {} +NativeExeSymbol::NativeExeSymbol(NativeSession &Session, uint32_t SymbolId) + : NativeRawSymbol(Session, SymbolId), File(Session.getPDBFile()) {} + +std::unique_ptr NativeExeSymbol::clone() const { + return llvm::make_unique(Session, SymbolId); +} std::unique_ptr NativeExeSymbol::findChildren(PDB_SymType Type) const { diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp index 70968d4330b0..ed6db63edbab 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp @@ -22,8 +22,8 @@ using namespace llvm; using namespace llvm::pdb; -NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession) - : Session(PDBSession) {} +NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession, uint32_t SymbolId) + : Session(PDBSession), SymbolId(SymbolId) {} void NativeRawSymbol::dump(raw_ostream &OS, int Indent) const {} @@ -253,9 +253,7 @@ uint32_t NativeRawSymbol::getSubTypeId() const { std::string NativeRawSymbol::getSymbolsFileName() const { return ""; } -uint32_t NativeRawSymbol::getSymIndexId() const { - return 0; -} +uint32_t NativeRawSymbol::getSymIndexId() const { return SymbolId; } uint32_t NativeRawSymbol::getTargetOffset() const { return 0; diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp index 7e6843bceb7d..3ab381e76e62 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -70,12 +70,11 @@ uint64_t NativeSession::getLoadAddress() const { return 0; } void NativeSession::setLoadAddress(uint64_t Address) {} -std::unique_ptr NativeSession::getGlobalScope() const { - auto RawSymbol = - llvm::make_unique(const_cast(*this)); +std::unique_ptr NativeSession::getGlobalScope() { + auto RawSymbol = llvm::make_unique(*this, 0); auto PdbSymbol(PDBSymbol::create(*this, std::move(RawSymbol))); std::unique_ptr ExeSymbol( - static_cast(PdbSymbol.release())); + static_cast(PdbSymbol.release())); return ExeSymbol; } diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp index a9597cdf4c4d..4f6ebb0cb342 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -230,6 +230,14 @@ ArrayRef PDBFile::getDirectoryBlockArray() const { return ContainerLayout.DirectoryBlocks; } +MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const { + MSFStreamLayout Result; + auto Blocks = getStreamBlockList(StreamIdx); + Result.Blocks.assign(Blocks.begin(), Blocks.end()); + Result.Length = getStreamByteSize(StreamIdx); + return Result; +} + Expected PDBFile::getPDBGlobalsStream() { if (!Globals) { auto DbiS = getPDBDbiStream(); diff --git a/contrib/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp b/contrib/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp index 67c803d3124e..f917ef91f639 100644 --- a/contrib/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ b/contrib/llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -66,7 +66,13 @@ Error TpiStream::reload() { "TPI Stream Invalid number of hash buckets."); // The actual type records themselves come from this stream - if (auto EC = Reader.readArray(TypeRecords, Header->TypeRecordBytes)) + if (auto EC = + Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes)) + return EC; + + BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData); + if (auto EC = + RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size())) return EC; // Hash indices, hash values, etc come from the hash stream. @@ -135,6 +141,10 @@ uint16_t TpiStream::getTypeHashStreamAuxIndex() const { uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; } uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; } +BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const { + return TypeRecordsSubstream; +} + FixedStreamArray TpiStream::getHashValues() const { return HashValues; } diff --git a/contrib/llvm/lib/ExecutionEngine/Orc/OrcCBindings.cpp b/contrib/llvm/lib/ExecutionEngine/Orc/OrcCBindings.cpp index 8dcd49aaab5b..5fe259f80b6f 100644 --- a/contrib/llvm/lib/ExecutionEngine/Orc/OrcCBindings.cpp +++ b/contrib/llvm/lib/ExecutionEngine/Orc/OrcCBindings.cpp @@ -12,6 +12,24 @@ using namespace llvm; +LLVMSharedModuleRef LLVMOrcMakeSharedModule(LLVMModuleRef Mod) { + return wrap(new std::shared_ptr(unwrap(Mod))); +} + +void LLVMOrcDisposeSharedModuleRef(LLVMSharedModuleRef SharedMod) { + delete unwrap(SharedMod); +} + +LLVMSharedObjectBufferRef +LLVMOrcMakeSharedObjectBuffer(LLVMMemoryBufferRef ObjBuffer) { + return wrap(new std::shared_ptr(unwrap(ObjBuffer))); +} + +void +LLVMOrcDisposeSharedObjectBufferRef(LLVMSharedObjectBufferRef SharedObjBuffer) { + delete unwrap(SharedObjBuffer); +} + LLVMOrcJITStackRef LLVMOrcCreateInstance(LLVMTargetMachineRef TM) { TargetMachine *TM2(unwrap(TM)); @@ -65,21 +83,23 @@ LLVMOrcErrorCode LLVMOrcSetIndirectStubPointer(LLVMOrcJITStackRef JITStack, } LLVMOrcModuleHandle -LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod, +LLVMOrcAddEagerlyCompiledIR(LLVMOrcJITStackRef JITStack, + LLVMSharedModuleRef Mod, LLVMOrcSymbolResolverFn SymbolResolver, void *SymbolResolverCtx) { OrcCBindingsStack &J = *unwrap(JITStack); - Module *M(unwrap(Mod)); - return J.addIRModuleEager(M, SymbolResolver, SymbolResolverCtx); + std::shared_ptr *M(unwrap(Mod)); + return J.addIRModuleEager(*M, SymbolResolver, SymbolResolverCtx); } LLVMOrcModuleHandle -LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, LLVMModuleRef Mod, +LLVMOrcAddLazilyCompiledIR(LLVMOrcJITStackRef JITStack, + LLVMSharedModuleRef Mod, LLVMOrcSymbolResolverFn SymbolResolver, void *SymbolResolverCtx) { OrcCBindingsStack &J = *unwrap(JITStack); - Module *M(unwrap(Mod)); - return J.addIRModuleLazy(M, SymbolResolver, SymbolResolverCtx); + std::shared_ptr *M(unwrap(Mod)); + return J.addIRModuleLazy(*M, SymbolResolver, SymbolResolverCtx); } void LLVMOrcRemoveModule(LLVMOrcJITStackRef JITStack, LLVMOrcModuleHandle H) { diff --git a/contrib/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h b/contrib/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h index a79dd844bf4f..931d0a9eb2ad 100644 --- a/contrib/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h +++ b/contrib/llvm/lib/ExecutionEngine/Orc/OrcCBindingsStack.h @@ -1,4 +1,4 @@ -//===--- OrcCBindingsStack.h - Orc JIT stack for C bindings ---*- C++ -*---===// +//===- OrcCBindingsStack.h - Orc JIT stack for C bindings -----*- C++ -*---===// // // The LLVM Compiler Infrastructure // @@ -11,39 +11,63 @@ #define LLVM_LIB_EXECUTIONENGINE_ORC_ORCCBINDINGSSTACK_H #include "llvm-c/OrcBindings.h" -#include "llvm/ADT/Triple.h" +#include "llvm-c/TargetMachine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/IR/LLVMContext.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CBindingWrapping.h" #include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include +#include +#include +#include namespace llvm { class OrcCBindingsStack; +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(std::shared_ptr, + LLVMSharedModuleRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(std::shared_ptr, + LLVMSharedObjectBufferRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(OrcCBindingsStack, LLVMOrcJITStackRef) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef) class OrcCBindingsStack { public: - typedef orc::JITCompileCallbackManager CompileCallbackMgr; - typedef orc::RTDyldObjectLinkingLayer<> ObjLayerT; - typedef orc::IRCompileLayer CompileLayerT; - typedef orc::CompileOnDemandLayer - CODLayerT; - typedef std::function()> - CallbackManagerBuilder; + using CompileCallbackMgr = orc::JITCompileCallbackManager; + using ObjLayerT = orc::RTDyldObjectLinkingLayer; + using CompileLayerT = orc::IRCompileLayer; + using CODLayerT = + orc::CompileOnDemandLayer; - typedef CODLayerT::IndirectStubsManagerBuilderT IndirectStubsManagerBuilder; + using CallbackManagerBuilder = + std::function()>; + + using IndirectStubsManagerBuilder = CODLayerT::IndirectStubsManagerBuilderT; private: class GenericHandle { public: - virtual ~GenericHandle() {} + virtual ~GenericHandle() = default; + virtual JITSymbol findSymbolIn(const std::string &Name, bool ExportedSymbolsOnly) = 0; virtual void removeModule() = 0; @@ -51,7 +75,7 @@ class OrcCBindingsStack { template class GenericHandleImpl : public GenericHandle { public: - GenericHandleImpl(LayerT &Layer, typename LayerT::ModuleSetHandleT Handle) + GenericHandleImpl(LayerT &Layer, typename LayerT::ModuleHandleT Handle) : Layer(Layer), Handle(std::move(Handle)) {} JITSymbol findSymbolIn(const std::string &Name, @@ -59,31 +83,28 @@ class OrcCBindingsStack { return Layer.findSymbolIn(Handle, Name, ExportedSymbolsOnly); } - void removeModule() override { return Layer.removeModuleSet(Handle); } + void removeModule() override { return Layer.removeModule(Handle); } private: LayerT &Layer; - typename LayerT::ModuleSetHandleT Handle; + typename LayerT::ModuleHandleT Handle; }; template std::unique_ptr> - createGenericHandle(LayerT &Layer, typename LayerT::ModuleSetHandleT Handle) { + createGenericHandle(LayerT &Layer, typename LayerT::ModuleHandleT Handle) { return llvm::make_unique>(Layer, std::move(Handle)); } public: - // We need a 'ModuleSetHandleT' to conform to the layer concept. - typedef unsigned ModuleSetHandleT; - - typedef unsigned ModuleHandleT; + using ModuleHandleT = unsigned; OrcCBindingsStack(TargetMachine &TM, std::unique_ptr CCMgr, IndirectStubsManagerBuilder IndirectStubsMgrBuilder) : DL(TM.createDataLayout()), IndirectStubsMgr(IndirectStubsMgrBuilder()), - CCMgr(std::move(CCMgr)), ObjectLayer(), + CCMgr(std::move(CCMgr)), CompileLayer(ObjectLayer, orc::SimpleCompiler(TM)), CODLayer(CompileLayer, [](Function &F) { return std::set({&F}); }, @@ -153,7 +174,7 @@ class OrcCBindingsStack { if (ExternalResolver) return JITSymbol( ExternalResolver(Name.c_str(), ExternalResolverCtx), - llvm::JITSymbolFlags::Exported); + JITSymbolFlags::Exported); return JITSymbol(nullptr); }, @@ -163,11 +184,10 @@ class OrcCBindingsStack { } template - ModuleHandleT addIRModule(LayerT &Layer, Module *M, + ModuleHandleT addIRModule(LayerT &Layer, std::shared_ptr M, std::unique_ptr MemMgr, LLVMOrcSymbolResolverFn ExternalResolver, void *ExternalResolverCtx) { - // Attach a data-layout if one isn't already present. if (M->getDataLayout().isDefault()) M->setDataLayout(DL); @@ -184,11 +204,8 @@ class OrcCBindingsStack { auto Resolver = createResolver(ExternalResolver, ExternalResolverCtx); // Add the module to the JIT. - std::vector S; - S.push_back(std::move(M)); - - auto LH = Layer.addModuleSet(std::move(S), std::move(MemMgr), - std::move(Resolver)); + auto LH = Layer.addModule(std::move(M), std::move(MemMgr), + std::move(Resolver)); ModuleHandleT H = createHandle(Layer, LH); // Run the static constructors, and save the static destructor runner for @@ -201,7 +218,7 @@ class OrcCBindingsStack { return H; } - ModuleHandleT addIRModuleEager(Module *M, + ModuleHandleT addIRModuleEager(std::shared_ptr M, LLVMOrcSymbolResolverFn ExternalResolver, void *ExternalResolverCtx) { return addIRModule(CompileLayer, std::move(M), @@ -209,7 +226,7 @@ class OrcCBindingsStack { std::move(ExternalResolver), ExternalResolverCtx); } - ModuleHandleT addIRModuleLazy(Module *M, + ModuleHandleT addIRModuleLazy(std::shared_ptr M, LLVMOrcSymbolResolverFn ExternalResolver, void *ExternalResolverCtx) { return addIRModule(CODLayer, std::move(M), @@ -238,8 +255,7 @@ class OrcCBindingsStack { private: template - unsigned createHandle(LayerT &Layer, - typename LayerT::ModuleSetHandleT Handle) { + unsigned createHandle(LayerT &Layer, typename LayerT::ModuleHandleT Handle) { unsigned NewHandle; if (!FreeHandleIndexes.empty()) { NewHandle = FreeHandleIndexes.back(); diff --git a/contrib/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp b/contrib/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp index b7a68e041c12..f89f21adff41 100644 --- a/contrib/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp +++ b/contrib/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.cpp @@ -124,5 +124,10 @@ OrcMCJITReplacement::runFunction(Function *F, llvm_unreachable("Full-featured argument passing not supported yet!"); } +void OrcMCJITReplacement::runStaticConstructorsDestructors(bool isDtors) { + for (auto &M : LocalModules) + ExecutionEngine::runStaticConstructorsDestructors(*M, isDtors); +} + } // End namespace orc. } // End namespace llvm. diff --git a/contrib/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h b/contrib/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h index 7dd6b17d33cb..b20690c7caaf 100644 --- a/contrib/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h +++ b/contrib/llvm/lib/ExecutionEngine/Orc/OrcMCJITReplacement.h @@ -1,4 +1,4 @@ -//===---- OrcMCJITReplacement.h - Orc based MCJIT replacement ---*- C++ -*-===// +//===- OrcMCJITReplacement.h - Orc based MCJIT replacement ------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -24,9 +24,12 @@ #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ObjectFile.h" @@ -45,6 +48,9 @@ #include namespace llvm { + +class ObjectCache; + namespace orc { class OrcMCJITReplacement : public ExecutionEngine { @@ -151,7 +157,6 @@ class OrcMCJITReplacement : public ExecutionEngine { }; private: - static ExecutionEngine * createOrcMCJITReplacement(std::string *ErrorMsg, std::shared_ptr MemMgr, @@ -162,10 +167,6 @@ class OrcMCJITReplacement : public ExecutionEngine { } public: - static void Register() { - OrcMCJITReplacementCtor = createOrcMCJITReplacement; - } - OrcMCJITReplacement( std::shared_ptr MemMgr, std::shared_ptr ClientResolver, @@ -178,8 +179,11 @@ class OrcMCJITReplacement : public ExecutionEngine { CompileLayer(ObjectLayer, SimpleCompiler(*this->TM)), LazyEmitLayer(CompileLayer) {} - void addModule(std::unique_ptr M) override { + static void Register() { + OrcMCJITReplacementCtor = createOrcMCJITReplacement; + } + void addModule(std::unique_ptr M) override { // If this module doesn't have a DataLayout attached then attach the // default. if (M->getDataLayout().isDefault()) { @@ -187,29 +191,44 @@ class OrcMCJITReplacement : public ExecutionEngine { } else { assert(M->getDataLayout() == getDataLayout() && "DataLayout Mismatch"); } - Modules.push_back(std::move(M)); - std::vector Ms; - Ms.push_back(&*Modules.back()); - LazyEmitLayer.addModuleSet(std::move(Ms), &MemMgr, &Resolver); + auto *MPtr = M.release(); + ShouldDelete[MPtr] = true; + auto Deleter = + [this](Module *Mod) { + if (ShouldDelete[Mod]) + delete Mod; + }; + LocalModules.push_back(std::shared_ptr(MPtr, std::move(Deleter))); + LazyEmitLayer.addModule(LocalModules.back(), &MemMgr, &Resolver); } void addObjectFile(std::unique_ptr O) override { - std::vector> Objs; - Objs.push_back(std::move(O)); - ObjectLayer.addObjectSet(std::move(Objs), &MemMgr, &Resolver); + auto Obj = + std::make_shared>(std::move(O), + nullptr); + ObjectLayer.addObject(std::move(Obj), &MemMgr, &Resolver); } void addObjectFile(object::OwningBinary O) override { - std::vector>> Objs; - Objs.push_back( - llvm::make_unique>( - std::move(O))); - ObjectLayer.addObjectSet(std::move(Objs), &MemMgr, &Resolver); + auto Obj = + std::make_shared>(std::move(O)); + ObjectLayer.addObject(std::move(Obj), &MemMgr, &Resolver); } void addArchive(object::OwningBinary A) override { Archives.push_back(std::move(A)); } + + bool removeModule(Module *M) override { + for (auto I = LocalModules.begin(), E = LocalModules.end(); I != E; ++I) { + if (I->get() == M) { + ShouldDelete[M] = false; + LocalModules.erase(I); + return true; + } + } + return false; + } uint64_t getSymbolAddress(StringRef Name) { return findSymbol(Name).getAddress(); @@ -256,13 +275,15 @@ class OrcMCJITReplacement : public ExecutionEngine { ArrayRef ArgValues) override; void setObjectCache(ObjectCache *NewCache) override { - CompileLayer.setObjectCache(NewCache); + CompileLayer.getCompiler().setObjectCache(NewCache); } void setProcessAllSections(bool ProcessAllSections) override { ObjectLayer.setProcessAllSections(ProcessAllSections); } + void runStaticConstructorsDestructors(bool isDtors) override; + private: JITSymbol findMangledSymbol(StringRef Name) { if (auto Sym = LazyEmitLayer.findSymbol(Name, false)) @@ -294,10 +315,12 @@ class OrcMCJITReplacement : public ExecutionEngine { } std::unique_ptr &ChildBin = ChildBinOrErr.get(); if (ChildBin->isObject()) { - std::vector> ObjSet; - ObjSet.push_back(std::unique_ptr( - static_cast(ChildBin.release()))); - ObjectLayer.addObjectSet(std::move(ObjSet), &MemMgr, &Resolver); + std::unique_ptr ChildObj( + static_cast(ChildBinOrErr->release())); + auto Obj = + std::make_shared>( + std::move(ChildObj), nullptr); + ObjectLayer.addObject(std::move(Obj), &MemMgr, &Resolver); if (auto Sym = ObjectLayer.findSymbol(Name, true)) return Sym; } @@ -308,34 +331,19 @@ class OrcMCJITReplacement : public ExecutionEngine { class NotifyObjectLoadedT { public: - typedef std::vector> - LoadedObjInfoListT; + using LoadedObjInfoListT = + std::vector>; NotifyObjectLoadedT(OrcMCJITReplacement &M) : M(M) {} - template - void operator()(RTDyldObjectLinkingLayerBase::ObjSetHandleT H, - const ObjListT &Objects, - const LoadedObjInfoListT &Infos) const { + void operator()(RTDyldObjectLinkingLayerBase::ObjHandleT H, + const RTDyldObjectLinkingLayer::ObjectPtr &Obj, + const LoadedObjectInfo &Info) const { M.UnfinalizedSections[H] = std::move(M.SectionsAllocatedSinceLastLoad); M.SectionsAllocatedSinceLastLoad = SectionAddrSet(); - assert(Objects.size() == Infos.size() && - "Incorrect number of Infos for Objects."); - for (unsigned I = 0; I < Objects.size(); ++I) - M.MemMgr.notifyObjectLoaded(&M, getObject(*Objects[I])); + M.MemMgr.notifyObjectLoaded(&M, *Obj->getBinary()); } - private: - static const object::ObjectFile& getObject(const object::ObjectFile &Obj) { - return Obj; - } - - template - static const object::ObjectFile& - getObject(const object::OwningBinary &Obj) { - return *Obj.getBinary(); - } - OrcMCJITReplacement &M; }; @@ -343,7 +351,7 @@ class OrcMCJITReplacement : public ExecutionEngine { public: NotifyFinalizedT(OrcMCJITReplacement &M) : M(M) {} - void operator()(RTDyldObjectLinkingLayerBase::ObjSetHandleT H) { + void operator()(RTDyldObjectLinkingLayerBase::ObjHandleT H) { M.UnfinalizedSections.erase(H); } @@ -360,9 +368,9 @@ class OrcMCJITReplacement : public ExecutionEngine { return MangledName; } - typedef RTDyldObjectLinkingLayer ObjectLayerT; - typedef IRCompileLayer CompileLayerT; - typedef LazyEmittingLayer LazyEmitLayerT; + using ObjectLayerT = RTDyldObjectLinkingLayer; + using CompileLayerT = IRCompileLayer; + using LazyEmitLayerT = LazyEmittingLayer; std::unique_ptr TM; MCJITReplacementMemMgr MemMgr; @@ -380,21 +388,24 @@ class OrcMCJITReplacement : public ExecutionEngine { // We need to store ObjLayerT::ObjSetHandles for each of the object sets // that have been emitted but not yet finalized so that we can forward the // mapSectionAddress calls appropriately. - typedef std::set SectionAddrSet; - struct ObjSetHandleCompare { - bool operator()(ObjectLayerT::ObjSetHandleT H1, - ObjectLayerT::ObjSetHandleT H2) const { + using SectionAddrSet = std::set; + struct ObjHandleCompare { + bool operator()(ObjectLayerT::ObjHandleT H1, + ObjectLayerT::ObjHandleT H2) const { return &*H1 < &*H2; } }; SectionAddrSet SectionsAllocatedSinceLastLoad; - std::map + std::map UnfinalizedSections; + std::map ShouldDelete; + std::vector> LocalModules; std::vector> Archives; }; } // end namespace orc + } // end namespace llvm #endif // LLVM_LIB_EXECUTIONENGINE_ORC_MCJITREPLACEMENT_H diff --git a/contrib/llvm/lib/IR/AsmWriter.cpp b/contrib/llvm/lib/IR/AsmWriter.cpp index 556e122ff82f..c7f112887a30 100644 --- a/contrib/llvm/lib/IR/AsmWriter.cpp +++ b/contrib/llvm/lib/IR/AsmWriter.cpp @@ -1,5 +1,4 @@ - -//===-- AsmWriter.cpp - Printing LLVM as an assembly file -----------------===// +//===- AsmWriter.cpp - Printing LLVM as an assembly file ------------------===// // // The LLVM Compiler Infrastructure // @@ -15,63 +14,105 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/None.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/IR/Argument.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/Attributes.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/CallingConv.h" +#include "llvm/IR/Comdat.h" +#include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" -#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalIFunc.h" +#include "llvm/IR/GlobalIndirectSymbol.h" +#include "llvm/IR/GlobalObject.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/InlineAsm.h" -#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/ModuleSlotTracker.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Statepoint.h" +#include "llvm/IR/Type.h" #include "llvm/IR/TypeFinder.h" +#include "llvm/IR/Use.h" #include "llvm/IR/UseListOrder.h" -#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/IR/User.h" +#include "llvm/IR/Value.h" +#include "llvm/Support/AtomicOrdering.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" -#include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include + using namespace llvm; // Make virtual table appear in this compilation unit. -AssemblyAnnotationWriter::~AssemblyAnnotationWriter() {} +AssemblyAnnotationWriter::~AssemblyAnnotationWriter() = default; //===----------------------------------------------------------------------===// // Helper Functions //===----------------------------------------------------------------------===// namespace { + struct OrderMap { DenseMap> IDs; unsigned size() const { return IDs.size(); } std::pair &operator[](const Value *V) { return IDs[V]; } + std::pair lookup(const Value *V) const { return IDs.lookup(V); } + void index(const Value *V) { // Explicitly sequence get-size and insert-value operations to avoid UB. unsigned ID = IDs.size() + 1; IDs[V].first = ID; } }; -} + +} // end anonymous namespace static void orderValue(const Value *V, OrderMap &OM) { if (OM.lookup(V).first) @@ -139,7 +180,7 @@ static void predictValueUseListOrderImpl(const Value *V, const Function *F, unsigned ID, const OrderMap &OM, UseListOrderStack &Stack) { // Predict use-list order for this one. - typedef std::pair Entry; + using Entry = std::pair; SmallVector List; for (const Use &U : V->uses()) // Check if this user will be serialized. @@ -421,13 +462,10 @@ static void PrintLLVMName(raw_ostream &OS, const Value *V) { isa(V) ? GlobalPrefix : LocalPrefix); } - namespace { -class TypePrinting { - TypePrinting(const TypePrinting &) = delete; - void operator=(const TypePrinting&) = delete; -public: +class TypePrinting { +public: /// NamedTypes - The named types that are used by the current module. TypeFinder NamedTypes; @@ -435,6 +473,8 @@ class TypePrinting { DenseMap NumberedTypes; TypePrinting() = default; + TypePrinting(const TypePrinting &) = delete; + TypePrinting &operator=(const TypePrinting &) = delete; void incorporateTypes(const Module &M); @@ -442,7 +482,8 @@ class TypePrinting { void printStructBody(StructType *Ty, raw_ostream &OS); }; -} // namespace + +} // end anonymous namespace void TypePrinting::incorporateTypes(const Module &M) { NamedTypes.run(M, false); @@ -574,6 +615,7 @@ void TypePrinting::printStructBody(StructType *STy, raw_ostream &OS) { } namespace llvm { + //===----------------------------------------------------------------------===// // SlotTracker Class: Enumerate slot numbers for unnamed values //===----------------------------------------------------------------------===// @@ -582,32 +624,33 @@ namespace llvm { class SlotTracker { public: /// ValueMap - A mapping of Values to slot numbers. - typedef DenseMap ValueMap; + using ValueMap = DenseMap; private: /// TheModule - The module for which we are holding slot numbers. const Module* TheModule; /// TheFunction - The function for which we are holding slot numbers. - const Function* TheFunction; - bool FunctionProcessed; + const Function* TheFunction = nullptr; + bool FunctionProcessed = false; bool ShouldInitializeAllMetadata; /// mMap - The slot map for the module level data. ValueMap mMap; - unsigned mNext; + unsigned mNext = 0; /// fMap - The slot map for the function level data. ValueMap fMap; - unsigned fNext; + unsigned fNext = 0; /// mdnMap - Map for MDNodes. DenseMap mdnMap; - unsigned mdnNext; + unsigned mdnNext = 0; /// asMap - The slot map for attribute sets. DenseMap asMap; - unsigned asNext; + unsigned asNext = 0; + public: /// Construct from a module. /// @@ -616,6 +659,7 @@ class SlotTracker { /// within a function (even if no functions have been initialized). explicit SlotTracker(const Module *M, bool ShouldInitializeAllMetadata = false); + /// Construct from a function, starting out in incorp state. /// /// If \c ShouldInitializeAllMetadata, initializes all metadata in all @@ -624,6 +668,9 @@ class SlotTracker { explicit SlotTracker(const Function *F, bool ShouldInitializeAllMetadata = false); + SlotTracker(const SlotTracker &) = delete; + SlotTracker &operator=(const SlotTracker &) = delete; + /// Return the slot number of the specified value in it's type /// plane. If something is not in the SlotTracker, return -1. int getLocalSlot(const Value *V); @@ -646,14 +693,16 @@ class SlotTracker { void purgeFunction(); /// MDNode map iterators. - typedef DenseMap::iterator mdn_iterator; + using mdn_iterator = DenseMap::iterator; + mdn_iterator mdn_begin() { return mdnMap.begin(); } mdn_iterator mdn_end() { return mdnMap.end(); } unsigned mdn_size() const { return mdnMap.size(); } bool mdn_empty() const { return mdnMap.empty(); } /// AttributeSet map iterators. - typedef DenseMap::iterator as_iterator; + using as_iterator = DenseMap::iterator; + as_iterator as_begin() { return asMap.begin(); } as_iterator as_end() { return asMap.end(); } unsigned as_size() const { return asMap.size(); } @@ -691,11 +740,9 @@ class SlotTracker { /// Add all of the metadata from an instruction. void processInstructionMetadata(const Instruction &I); - - SlotTracker(const SlotTracker &) = delete; - void operator=(const SlotTracker &) = delete; }; -} // namespace llvm + +} // end namespace llvm ModuleSlotTracker::ModuleSlotTracker(SlotTracker &Machine, const Module *M, const Function *F) @@ -706,7 +753,7 @@ ModuleSlotTracker::ModuleSlotTracker(const Module *M, : ShouldCreateStorage(M), ShouldInitializeAllMetadata(ShouldInitializeAllMetadata), M(M) {} -ModuleSlotTracker::~ModuleSlotTracker() {} +ModuleSlotTracker::~ModuleSlotTracker() = default; SlotTracker *ModuleSlotTracker::getMachine() { if (!ShouldCreateStorage) @@ -773,17 +820,13 @@ static SlotTracker *createSlotTracker(const Value *V) { // Module level constructor. Causes the contents of the Module (sans functions) // to be added to the slot table. SlotTracker::SlotTracker(const Module *M, bool ShouldInitializeAllMetadata) - : TheModule(M), TheFunction(nullptr), FunctionProcessed(false), - ShouldInitializeAllMetadata(ShouldInitializeAllMetadata), mNext(0), - fNext(0), mdnNext(0), asNext(0) {} + : TheModule(M), ShouldInitializeAllMetadata(ShouldInitializeAllMetadata) {} // Function level constructor. Causes the contents of the Module and the one // function provided to be added to the slot table. SlotTracker::SlotTracker(const Function *F, bool ShouldInitializeAllMetadata) : TheModule(F ? F->getParent() : nullptr), TheFunction(F), - FunctionProcessed(false), - ShouldInitializeAllMetadata(ShouldInitializeAllMetadata), mNext(0), - fNext(0), mdnNext(0), asNext(0) {} + ShouldInitializeAllMetadata(ShouldInitializeAllMetadata) {} inline void SlotTracker::initialize() { if (TheModule) { @@ -949,7 +992,6 @@ int SlotTracker::getMetadataSlot(const MDNode *N) { return MI == mdnMap.end() ? -1 : (int)MI->second; } - /// getLocalSlot - Get the slot number for a value that is local to a function. int SlotTracker::getLocalSlot(const Value *V) { assert(!isa(V) && "Can't get a constant or global slot with this!"); @@ -1248,7 +1290,6 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV, return; } - if (const ConstantStruct *CS = dyn_cast(CV)) { if (CS->getType()->isPacked()) Out << '<'; @@ -1381,11 +1422,14 @@ static void writeMDTuple(raw_ostream &Out, const MDTuple *Node, } namespace { + struct FieldSeparator { - bool Skip; + bool Skip = true; const char *Sep; - FieldSeparator(const char *Sep = ", ") : Skip(true), Sep(Sep) {} + + FieldSeparator(const char *Sep = ", ") : Sep(Sep) {} }; + raw_ostream &operator<<(raw_ostream &OS, FieldSeparator &FS) { if (FS.Skip) { FS.Skip = false; @@ -1393,19 +1437,20 @@ raw_ostream &operator<<(raw_ostream &OS, FieldSeparator &FS) { } return OS << FS.Sep; } + struct MDFieldPrinter { raw_ostream &Out; FieldSeparator FS; - TypePrinting *TypePrinter; - SlotTracker *Machine; - const Module *Context; + TypePrinting *TypePrinter = nullptr; + SlotTracker *Machine = nullptr; + const Module *Context = nullptr; - explicit MDFieldPrinter(raw_ostream &Out) - : Out(Out), TypePrinter(nullptr), Machine(nullptr), Context(nullptr) {} + explicit MDFieldPrinter(raw_ostream &Out) : Out(Out) {} MDFieldPrinter(raw_ostream &Out, TypePrinting *TypePrinter, SlotTracker *Machine, const Module *Context) : Out(Out), TypePrinter(TypePrinter), Machine(Machine), Context(Context) { } + void printTag(const DINode *N); void printMacinfoType(const DIMacroNode *N); void printChecksumKind(const DIFile *N); @@ -1422,7 +1467,8 @@ struct MDFieldPrinter { bool ShouldSkipZero = true); void printEmissionKind(StringRef Name, DICompileUnit::DebugEmissionKind EK); }; -} // end namespace + +} // end anonymous namespace void MDFieldPrinter::printTag(const DINode *N) { Out << FS << "tag: "; @@ -1518,7 +1564,6 @@ void MDFieldPrinter::printEmissionKind(StringRef Name, Out << FS << Name << ": " << DICompileUnit::EmissionKindString(EK); } - template void MDFieldPrinter::printDwarfEnum(StringRef Name, IntTy Value, Stringifier toString, bool ShouldSkipZero) { @@ -1923,7 +1968,6 @@ static void writeDIImportedEntity(raw_ostream &Out, const DIImportedEntity *N, Out << ")"; } - static void WriteMDNodeBodyInternal(raw_ostream &Out, const MDNode *Node, TypePrinting *TypePrinter, SlotTracker *Machine, @@ -2062,6 +2106,7 @@ static void WriteAsOperandInternal(raw_ostream &Out, const Metadata *MD, } namespace { + class AssemblyWriter { formatted_raw_ostream &Out; const Module *TheModule; @@ -2125,7 +2170,8 @@ class AssemblyWriter { // intrinsic indicating base and derived pointer names. void printGCRelocateComment(const GCRelocateInst &Relocate); }; -} // namespace + +} // end anonymous namespace AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac, const Module *M, AssemblyAnnotationWriter *AAW, @@ -2594,7 +2640,6 @@ void AssemblyWriter::printTypeIdentities() { } /// printFunction - Print all aspects of a function. -/// void AssemblyWriter::printFunction(const Function *F) { // Print out the return type and name. Out << '\n'; @@ -2730,7 +2775,6 @@ void AssemblyWriter::printFunction(const Function *F) { /// printArgument - This member is called for every argument that is passed into /// the function. Simply print it out -/// void AssemblyWriter::printArgument(const Argument *Arg, AttributeSet Attrs) { // Output type... TypePrinter.print(Arg->getType(), Out); @@ -2747,7 +2791,6 @@ void AssemblyWriter::printArgument(const Argument *Arg, AttributeSet Attrs) { } /// printBasicBlock - This member is called for each basic block in a method. -/// void AssemblyWriter::printBasicBlock(const BasicBlock *BB) { if (BB->hasName()) { // Print out the label if it exists... Out << "\n"; @@ -2813,7 +2856,6 @@ void AssemblyWriter::printGCRelocateComment(const GCRelocateInst &Relocate) { /// printInfoComment - Print a little comment after the instruction indicating /// which slot it occupies. -/// void AssemblyWriter::printInfoComment(const Value &V) { if (const auto *Relocate = dyn_cast(&V)) printGCRelocateComment(*Relocate); @@ -3046,7 +3088,6 @@ void AssemblyWriter::printInstruction(const Instruction &I) { Out << " #" << Machine.getAttributeGroupSlot(PAL.getFnAttributes()); writeOperandBundles(CI); - } else if (const InvokeInst *II = dyn_cast(&I)) { Operand = II->getCalledValue(); FunctionType *FTy = II->getFunctionType(); @@ -3087,7 +3128,6 @@ void AssemblyWriter::printInstruction(const Instruction &I) { writeOperand(II->getNormalDest(), true); Out << " unwind "; writeOperand(II->getUnwindDest(), true); - } else if (const AllocaInst *AI = dyn_cast(&I)) { Out << ' '; if (AI->isUsedWithInAlloca()) @@ -3113,7 +3153,6 @@ void AssemblyWriter::printInstruction(const Instruction &I) { if (AddrSpace != 0) { Out << ", addrspace(" << AddrSpace << ')'; } - } else if (isa(I)) { if (Operand) { Out << ' '; diff --git a/contrib/llvm/lib/IR/AttributeImpl.h b/contrib/llvm/lib/IR/AttributeImpl.h index 4ed7b021883d..9c7b61f67923 100644 --- a/contrib/llvm/lib/IR/AttributeImpl.h +++ b/contrib/llvm/lib/IR/AttributeImpl.h @@ -100,6 +100,7 @@ class AttributeImpl : public FoldingSetNode { class EnumAttributeImpl : public AttributeImpl { virtual void anchor(); + Attribute::AttrKind Kind; protected: @@ -133,6 +134,7 @@ class IntAttributeImpl : public EnumAttributeImpl { class StringAttributeImpl : public AttributeImpl { virtual void anchor(); + std::string Kind; std::string Val; @@ -243,7 +245,8 @@ class AttributeListImpl final return AvailableFunctionAttrs & ((uint64_t)1) << Kind; } - typedef const AttributeSet *iterator; + using iterator = const AttributeSet *; + iterator begin() const { return getTrailingObjects(); } iterator end() const { return begin() + NumAttrSets; } diff --git a/contrib/llvm/lib/IR/Attributes.cpp b/contrib/llvm/lib/IR/Attributes.cpp index a518f7b5c81a..8f2e641d64b9 100644 --- a/contrib/llvm/lib/IR/Attributes.cpp +++ b/contrib/llvm/lib/IR/Attributes.cpp @@ -1638,6 +1638,39 @@ static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) { Caller.addFnAttr(Attribute::StackProtect); } +/// \brief If the inlined function required stack probes, then ensure that +/// the calling function has those too. +static void adjustCallerStackProbes(Function &Caller, const Function &Callee) { + if (!Caller.hasFnAttribute("probe-stack") && + Callee.hasFnAttribute("probe-stack")) { + Caller.addFnAttr(Callee.getFnAttribute("probe-stack")); + } +} + +/// \brief If the inlined function defines the size of guard region +/// on the stack, then ensure that the calling function defines a guard region +/// that is no larger. +static void +adjustCallerStackProbeSize(Function &Caller, const Function &Callee) { + if (Callee.hasFnAttribute("stack-probe-size")) { + uint64_t CalleeStackProbeSize; + Callee.getFnAttribute("stack-probe-size") + .getValueAsString() + .getAsInteger(0, CalleeStackProbeSize); + if (Caller.hasFnAttribute("stack-probe-size")) { + uint64_t CallerStackProbeSize; + Caller.getFnAttribute("stack-probe-size") + .getValueAsString() + .getAsInteger(0, CallerStackProbeSize); + if (CallerStackProbeSize > CalleeStackProbeSize) { + Caller.addFnAttr(Callee.getFnAttribute("stack-probe-size")); + } + } else { + Caller.addFnAttr(Callee.getFnAttribute("stack-probe-size")); + } + } +} + #define GET_ATTR_COMPAT_FUNC #include "AttributesCompatFunc.inc" diff --git a/contrib/llvm/lib/IR/AutoUpgrade.cpp b/contrib/llvm/lib/IR/AutoUpgrade.cpp index 06934b365a11..6a4b8032ffd5 100644 --- a/contrib/llvm/lib/IR/AutoUpgrade.cpp +++ b/contrib/llvm/lib/IR/AutoUpgrade.cpp @@ -142,6 +142,11 @@ static bool ShouldUpgradeX86Intrinsic(Function *F, StringRef Name) { Name.startswith("avx512.mask.packssdw.") || // Added in 5.0 Name.startswith("avx512.mask.packuswb.") || // Added in 5.0 Name.startswith("avx512.mask.packusdw.") || // Added in 5.0 + Name.startswith("avx512.mask.cmp.b") || // Added in 5.0 + Name.startswith("avx512.mask.cmp.d") || // Added in 5.0 + Name.startswith("avx512.mask.cmp.q") || // Added in 5.0 + Name.startswith("avx512.mask.cmp.w") || // Added in 5.0 + Name.startswith("avx512.mask.ucmp.") || // Added in 5.0 Name == "avx512.mask.add.pd.128" || // Added in 4.0 Name == "avx512.mask.add.pd.256" || // Added in 4.0 Name == "avx512.mask.add.ps.128" || // Added in 4.0 @@ -783,12 +788,30 @@ static Value *upgradeIntMinMax(IRBuilder<> &Builder, CallInst &CI, } static Value *upgradeMaskedCompare(IRBuilder<> &Builder, CallInst &CI, - ICmpInst::Predicate Pred) { + unsigned CC, bool Signed) { Value *Op0 = CI.getArgOperand(0); unsigned NumElts = Op0->getType()->getVectorNumElements(); - Value *Cmp = Builder.CreateICmp(Pred, Op0, CI.getArgOperand(1)); - Value *Mask = CI.getArgOperand(2); + Value *Cmp; + if (CC == 3) { + Cmp = Constant::getNullValue(llvm::VectorType::get(Builder.getInt1Ty(), NumElts)); + } else if (CC == 7) { + Cmp = Constant::getAllOnesValue(llvm::VectorType::get(Builder.getInt1Ty(), NumElts)); + } else { + ICmpInst::Predicate Pred; + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case 0: Pred = ICmpInst::ICMP_EQ; break; + case 1: Pred = Signed ? ICmpInst::ICMP_SLT : ICmpInst::ICMP_ULT; break; + case 2: Pred = Signed ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; break; + case 4: Pred = ICmpInst::ICMP_NE; break; + case 5: Pred = Signed ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE; break; + case 6: Pred = Signed ? ICmpInst::ICMP_SGT : ICmpInst::ICMP_UGT; break; + } + Cmp = Builder.CreateICmp(Pred, Op0, CI.getArgOperand(1)); + } + + Value *Mask = CI.getArgOperand(CI.getNumArgOperands() - 1); const auto *C = dyn_cast(Mask); if (!C || !C->isAllOnesValue()) Cmp = Builder.CreateAnd(Cmp, getX86MaskVec(Builder, Mask, NumElts)); @@ -1007,9 +1030,13 @@ void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { } else if (IsX86 && Name.startswith("avx512.mask.pcmp")) { // "avx512.mask.pcmpeq." or "avx512.mask.pcmpgt." bool CmpEq = Name[16] == 'e'; - Rep = upgradeMaskedCompare(Builder, *CI, - CmpEq ? ICmpInst::ICMP_EQ - : ICmpInst::ICMP_SGT); + Rep = upgradeMaskedCompare(Builder, *CI, CmpEq ? 0 : 6, true); + } else if (IsX86 && Name.startswith("avx512.mask.cmp")) { + unsigned Imm = cast(CI->getArgOperand(2))->getZExtValue(); + Rep = upgradeMaskedCompare(Builder, *CI, Imm, true); + } else if (IsX86 && Name.startswith("avx512.mask.ucmp")) { + unsigned Imm = cast(CI->getArgOperand(2))->getZExtValue(); + Rep = upgradeMaskedCompare(Builder, *CI, Imm, false); } else if (IsX86 && (Name == "sse41.pmaxsb" || Name == "sse2.pmaxs.w" || Name == "sse41.pmaxsd" || diff --git a/contrib/llvm/lib/IR/BasicBlock.cpp b/contrib/llvm/lib/IR/BasicBlock.cpp index 1f8659d4e2ca..2b780adf6c69 100644 --- a/contrib/llvm/lib/IR/BasicBlock.cpp +++ b/contrib/llvm/lib/IR/BasicBlock.cpp @@ -355,6 +355,19 @@ bool BasicBlock::canSplitPredecessors() const { return true; } +bool BasicBlock::isLegalToHoistInto() const { + auto *Term = getTerminator(); + // No terminator means the block is under construction. + if (!Term) + return true; + + // If the block has no successors, there can be no instructions to hoist. + assert(Term->getNumSuccessors() > 0); + + // Instructions should not be hoisted across exception handling boundaries. + return !Term->isExceptional(); +} + /// This splits a basic block into two at the specified /// instruction. Note that all instructions BEFORE the specified iterator stay /// as part of the original basic block, an unconditional branch is added to diff --git a/contrib/llvm/lib/IR/ConstantRange.cpp b/contrib/llvm/lib/IR/ConstantRange.cpp index 21d1996ef851..4bd17257016d 100644 --- a/contrib/llvm/lib/IR/ConstantRange.cpp +++ b/contrib/llvm/lib/IR/ConstantRange.cpp @@ -1,4 +1,4 @@ -//===-- ConstantRange.cpp - ConstantRange implementation ------------------===// +//===- ConstantRange.cpp - ConstantRange implementation -------------------===// // // The LLVM Compiler Infrastructure // @@ -21,12 +21,21 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/APInt.h" #include "llvm/IR/ConstantRange.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" +#include "llvm/IR/Metadata.h" #include "llvm/IR/Operator.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include + using namespace llvm; ConstantRange::ConstantRange(uint32_t BitWidth, bool Full) @@ -170,7 +179,7 @@ ConstantRange ConstantRange::makeGuaranteedNoWrapRegion(Instruction::BinaryOps BinOp, const ConstantRange &Other, unsigned NoWrapKind) { - typedef OverflowingBinaryOperator OBO; + using OBO = OverflowingBinaryOperator; // Computes the intersection of CR0 and CR1. It is different from // intersectWith in that the ConstantRange returned will only contain elements @@ -284,27 +293,14 @@ APInt ConstantRange::getUnsignedMin() const { } APInt ConstantRange::getSignedMax() const { - if (!isWrappedSet()) { - APInt UpperMinusOne = getUpper() - 1; - if (getLower().sle(UpperMinusOne)) - return UpperMinusOne; - return APInt::getSignedMaxValue(getBitWidth()); - } - if (getLower().isNegative() == getUpper().isNegative()) + if (isFullSet() || Lower.sgt(Upper)) return APInt::getSignedMaxValue(getBitWidth()); return getUpper() - 1; } APInt ConstantRange::getSignedMin() const { - if (!isWrappedSet()) { - if (getLower().sle(getUpper() - 1)) - return getLower(); + if (isFullSet() || (Lower.sgt(Upper) && !getUpper().isMinSignedValue())) return APInt::getSignedMinValue(getBitWidth()); - } - if ((getUpper() - 1).slt(getLower())) { - if (!getUpper().isMinSignedValue()) - return APInt::getSignedMinValue(getBitWidth()); - } return getLower(); } diff --git a/contrib/llvm/lib/IR/Instructions.cpp b/contrib/llvm/lib/IR/Instructions.cpp index 023a0b178a14..a79b00be4ffe 100644 --- a/contrib/llvm/lib/IR/Instructions.cpp +++ b/contrib/llvm/lib/IR/Instructions.cpp @@ -1995,8 +1995,8 @@ BinaryOperator::BinaryOperator(BinaryOps iType, Value *S1, Value *S2, InsertBefore) { Op<0>() = S1; Op<1>() = S2; - init(iType); setName(Name); + AssertOK(); } BinaryOperator::BinaryOperator(BinaryOps iType, Value *S1, Value *S2, @@ -2008,17 +2008,17 @@ BinaryOperator::BinaryOperator(BinaryOps iType, Value *S1, Value *S2, InsertAtEnd) { Op<0>() = S1; Op<1>() = S2; - init(iType); setName(Name); + AssertOK(); } -void BinaryOperator::init(BinaryOps iType) { +void BinaryOperator::AssertOK() { Value *LHS = getOperand(0), *RHS = getOperand(1); (void)LHS; (void)RHS; // Silence warnings. assert(LHS->getType() == RHS->getType() && "Binary operator operand types must match!"); #ifndef NDEBUG - switch (iType) { + switch (getOpcode()) { case Add: case Sub: case Mul: assert(getType() == LHS->getType() && @@ -2038,8 +2038,7 @@ void BinaryOperator::init(BinaryOps iType) { case SDiv: assert(getType() == LHS->getType() && "Arithmetic operation should return same type as operands!"); - assert((getType()->isIntegerTy() || (getType()->isVectorTy() && - cast(getType())->getElementType()->isIntegerTy())) && + assert(getType()->isIntOrIntVectorTy() && "Incorrect operand type (not integer) for S/UDIV"); break; case FDiv: @@ -2052,8 +2051,7 @@ void BinaryOperator::init(BinaryOps iType) { case SRem: assert(getType() == LHS->getType() && "Arithmetic operation should return same type as operands!"); - assert((getType()->isIntegerTy() || (getType()->isVectorTy() && - cast(getType())->getElementType()->isIntegerTy())) && + assert(getType()->isIntOrIntVectorTy() && "Incorrect operand type (not integer) for S/UREM"); break; case FRem: @@ -2067,22 +2065,17 @@ void BinaryOperator::init(BinaryOps iType) { case AShr: assert(getType() == LHS->getType() && "Shift operation should return same type as operands!"); - assert((getType()->isIntegerTy() || - (getType()->isVectorTy() && - cast(getType())->getElementType()->isIntegerTy())) && + assert(getType()->isIntOrIntVectorTy() && "Tried to create a shift operation on a non-integral type!"); break; case And: case Or: case Xor: assert(getType() == LHS->getType() && "Logical operation should return same type as operands!"); - assert((getType()->isIntegerTy() || - (getType()->isVectorTy() && - cast(getType())->getElementType()->isIntegerTy())) && + assert(getType()->isIntOrIntVectorTy() && "Tried to create a logical operation on a non-integral type!"); break; - default: - break; + default: llvm_unreachable("Invalid opcode provided"); } #endif } diff --git a/contrib/llvm/lib/IR/LLVMContextImpl.cpp b/contrib/llvm/lib/IR/LLVMContextImpl.cpp index 4a30d28c3913..c19e1be44fdc 100644 --- a/contrib/llvm/lib/IR/LLVMContextImpl.cpp +++ b/contrib/llvm/lib/IR/LLVMContextImpl.cpp @@ -1,4 +1,4 @@ -//===-- LLVMContextImpl.cpp - Implement LLVMContextImpl -------------------===// +//===- LLVMContextImpl.cpp - Implement LLVMContextImpl --------------------===// // // The LLVM Compiler Infrastructure // @@ -12,18 +12,17 @@ //===----------------------------------------------------------------------===// #include "LLVMContextImpl.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/IR/Attributes.h" -#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Module.h" #include "llvm/IR/OptBisect.h" +#include "llvm/IR/Type.h" #include "llvm/Support/ManagedStatic.h" -#include +#include +#include + using namespace llvm; LLVMContextImpl::LLVMContextImpl(LLVMContext &C) - : TheTrueVal(nullptr), TheFalseVal(nullptr), - VoidTy(C, Type::VoidTyID), + : VoidTy(C, Type::VoidTyID), LabelTy(C, Type::LabelTyID), HalfTy(C, Type::HalfTyID), FloatTy(C, Type::FloatTyID), @@ -39,17 +38,7 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C) Int16Ty(C, 16), Int32Ty(C, 32), Int64Ty(C, 64), - Int128Ty(C, 128) { - InlineAsmDiagHandler = nullptr; - InlineAsmDiagContext = nullptr; - DiagnosticHandler = nullptr; - DiagnosticContext = nullptr; - RespectDiagnosticFilters = false; - DiagnosticHotnessRequested = false; - YieldCallback = nullptr; - YieldOpaqueHandle = nullptr; - NamedStructTypesUniqueID = 0; -} + Int128Ty(C, 128) {} LLVMContextImpl::~LLVMContextImpl() { // NOTE: We need to delete the contents of OwnedModules, but Module's dtor @@ -156,7 +145,6 @@ void LLVMContextImpl::dropTriviallyDeadConstantArrays() { C->destroyConstant(); } } - } while (Changed); } @@ -165,6 +153,7 @@ void Module::dropTriviallyDeadConstantArrays() { } namespace llvm { + /// \brief Make MDOperand transparent for hashing. /// /// This overload of an implementation detail of the hashing library makes @@ -179,7 +168,8 @@ namespace llvm { /// does not cause MDOperand to be transparent. In particular, a bare pointer /// doesn't get hashed before it's combined, whereas \a MDOperand would. static const Metadata *get_hashable_data(const MDOperand &X) { return X.get(); } -} + +} // end namespace llvm unsigned MDNodeOpsKey::calculateHash(MDNode *N, unsigned Offset) { unsigned Hash = hash_combine_range(N->op_begin() + Offset, N->op_end()); diff --git a/contrib/llvm/lib/IR/LLVMContextImpl.h b/contrib/llvm/lib/IR/LLVMContextImpl.h index 4ba974409a4f..4147f71ad9d2 100644 --- a/contrib/llvm/lib/IR/LLVMContextImpl.h +++ b/contrib/llvm/lib/IR/LLVMContextImpl.h @@ -1,4 +1,4 @@ -//===-- LLVMContextImpl.h - The LLVMContextImpl opaque class ----*- C++ -*-===// +//===- LLVMContextImpl.h - The LLVMContextImpl opaque class -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -21,11 +21,16 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/IR/Constants.h" @@ -33,21 +38,26 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" -#include "llvm/IR/ValueHandle.h" +#include "llvm/IR/TrackingMDRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/YAMLTraits.h" +#include +#include +#include +#include +#include +#include +#include #include namespace llvm { -class ConstantInt; class ConstantFP; -class DiagnosticInfoOptimizationRemark; -class DiagnosticInfoOptimizationRemarkMissed; -class DiagnosticInfoOptimizationRemarkAnalysis; -class GCStrategy; -class LLVMContext; +class ConstantInt; class Type; class Value; +class ValueHandleBase; struct DenseMapAPIntKeyInfo { static inline APInt getEmptyKey() { @@ -55,14 +65,17 @@ struct DenseMapAPIntKeyInfo { V.U.VAL = 0; return V; } + static inline APInt getTombstoneKey() { APInt V(nullptr, 0); V.U.VAL = 1; return V; } + static unsigned getHashValue(const APInt &Key) { return static_cast(hash_value(Key)); } + static bool isEqual(const APInt &LHS, const APInt &RHS) { return LHS.getBitWidth() == RHS.getBitWidth() && LHS == RHS; } @@ -71,9 +84,11 @@ struct DenseMapAPIntKeyInfo { struct DenseMapAPFloatKeyInfo { static inline APFloat getEmptyKey() { return APFloat(APFloat::Bogus(), 1); } static inline APFloat getTombstoneKey() { return APFloat(APFloat::Bogus(), 2); } + static unsigned getHashValue(const APFloat &Key) { return static_cast(hash_value(Key)); } + static bool isEqual(const APFloat &LHS, const APFloat &RHS) { return LHS.bitwiseIsEqual(RHS); } @@ -83,10 +98,13 @@ struct AnonStructTypeKeyInfo { struct KeyTy { ArrayRef ETypes; bool isPacked; + KeyTy(const ArrayRef& E, bool P) : ETypes(E), isPacked(P) {} + KeyTy(const StructType *ST) : ETypes(ST->elements()), isPacked(ST->isPacked()) {} + bool operator==(const KeyTy& that) const { if (isPacked != that.isPacked) return false; @@ -98,25 +116,31 @@ struct AnonStructTypeKeyInfo { return !this->operator==(that); } }; + static inline StructType* getEmptyKey() { return DenseMapInfo::getEmptyKey(); } + static inline StructType* getTombstoneKey() { return DenseMapInfo::getTombstoneKey(); } + static unsigned getHashValue(const KeyTy& Key) { return hash_combine(hash_combine_range(Key.ETypes.begin(), Key.ETypes.end()), Key.isPacked); } + static unsigned getHashValue(const StructType *ST) { return getHashValue(KeyTy(ST)); } + static bool isEqual(const KeyTy& LHS, const StructType *RHS) { if (RHS == getEmptyKey() || RHS == getTombstoneKey()) return false; return LHS == KeyTy(RHS); } + static bool isEqual(const StructType *LHS, const StructType *RHS) { return LHS == RHS; } @@ -127,11 +151,13 @@ struct FunctionTypeKeyInfo { const Type *ReturnType; ArrayRef Params; bool isVarArg; + KeyTy(const Type* R, const ArrayRef& P, bool V) : ReturnType(R), Params(P), isVarArg(V) {} KeyTy(const FunctionType *FT) : ReturnType(FT->getReturnType()), Params(FT->params()), isVarArg(FT->isVarArg()) {} + bool operator==(const KeyTy& that) const { if (ReturnType != that.ReturnType) return false; @@ -145,26 +171,32 @@ struct FunctionTypeKeyInfo { return !this->operator==(that); } }; + static inline FunctionType* getEmptyKey() { return DenseMapInfo::getEmptyKey(); } + static inline FunctionType* getTombstoneKey() { return DenseMapInfo::getTombstoneKey(); } + static unsigned getHashValue(const KeyTy& Key) { return hash_combine(Key.ReturnType, hash_combine_range(Key.Params.begin(), Key.Params.end()), Key.isVarArg); } + static unsigned getHashValue(const FunctionType *FT) { return getHashValue(KeyTy(FT)); } + static bool isEqual(const KeyTy& LHS, const FunctionType *RHS) { if (RHS == getEmptyKey() || RHS == getTombstoneKey()) return false; return LHS == KeyTy(RHS); } + static bool isEqual(const FunctionType *LHS, const FunctionType *RHS) { return LHS == RHS; } @@ -174,7 +206,6 @@ struct FunctionTypeKeyInfo { class MDNodeOpsKey { ArrayRef RawOps; ArrayRef Ops; - unsigned Hash; protected: @@ -212,14 +243,15 @@ class MDNodeOpsKey { }; template struct MDNodeKeyImpl; -template struct MDNodeInfo; /// Configuration point for MDNodeInfo::isEqual(). template struct MDNodeSubsetEqualImpl { - typedef MDNodeKeyImpl KeyTy; + using KeyTy = MDNodeKeyImpl; + static bool isSubsetEqual(const KeyTy &LHS, const NodeTy *RHS) { return false; } + static bool isSubsetEqual(const NodeTy *LHS, const NodeTy *RHS) { return false; } @@ -252,7 +284,6 @@ template <> struct MDNodeKeyImpl { MDNodeKeyImpl(unsigned Line, unsigned Column, Metadata *Scope, Metadata *InlinedAt) : Line(Line), Column(Column), Scope(Scope), InlinedAt(InlinedAt) {} - MDNodeKeyImpl(const DILocation *L) : Line(L->getLine()), Column(L->getColumn()), Scope(L->getRawScope()), InlinedAt(L->getRawInlinedAt()) {} @@ -261,6 +292,7 @@ template <> struct MDNodeKeyImpl { return Line == RHS->getLine() && Column == RHS->getColumn() && Scope == RHS->getRawScope() && InlinedAt == RHS->getRawInlinedAt(); } + unsigned getHashValue() const { return hash_combine(Line, Column, Scope, InlinedAt); } @@ -270,6 +302,7 @@ template <> struct MDNodeKeyImpl { template <> struct MDNodeKeyImpl : MDNodeOpsKey { unsigned Tag; MDString *Header; + MDNodeKeyImpl(unsigned Tag, MDString *Header, ArrayRef DwarfOps) : MDNodeOpsKey(DwarfOps), Tag(Tag), Header(Header) {} MDNodeKeyImpl(const GenericDINode *N) @@ -299,6 +332,7 @@ template <> struct MDNodeKeyImpl { bool isKeyOf(const DISubrange *RHS) const { return Count == RHS->getCount() && LowerBound == RHS->getLowerBound(); } + unsigned getHashValue() const { return hash_combine(Count, LowerBound); } }; @@ -313,6 +347,7 @@ template <> struct MDNodeKeyImpl { bool isKeyOf(const DIEnumerator *RHS) const { return Value == RHS->getValue() && Name == RHS->getRawName(); } + unsigned getHashValue() const { return hash_combine(Value, Name); } }; @@ -337,6 +372,7 @@ template <> struct MDNodeKeyImpl { AlignInBits == RHS->getAlignInBits() && Encoding == RHS->getEncoding(); } + unsigned getHashValue() const { return hash_combine(Tag, Name, SizeInBits, AlignInBits, Encoding); } @@ -384,6 +420,7 @@ template <> struct MDNodeKeyImpl { Flags == RHS->getFlags() && ExtraData == RHS->getRawExtraData(); } + unsigned getHashValue() const { // If this is a member inside an ODR type, only hash the type and the name. // Otherwise the hash will be stronger than @@ -402,10 +439,12 @@ template <> struct MDNodeKeyImpl { }; template <> struct MDNodeSubsetEqualImpl { - typedef MDNodeKeyImpl KeyTy; + using KeyTy = MDNodeKeyImpl; + static bool isSubsetEqual(const KeyTy &LHS, const DIDerivedType *RHS) { return isODRMember(LHS.Tag, LHS.Scope, LHS.Name, RHS); } + static bool isSubsetEqual(const DIDerivedType *LHS, const DIDerivedType *RHS) { return isODRMember(LHS->getTag(), LHS->getRawScope(), LHS->getRawName(), RHS); @@ -480,6 +519,7 @@ template <> struct MDNodeKeyImpl { TemplateParams == RHS->getRawTemplateParams() && Identifier == RHS->getRawIdentifier(); } + unsigned getHashValue() const { // Intentionally computes the hash on a subset of the operands for // performance reason. The subset has to be significant enough to avoid @@ -504,6 +544,7 @@ template <> struct MDNodeKeyImpl { return Flags == RHS->getFlags() && CC == RHS->getCC() && TypeArray == RHS->getRawTypeArray(); } + unsigned getHashValue() const { return hash_combine(Flags, CC, TypeArray); } }; @@ -527,6 +568,7 @@ template <> struct MDNodeKeyImpl { CSKind == RHS->getChecksumKind() && Checksum == RHS->getRawChecksum(); } + unsigned getHashValue() const { return hash_combine(Filename, Directory, CSKind, Checksum); } @@ -601,6 +643,7 @@ template <> struct MDNodeKeyImpl { Variables == RHS->getRawVariables() && ThrownTypes == RHS->getRawThrownTypes(); } + unsigned getHashValue() const { // If this is a declaration inside an ODR type, only hash the type and the // name. Otherwise the hash will be stronger than @@ -619,11 +662,13 @@ template <> struct MDNodeKeyImpl { }; template <> struct MDNodeSubsetEqualImpl { - typedef MDNodeKeyImpl KeyTy; + using KeyTy = MDNodeKeyImpl; + static bool isSubsetEqual(const KeyTy &LHS, const DISubprogram *RHS) { return isDeclarationOfODRMember(LHS.IsDefinition, LHS.Scope, LHS.LinkageName, LHS.TemplateParams, RHS); } + static bool isSubsetEqual(const DISubprogram *LHS, const DISubprogram *RHS) { return isDeclarationOfODRMember(LHS->isDefinition(), LHS->getRawScope(), LHS->getRawLinkageName(), @@ -672,6 +717,7 @@ template <> struct MDNodeKeyImpl { return Scope == RHS->getRawScope() && File == RHS->getRawFile() && Line == RHS->getLine() && Column == RHS->getColumn(); } + unsigned getHashValue() const { return hash_combine(Scope, File, Line, Column); } @@ -692,6 +738,7 @@ template <> struct MDNodeKeyImpl { return Scope == RHS->getRawScope() && File == RHS->getRawFile() && Discriminator == RHS->getDiscriminator(); } + unsigned getHashValue() const { return hash_combine(Scope, File, Discriminator); } @@ -712,6 +759,7 @@ template <> struct MDNodeKeyImpl { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && ExportSymbols == RHS->getExportSymbols(); } + unsigned getHashValue() const { return hash_combine(Scope, Name); } @@ -723,6 +771,7 @@ template <> struct MDNodeKeyImpl { MDString *ConfigurationMacros; MDString *IncludePath; MDString *ISysRoot; + MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *ConfigurationMacros, MDString *IncludePath, MDString *ISysRoot) : Scope(Scope), Name(Name), ConfigurationMacros(ConfigurationMacros), @@ -738,6 +787,7 @@ template <> struct MDNodeKeyImpl { IncludePath == RHS->getRawIncludePath() && ISysRoot == RHS->getRawISysRoot(); } + unsigned getHashValue() const { return hash_combine(Scope, Name, ConfigurationMacros, IncludePath, ISysRoot); @@ -755,6 +805,7 @@ template <> struct MDNodeKeyImpl { bool isKeyOf(const DITemplateTypeParameter *RHS) const { return Name == RHS->getRawName() && Type == RHS->getRawType(); } + unsigned getHashValue() const { return hash_combine(Name, Type); } }; @@ -774,6 +825,7 @@ template <> struct MDNodeKeyImpl { return Tag == RHS->getTag() && Name == RHS->getRawName() && Type == RHS->getRawType() && Value == RHS->getValue(); } + unsigned getHashValue() const { return hash_combine(Tag, Name, Type, Value); } }; @@ -816,6 +868,7 @@ template <> struct MDNodeKeyImpl { RHS->getRawStaticDataMemberDeclaration() && AlignInBits == RHS->getAlignInBits(); } + unsigned getHashValue() const { // We do not use AlignInBits in hashing function here on purpose: // in most cases this param for local variable is zero (for function param @@ -856,6 +909,7 @@ template <> struct MDNodeKeyImpl { Type == RHS->getRawType() && Arg == RHS->getArg() && Flags == RHS->getFlags() && AlignInBits == RHS->getAlignInBits(); } + unsigned getHashValue() const { // We do not use AlignInBits in hashing function here on purpose: // in most cases this param for local variable is zero (for function param @@ -877,6 +931,7 @@ template <> struct MDNodeKeyImpl { bool isKeyOf(const DIExpression *RHS) const { return Elements == RHS->getElements(); } + unsigned getHashValue() const { return hash_combine_range(Elements.begin(), Elements.end()); } @@ -895,6 +950,7 @@ template <> struct MDNodeKeyImpl { return Variable == RHS->getRawVariable() && Expression == RHS->getRawExpression(); } + unsigned getHashValue() const { return hash_combine(Variable, Expression); } }; @@ -923,6 +979,7 @@ template <> struct MDNodeKeyImpl { SetterName == RHS->getRawSetterName() && Attributes == RHS->getAttributes() && Type == RHS->getRawType(); } + unsigned getHashValue() const { return hash_combine(Name, File, Line, GetterName, SetterName, Attributes, Type); @@ -948,6 +1005,7 @@ template <> struct MDNodeKeyImpl { Entity == RHS->getRawEntity() && Line == RHS->getLine() && Name == RHS->getRawName(); } + unsigned getHashValue() const { return hash_combine(Tag, Scope, Entity, Line, Name); } @@ -969,6 +1027,7 @@ template <> struct MDNodeKeyImpl { return MIType == RHS->getMacinfoType() && Line == RHS->getLine() && Name == RHS->getRawName() && Value == RHS->getRawValue(); } + unsigned getHashValue() const { return hash_combine(MIType, Line, Name, Value); } @@ -991,6 +1050,7 @@ template <> struct MDNodeKeyImpl { return MIType == RHS->getMacinfoType() && Line == RHS->getLine() && File == RHS->getRawFile() && Elements == RHS->getRawElements(); } + unsigned getHashValue() const { return hash_combine(MIType, Line, File, Elements); } @@ -998,23 +1058,29 @@ template <> struct MDNodeKeyImpl { /// \brief DenseMapInfo for MDNode subclasses. template struct MDNodeInfo { - typedef MDNodeKeyImpl KeyTy; - typedef MDNodeSubsetEqualImpl SubsetEqualTy; + using KeyTy = MDNodeKeyImpl; + using SubsetEqualTy = MDNodeSubsetEqualImpl; + static inline NodeTy *getEmptyKey() { return DenseMapInfo::getEmptyKey(); } + static inline NodeTy *getTombstoneKey() { return DenseMapInfo::getTombstoneKey(); } + static unsigned getHashValue(const KeyTy &Key) { return Key.getHashValue(); } + static unsigned getHashValue(const NodeTy *N) { return KeyTy(N).getHashValue(); } + static bool isEqual(const KeyTy &LHS, const NodeTy *RHS) { if (RHS == getEmptyKey() || RHS == getTombstoneKey()) return false; return SubsetEqualTy::isSubsetEqual(LHS, RHS) || LHS.isKeyOf(RHS); } + static bool isEqual(const NodeTy *LHS, const NodeTy *RHS) { if (LHS == RHS) return true; @@ -1024,7 +1090,7 @@ template struct MDNodeInfo { } }; -#define HANDLE_MDNODE_LEAF(CLASS) typedef MDNodeInfo CLASS##Info; +#define HANDLE_MDNODE_LEAF(CLASS) using CLASS##Info = MDNodeInfo; #include "llvm/IR/Metadata.def" /// \brief Map-like storage for metadata attachments. @@ -1097,24 +1163,24 @@ class LLVMContextImpl { /// will be automatically deleted if this context is deleted. SmallPtrSet OwnedModules; - LLVMContext::InlineAsmDiagHandlerTy InlineAsmDiagHandler; - void *InlineAsmDiagContext; + LLVMContext::InlineAsmDiagHandlerTy InlineAsmDiagHandler = nullptr; + void *InlineAsmDiagContext = nullptr; - LLVMContext::DiagnosticHandlerTy DiagnosticHandler; - void *DiagnosticContext; - bool RespectDiagnosticFilters; - bool DiagnosticHotnessRequested; + LLVMContext::DiagnosticHandlerTy DiagnosticHandler = nullptr; + void *DiagnosticContext = nullptr; + bool RespectDiagnosticFilters = false; + bool DiagnosticHotnessRequested = false; std::unique_ptr DiagnosticsOutputFile; - LLVMContext::YieldCallbackTy YieldCallback; - void *YieldOpaqueHandle; + LLVMContext::YieldCallbackTy YieldCallback = nullptr; + void *YieldOpaqueHandle = nullptr; - typedef DenseMap, DenseMapAPIntKeyInfo> - IntMapTy; + using IntMapTy = + DenseMap, DenseMapAPIntKeyInfo>; IntMapTy IntConstants; - typedef DenseMap, DenseMapAPFloatKeyInfo> - FPMapTy; + using FPMapTy = + DenseMap, DenseMapAPFloatKeyInfo>; FPMapTy FPConstants; FoldingSet AttrsSet; @@ -1142,13 +1208,13 @@ class LLVMContextImpl { DenseMap> CAZConstants; - typedef ConstantUniqueMap ArrayConstantsTy; + using ArrayConstantsTy = ConstantUniqueMap; ArrayConstantsTy ArrayConstants; - typedef ConstantUniqueMap StructConstantsTy; + using StructConstantsTy = ConstantUniqueMap; StructConstantsTy StructConstants; - typedef ConstantUniqueMap VectorConstantsTy; + using VectorConstantsTy = ConstantUniqueMap; VectorConstantsTy VectorConstants; DenseMap> CPNConstants; @@ -1163,8 +1229,8 @@ class LLVMContextImpl { ConstantUniqueMap InlineAsms; - ConstantInt *TheTrueVal; - ConstantInt *TheFalseVal; + ConstantInt *TheTrueVal = nullptr; + ConstantInt *TheFalseVal = nullptr; std::unique_ptr TheNoneToken; @@ -1172,7 +1238,6 @@ class LLVMContextImpl { Type VoidTy, LabelTy, HalfTy, FloatTy, DoubleTy, MetadataTy, TokenTy; Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy; IntegerType Int1Ty, Int8Ty, Int16Ty, Int32Ty, Int64Ty, Int128Ty; - /// TypeAllocator - All dynamically allocated types are allocated from this. /// They live forever until the context is torn down. @@ -1180,23 +1245,22 @@ class LLVMContextImpl { DenseMap IntegerTypes; - typedef DenseSet FunctionTypeSet; + using FunctionTypeSet = DenseSet; FunctionTypeSet FunctionTypes; - typedef DenseSet StructTypeSet; + using StructTypeSet = DenseSet; StructTypeSet AnonStructTypes; StringMap NamedStructTypes; - unsigned NamedStructTypesUniqueID; + unsigned NamedStructTypesUniqueID = 0; DenseMap, ArrayType*> ArrayTypes; DenseMap, VectorType*> VectorTypes; DenseMap PointerTypes; // Pointers in AddrSpace = 0 DenseMap, PointerType*> ASPointerTypes; - /// ValueHandles - This map keeps track of all of the value handles that are /// watching a Value*. The Value::HasValueHandle bit is used to know /// whether or not a value has an entry in this map. - typedef DenseMap ValueHandlesTy; + using ValueHandlesTy = DenseMap; ValueHandlesTy ValueHandles; /// CustomMDKindNames - Map to hold the metadata string to ID mapping. @@ -1254,6 +1318,6 @@ class LLVMContextImpl { OptBisect &getOptBisect(); }; -} +} // end namespace llvm -#endif +#endif // LLVM_LIB_IR_LLVMCONTEXTIMPL_H diff --git a/contrib/llvm/lib/IR/Metadata.cpp b/contrib/llvm/lib/IR/Metadata.cpp index 92e5798dcf21..ac02ff76c843 100644 --- a/contrib/llvm/lib/IR/Metadata.cpp +++ b/contrib/llvm/lib/IR/Metadata.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/Metadata.h" #include "LLVMContextImpl.h" #include "MetadataImpl.h" #include "SymbolTableListTraitsImpl.h" @@ -27,6 +26,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" #include "llvm/IR/Argument.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" @@ -39,6 +39,7 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/TrackingMDRef.h" #include "llvm/IR/Type.h" @@ -53,6 +54,7 @@ #include #include #include +#include #include #include @@ -233,7 +235,7 @@ void ReplaceableMetadataImpl::replaceAllUsesWith(Metadata *MD) { return; // Copy out uses since UseMap will get touched below. - typedef std::pair> UseTy; + using UseTy = std::pair>; SmallVector Uses(UseMap.begin(), UseMap.end()); std::sort(Uses.begin(), Uses.end(), [](const UseTy &L, const UseTy &R) { return L.second.second < R.second.second; @@ -286,7 +288,7 @@ void ReplaceableMetadataImpl::resolveAllUses(bool ResolveUsers) { } // Copy out uses since UseMap could get touched below. - typedef std::pair> UseTy; + using UseTy = std::pair>; SmallVector Uses(UseMap.begin(), UseMap.end()); std::sort(Uses.begin(), Uses.end(), [](const UseTy &L, const UseTy &R) { return L.second.second < R.second.second; @@ -758,8 +760,8 @@ static T *uniquifyImpl(T *N, DenseSet &Store) { } template struct MDNode::HasCachedHash { - typedef char Yes[1]; - typedef char No[2]; + using Yes = char[1]; + using No = char[2]; template struct SFINAE {}; template @@ -1484,7 +1486,7 @@ void GlobalObject::addTypeMetadata(unsigned Offset, Metadata *TypeID) { addMetadata( LLVMContext::MD_type, *MDTuple::get(getContext(), - {ConstantAsMetadata::get(llvm::ConstantInt::get( + {ConstantAsMetadata::get(ConstantInt::get( Type::getInt64Ty(getContext()), Offset)), TypeID})); } diff --git a/contrib/llvm/lib/IR/Statepoint.cpp b/contrib/llvm/lib/IR/Statepoint.cpp index 8c3f0f208cc6..18efee2177c3 100644 --- a/contrib/llvm/lib/IR/Statepoint.cpp +++ b/contrib/llvm/lib/IR/Statepoint.cpp @@ -44,10 +44,22 @@ bool llvm::isGCRelocate(ImmutableCallSite CS) { return CS.getInstruction() && isa(CS.getInstruction()); } +bool llvm::isGCRelocate(const Value *V) { + if (auto CS = ImmutableCallSite(V)) + return isGCRelocate(CS); + return false; +} + bool llvm::isGCResult(ImmutableCallSite CS) { return CS.getInstruction() && isa(CS.getInstruction()); } +bool llvm::isGCResult(const Value *V) { + if (auto CS = ImmutableCallSite(V)) + return isGCResult(CS); + return false; +} + bool llvm::isStatepointDirectiveAttr(Attribute Attr) { return Attr.hasAttribute("statepoint-id") || Attr.hasAttribute("statepoint-num-patch-bytes"); diff --git a/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp index e4094d44867b..1efd481b246c 100644 --- a/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -32,7 +32,6 @@ #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/LTO/LTO.h" -#include "llvm/Linker/Linker.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Support/CachePruning.h" diff --git a/contrib/llvm/lib/MC/ELFObjectWriter.cpp b/contrib/llvm/lib/MC/ELFObjectWriter.cpp index 4d139132df46..30f357826805 100644 --- a/contrib/llvm/lib/MC/ELFObjectWriter.cpp +++ b/contrib/llvm/lib/MC/ELFObjectWriter.cpp @@ -633,9 +633,6 @@ void ELFObjectWriter::recordRelocation(MCAssembler &Asm, MCContext &Ctx = Asm.getContext(); if (const MCSymbolRefExpr *RefB = Target.getSymB()) { - assert(RefB->getKind() == MCSymbolRefExpr::VK_None && - "Should not have constructed this"); - // Let A, B and C being the components of Target and R be the location of // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). // If it is pcrel, we want to compute (A - B + C - R). diff --git a/contrib/llvm/lib/MC/MCAssembler.cpp b/contrib/llvm/lib/MC/MCAssembler.cpp index 53cdaac3aa54..92c5da0e9fef 100644 --- a/contrib/llvm/lib/MC/MCAssembler.cpp +++ b/contrib/llvm/lib/MC/MCAssembler.cpp @@ -193,14 +193,23 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, // FIXME: This code has some duplication with recordRelocation. We should // probably merge the two into a single callback that tries to evaluate a // fixup and records a relocation if one is needed. + + // On error claim to have completely evaluated the fixup, to prevent any + // further processing from being done. const MCExpr *Expr = Fixup.getValue(); + MCContext &Ctx = getContext(); + Value = 0; if (!Expr->evaluateAsRelocatable(Target, &Layout, &Fixup)) { - getContext().reportError(Fixup.getLoc(), "expected relocatable expression"); - // Claim to have completely evaluated the fixup, to prevent any further - // processing from being done. - Value = 0; + Ctx.reportError(Fixup.getLoc(), "expected relocatable expression"); return true; } + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + if (RefB->getKind() != MCSymbolRefExpr::VK_None) { + Ctx.reportError(Fixup.getLoc(), + "unsupported subtraction of qualified symbol"); + return true; + } + } bool IsPCRel = Backend.getFixupKindInfo( Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; @@ -254,8 +263,7 @@ bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, // Let the backend adjust the fixup value if necessary, including whether // we need a relocation. - Backend.processFixupValue(*this, Layout, Fixup, DF, Target, Value, - IsResolved); + Backend.processFixupValue(*this, Fixup, Target, IsResolved); return IsResolved; } @@ -639,9 +647,9 @@ void MCAssembler::writeSectionData(const MCSection *Sec, Layout.getSectionAddressSize(Sec)); } -std::pair MCAssembler::handleFixup(const MCAsmLayout &Layout, - MCFragment &F, - const MCFixup &Fixup) { +std::tuple +MCAssembler::handleFixup(const MCAsmLayout &Layout, MCFragment &F, + const MCFixup &Fixup) { // Evaluate the fixup. MCValue Target; uint64_t FixedValue; @@ -654,7 +662,7 @@ std::pair MCAssembler::handleFixup(const MCAsmLayout &Layout, getWriter().recordRelocation(*this, Layout, &F, Fixup, Target, IsPCRel, FixedValue); } - return std::make_pair(FixedValue, IsPCRel); + return std::make_tuple(Target, FixedValue, IsPCRel); } void MCAssembler::layout(MCAsmLayout &Layout) { @@ -731,9 +739,11 @@ void MCAssembler::layout(MCAsmLayout &Layout) { for (const MCFixup &Fixup : Fixups) { uint64_t FixedValue; bool IsPCRel; - std::tie(FixedValue, IsPCRel) = handleFixup(Layout, Frag, Fixup); - getBackend().applyFixup(Fixup, Contents.data(), Contents.size(), - FixedValue, IsPCRel, getContext()); + MCValue Target; + std::tie(Target, FixedValue, IsPCRel) = + handleFixup(Layout, Frag, Fixup); + getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue, + IsPCRel); } } } diff --git a/contrib/llvm/lib/MC/MCFragment.cpp b/contrib/llvm/lib/MC/MCFragment.cpp index f3d0eb55eecd..6e0249377a89 100644 --- a/contrib/llvm/lib/MC/MCFragment.cpp +++ b/contrib/llvm/lib/MC/MCFragment.cpp @@ -307,7 +307,7 @@ raw_ostream &operator<<(raw_ostream &OS, const MCFixup &AF) { } // end namespace llvm #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void MCFragment::dump() { +LLVM_DUMP_METHOD void MCFragment::dump() const { raw_ostream &OS = errs(); OS << "<"; @@ -328,9 +328,9 @@ LLVM_DUMP_METHOD void MCFragment::dump() { case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break; } - OS << "(getBundlePadding()) << ">"; switch (getKind()) { @@ -382,7 +382,8 @@ LLVM_DUMP_METHOD void MCFragment::dump() { } case MCFragment::FT_Fill: { const MCFillFragment *FF = cast(this); - OS << " Value:" << FF->getValue() << " Size:" << FF->getSize(); + OS << " Value:" << static_cast(FF->getValue()) + << " Size:" << FF->getSize(); break; } case MCFragment::FT_Relaxable: { @@ -395,7 +396,8 @@ LLVM_DUMP_METHOD void MCFragment::dump() { case MCFragment::FT_Org: { const MCOrgFragment *OF = cast(this); OS << "\n "; - OS << " Offset:" << OF->getOffset() << " Value:" << OF->getValue(); + OS << " Offset:" << OF->getOffset() + << " Value:" << static_cast(OF->getValue()); break; } case MCFragment::FT_Dwarf: { @@ -445,19 +447,19 @@ LLVM_DUMP_METHOD void MCFragment::dump() { OS << ">"; } -LLVM_DUMP_METHOD void MCAssembler::dump() { +LLVM_DUMP_METHOD void MCAssembler::dump() const{ raw_ostream &OS = errs(); OS << "dump(); } OS << "],\n"; OS << " Symbols:["; - for (symbol_iterator it = symbol_begin(), ie = symbol_end(); it != ie; ++it) { + for (const_symbol_iterator it = symbol_begin(), ie = symbol_end(); it != ie; ++it) { if (it != symbol_begin()) OS << ",\n "; OS << "("; it->dump(); diff --git a/contrib/llvm/lib/MC/MCSection.cpp b/contrib/llvm/lib/MC/MCSection.cpp index b961cb3968e8..d141dd6627c4 100644 --- a/contrib/llvm/lib/MC/MCSection.cpp +++ b/contrib/llvm/lib/MC/MCSection.cpp @@ -86,7 +86,7 @@ MCSection::getSubsectionInsertionPoint(unsigned Subsection) { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void MCSection::dump() { +LLVM_DUMP_METHOD void MCSection::dump() const { raw_ostream &OS = errs(); OS << "setWeak(true); + Symbol->setExternal(true); + break; + case MCSA_Global: Symbol->setExternal(true); break; + case MCSA_ELF_TypeFunction: Symbol->setIsFunction(true); break; + case MCSA_ELF_TypeObject: Symbol->setIsFunction(false); break; + default: // unrecognized directive + llvm_unreachable("unexpected MCSymbolAttr"); return false; } diff --git a/contrib/llvm/lib/MC/WinCOFFStreamer.cpp b/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp similarity index 97% rename from contrib/llvm/lib/MC/WinCOFFStreamer.cpp rename to contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp index b4d0d7a87f1d..bf341bb1f451 100644 --- a/contrib/llvm/lib/MC/WinCOFFStreamer.cpp +++ b/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp @@ -1,4 +1,4 @@ -//===- llvm/MC/WinCOFFStreamer.cpp ----------------------------------------===// +//===- llvm/MC/MCWinCOFFStreamer.cpp --------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -190,7 +190,8 @@ void MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { << COFF::SCT_COMPLEX_TYPE_SHIFT); } -void MCWinCOFFStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { +void MCWinCOFFStreamer::EmitCOFFSectionIndex(const MCSymbol *Symbol) { + visitUsedSymbol(*Symbol); MCDataFragment *DF = getOrCreateDataFragment(); const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext()); MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, FK_SecRel_2); @@ -198,8 +199,9 @@ void MCWinCOFFStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) { DF->getContents().resize(DF->getContents().size() + 2, 0); } -void MCWinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, +void MCWinCOFFStreamer::EmitCOFFSecRel32(const MCSymbol *Symbol, uint64_t Offset) { + visitUsedSymbol(*Symbol); MCDataFragment *DF = getOrCreateDataFragment(); // Create Symbol A for the relocation relative reference. const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, getContext()); diff --git a/contrib/llvm/lib/MC/WasmObjectWriter.cpp b/contrib/llvm/lib/MC/WasmObjectWriter.cpp index db304c027f99..45534ba18212 100644 --- a/contrib/llvm/lib/MC/WasmObjectWriter.cpp +++ b/contrib/llvm/lib/MC/WasmObjectWriter.cpp @@ -129,15 +129,15 @@ struct WasmGlobal { // Information about a single relocation. struct WasmRelocationEntry { - uint64_t Offset; // Where is the relocation. - const MCSymbolWasm *Symbol; // The symbol to relocate with. - int64_t Addend; // A value to add to the symbol. - unsigned Type; // The type of the relocation. - MCSectionWasm *FixupSection;// The section the relocation is targeting. + uint64_t Offset; // Where is the relocation. + const MCSymbolWasm *Symbol; // The symbol to relocate with. + int64_t Addend; // A value to add to the symbol. + unsigned Type; // The type of the relocation. + const MCSectionWasm *FixupSection;// The section the relocation is targeting. WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol, int64_t Addend, unsigned Type, - MCSectionWasm *FixupSection) + const MCSectionWasm *FixupSection) : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type), FixupSection(FixupSection) {} @@ -156,9 +156,19 @@ struct WasmRelocationEntry { Out << "Off=" << Offset << ", Sym=" << Symbol << ", Addend=" << Addend << ", Type=" << Type << ", FixupSection=" << FixupSection; } - void dump() const { print(errs()); } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const { print(dbgs()); } +#endif }; +#if !defined(NDEBUG) +raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { + Rel.print(OS); + return OS; +} +#endif + class WasmObjectWriter : public MCObjectWriter { /// Helper struct for containing some precomputed information on symbols. struct WasmSymbolData { @@ -229,6 +239,11 @@ class WasmObjectWriter : public MCObjectWriter { void writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; + void writeString(const StringRef Str) { + encodeULEB128(Str.size(), getStream()); + writeBytes(Str); + } + void writeValueType(wasm::ValType Ty) { encodeSLEB128(int32_t(Ty), getStream()); } @@ -250,7 +265,8 @@ class WasmObjectWriter : public MCObjectWriter { uint32_t NumFuncImports); void writeCodeRelocSection(); void writeDataRelocSection(uint64_t DataSectionHeaderSize); - void writeLinkingMetaDataSection(bool HasStackPointer, + void writeLinkingMetaDataSection(ArrayRef WeakSymbols, + bool HasStackPointer, uint32_t StackPointerGlobal); void applyRelocations(ArrayRef Relocations, @@ -282,6 +298,7 @@ void WasmObjectWriter::startSection(SectionBookkeeping &Section, assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) && "Only custom sections can have names"); + DEBUG(dbgs() << "startSection " << SectionId << ": " << Name << "\n"); encodeULEB128(SectionId, getStream()); Section.SizeOffset = getStream().tell(); @@ -295,8 +312,8 @@ void WasmObjectWriter::startSection(SectionBookkeeping &Section, // Custom sections in wasm also have a string identifier. if (SectionId == wasm::WASM_SEC_CUSTOM) { - encodeULEB128(strlen(Name), getStream()); - writeBytes(Name); + assert(Name); + writeString(StringRef(Name)); } } @@ -307,6 +324,7 @@ void WasmObjectWriter::endSection(SectionBookkeeping &Section) { if (uint32_t(Size) != Size) report_fatal_error("section size does not fit in a uint32_t"); + DEBUG(dbgs() << "endSection size=" << Size << "\n"); unsigned Padding = PaddingFor5ByteULEB128(Size); // Write the final section size to the payload_len field, which follows @@ -332,7 +350,7 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, bool &IsPCRel, uint64_t &FixedValue) { - MCSectionWasm &FixupSection = cast(*Fragment->getParent()); + const auto &FixupSection = cast(*Fragment->getParent()); uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); @@ -406,9 +424,12 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, } assert(!IsPCRel); + assert(SymA); + unsigned Type = getRelocType(Target, Fixup); WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection); + DEBUG(dbgs() << "WasmReloc: " << Rec << "\n"); if (FixupSection.hasInstructions()) CodeRelocations.push_back(Rec); @@ -453,11 +474,10 @@ static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) { const MCSymbolWasm *Sym = RelEntry.Symbol; // For undefined symbols, use a hopefully invalid value. - if (!Sym->isDefined(false)) + if (!Sym->isDefined(/*SetUsed=*/false)) return UINT32_MAX; - MCSectionWasm &Section = - cast(RelEntry.Symbol->getSection(false)); + const auto &Section = cast(RelEntry.Symbol->getSection(false)); uint64_t Address = Section.getSectionOffset() + RelEntry.Addend; // Ignore overflow. LLVM allows address arithmetic to silently wrap. @@ -471,16 +491,23 @@ uint32_t WasmObjectWriter::getRelocationIndexValue( switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: - assert(IndirectSymbolIndices.count(RelEntry.Symbol)); + if (!IndirectSymbolIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found table index space:" + + RelEntry.Symbol->getName()); return IndirectSymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: - assert(SymbolIndices.count(RelEntry.Symbol)); + if (!SymbolIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found function/global index space:" + + RelEntry.Symbol->getName()); return SymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: - assert(TypeIndices.count(RelEntry.Symbol)); + if (!TypeIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found in type index space:" + + RelEntry.Symbol->getName()); return TypeIndices[RelEntry.Symbol]; default: llvm_unreachable("invalid relocation type"); @@ -497,10 +524,12 @@ void WasmObjectWriter::applyRelocations( RelEntry.FixupSection->getSectionOffset() + RelEntry.Offset; + DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: { + case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: { uint32_t Index = getRelocationIndexValue(RelEntry); WritePatchableSLEB(Stream, Index, Offset); break; @@ -526,7 +555,7 @@ void WasmObjectWriter::applyRelocations( break; } default: - llvm_unreachable("unsupported relocation type"); + llvm_unreachable("invalid relocation type"); } } } @@ -573,6 +602,7 @@ void WasmObjectWriter::writeTypeSection( endSection(Section); } + void WasmObjectWriter::writeImportSection( const SmallVector &Imports) { if (Imports.empty()) @@ -583,13 +613,8 @@ void WasmObjectWriter::writeImportSection( encodeULEB128(Imports.size(), getStream()); for (const WasmImport &Import : Imports) { - StringRef ModuleName = Import.ModuleName; - encodeULEB128(ModuleName.size(), getStream()); - writeBytes(ModuleName); - - StringRef FieldName = Import.FieldName; - encodeULEB128(FieldName.size(), getStream()); - writeBytes(FieldName); + writeString(Import.ModuleName); + writeString(Import.FieldName); encodeULEB128(Import.Kind, getStream()); @@ -697,11 +722,8 @@ void WasmObjectWriter::writeExportSection( encodeULEB128(Exports.size(), getStream()); for (const WasmExport &Export : Exports) { - encodeULEB128(Export.FieldName.size(), getStream()); - writeBytes(Export.FieldName); - + writeString(Export.FieldName); encodeSLEB128(Export.Kind, getStream()); - encodeULEB128(Export.Index, getStream()); } @@ -743,17 +765,7 @@ void WasmObjectWriter::writeCodeSection( encodeULEB128(Functions.size(), getStream()); for (const WasmFunction &Func : Functions) { - MCSectionWasm &FuncSection = - static_cast(Func.Sym->getSection()); - - if (Func.Sym->isVariable()) - report_fatal_error("weak symbols not supported yet"); - - if (Func.Sym->getOffset() != 0) - report_fatal_error("function sections must contain one function each"); - - if (!Func.Sym->getSize()) - report_fatal_error("function symbols must have a size set with .size"); + auto &FuncSection = static_cast(Func.Sym->getSection()); int64_t Size = 0; if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout)) @@ -761,8 +773,7 @@ void WasmObjectWriter::writeCodeSection( encodeULEB128(Size, getStream()); - FuncSection.setSectionOffset(getStream().tell() - - Section.ContentsOffset); + FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset); Asm.writeSectionData(&FuncSection, Layout); } @@ -815,15 +826,13 @@ void WasmObjectWriter::writeNameSection( for (const WasmImport &Import : Imports) { if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) { encodeULEB128(Index, getStream()); - encodeULEB128(Import.FieldName.size(), getStream()); - writeBytes(Import.FieldName); + writeString(Import.FieldName); ++Index; } } for (const WasmFunction &Func : Functions) { encodeULEB128(Index, getStream()); - encodeULEB128(Func.Sym->getName().size(), getStream()); - writeBytes(Func.Sym->getName()); + writeString(Func.Sym->getName()); ++Index; } @@ -868,22 +877,37 @@ void WasmObjectWriter::writeDataRelocSection(uint64_t DataSectionHeaderSize) { } void WasmObjectWriter::writeLinkingMetaDataSection( - bool HasStackPointer, uint32_t StackPointerGlobal) { - if (!HasStackPointer) + ArrayRef WeakSymbols, bool HasStackPointer, + uint32_t StackPointerGlobal) { + if (!HasStackPointer && WeakSymbols.empty()) return; + SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); + SectionBookkeeping SubSection; - encodeULEB128(1, getStream()); // count + if (HasStackPointer) { + startSection(SubSection, wasm::WASM_STACK_POINTER); + encodeULEB128(StackPointerGlobal, getStream()); // id + endSection(SubSection); + } - encodeULEB128(wasm::WASM_STACK_POINTER, getStream()); // type - encodeULEB128(StackPointerGlobal, getStream()); // id + if (WeakSymbols.size() != 0) { + startSection(SubSection, wasm::WASM_SYMBOL_INFO); + encodeULEB128(WeakSymbols.size(), getStream()); + for (const StringRef Export: WeakSymbols) { + writeString(Export); + encodeULEB128(wasm::WASM_SYMBOL_FLAG_WEAK, getStream()); + } + endSection(SubSection); + } endSection(Section); } void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { + DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); MCContext &Ctx = Asm.getContext(); wasm::ValType PtrType = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32; @@ -894,6 +918,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, SmallVector Globals; SmallVector Imports; SmallVector Exports; + SmallVector WeakSymbols; SmallPtrSet IsAddressTaken; unsigned NumFuncImports = 0; unsigned NumGlobalImports = 0; @@ -902,7 +927,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, bool HasStackPointer = false; // Populate the IsAddressTaken set. - for (WasmRelocationEntry RelEntry : CodeRelocations) { + for (const WasmRelocationEntry &RelEntry : CodeRelocations) { switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: @@ -912,7 +937,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, break; } } - for (WasmRelocationEntry RelEntry : DataRelocations) { + for (const WasmRelocationEntry &RelEntry : DataRelocations) { switch (RelEntry.Type) { case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: @@ -975,7 +1000,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCFragment &Frag = *GlobalVars->begin(); if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) report_fatal_error("only data supported in .global_variables"); - const MCDataFragment &DataFrag = cast(Frag); + const auto &DataFrag = cast(Frag); if (!DataFrag.getFixups().empty()) report_fatal_error("fixups not supported in .global_variables"); const SmallVectorImpl &Contents = DataFrag.getContents(); @@ -1031,7 +1056,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCFragment &Frag = *StackPtr->begin(); if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data) report_fatal_error("only data supported in .stack_pointer"); - const MCDataFragment &DataFrag = cast(Frag); + const auto &DataFrag = cast(Frag); if (!DataFrag.getFixups().empty()) report_fatal_error("fixups not supported in .stack_pointer"); const SmallVectorImpl &Contents = DataFrag.getContents(); @@ -1041,14 +1066,30 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data(); } - // Handle defined symbols. + // Handle regular defined and undefined symbols. for (const MCSymbol &S : Asm.symbols()) { // Ignore unnamed temporary symbols, which aren't ever exported, imported, // or used in relocations. if (S.isTemporary() && S.getName().empty()) continue; + + // Variable references (weak references) are handled in a second pass + if (S.isVariable()) + continue; + const auto &WS = static_cast(S); + DEBUG(dbgs() << "MCSymbol: '" << S << "'" + << " isDefined=" << S.isDefined() << " isExternal=" + << S.isExternal() << " isTemporary=" << S.isTemporary() + << " isFunction=" << WS.isFunction() + << " isWeak=" << WS.isWeak() + << " isVariable=" << WS.isVariable() << "\n"); + + if (WS.isWeak()) + WeakSymbols.push_back(WS.getName()); + unsigned Index; + if (WS.isFunction()) { // Prepare the function's type, if we haven't seen it yet. WasmFunctionType F; @@ -1062,6 +1103,14 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, int32_t Type = Pair.first->second; if (WS.isDefined(/*SetUsed=*/false)) { + if (WS.getOffset() != 0) + report_fatal_error( + "function sections must contain one function each"); + + if (WS.getSize() == 0) + report_fatal_error( + "function symbols must have a size set with .size"); + // A definition. Take the next available index. Index = NumFuncImports + Functions.size(); @@ -1072,6 +1121,9 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, SymbolIndices[&WS] = Index; Functions.push_back(Func); } else { + // Should be no such thing as weak undefined symbol + assert(!WS.isVariable()); + // An import; the index was assigned above. Index = SymbolIndices.find(&WS)->second; } @@ -1085,86 +1137,108 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (WS.isTemporary() && !WS.getSize()) continue; - if (WS.isDefined(false)) { - if (WS.getOffset() != 0) - report_fatal_error("data sections must contain one variable each: " + - WS.getName()); - if (!WS.getSize()) - report_fatal_error("data symbols must have a size set with .size: " + - WS.getName()); + if (!WS.isDefined(/*SetUsed=*/false)) + continue; - int64_t Size = 0; - if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) - report_fatal_error(".size expression must be evaluatable"); + if (WS.getOffset() != 0) + report_fatal_error("data sections must contain one variable each: " + + WS.getName()); + if (!WS.getSize()) + report_fatal_error("data symbols must have a size set with .size: " + + WS.getName()); - MCSectionWasm &DataSection = - static_cast(WS.getSection()); + int64_t Size = 0; + if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) + report_fatal_error(".size expression must be evaluatable"); - if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection)) - report_fatal_error("data sections must contain at most one variable"); + auto &DataSection = static_cast(WS.getSection()); - DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); + if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection)) + report_fatal_error("data sections must contain at most one variable"); - DataSection.setSectionOffset(DataBytes.size()); + DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); - for (MCSection::iterator I = DataSection.begin(), E = DataSection.end(); - I != E; ++I) { - const MCFragment &Frag = *I; - if (Frag.hasInstructions()) - report_fatal_error("only data supported in data sections"); + DataSection.setSectionOffset(DataBytes.size()); - if (const MCAlignFragment *Align = dyn_cast(&Frag)) { - if (Align->getValueSize() != 1) - report_fatal_error("only byte values supported for alignment"); - // If nops are requested, use zeros, as this is the data section. - uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); - uint64_t Size = std::min(alignTo(DataBytes.size(), - Align->getAlignment()), - DataBytes.size() + - Align->getMaxBytesToEmit()); - DataBytes.resize(Size, Value); - } else if (const MCFillFragment *Fill = - dyn_cast(&Frag)) { - DataBytes.insert(DataBytes.end(), Size, Fill->getValue()); - } else { - const MCDataFragment &DataFrag = cast(Frag); - const SmallVectorImpl &Contents = DataFrag.getContents(); + for (const MCFragment &Frag : DataSection) { + if (Frag.hasInstructions()) + report_fatal_error("only data supported in data sections"); - DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); - } + if (auto *Align = dyn_cast(&Frag)) { + if (Align->getValueSize() != 1) + report_fatal_error("only byte values supported for alignment"); + // If nops are requested, use zeros, as this is the data section. + uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); + uint64_t Size = std::min(alignTo(DataBytes.size(), + Align->getAlignment()), + DataBytes.size() + + Align->getMaxBytesToEmit()); + DataBytes.resize(Size, Value); + } else if (auto *Fill = dyn_cast(&Frag)) { + DataBytes.insert(DataBytes.end(), Size, Fill->getValue()); + } else { + const auto &DataFrag = cast(Frag); + const SmallVectorImpl &Contents = DataFrag.getContents(); + + DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); } - - // For each global, prepare a corresponding wasm global holding its - // address. For externals these will also be named exports. - Index = NumGlobalImports + Globals.size(); - - WasmGlobal Global; - Global.Type = PtrType; - Global.IsMutable = false; - Global.HasImport = false; - Global.InitialValue = DataSection.getSectionOffset(); - Global.ImportIndex = 0; - SymbolIndices[&WS] = Index; - Globals.push_back(Global); } + + // For each global, prepare a corresponding wasm global holding its + // address. For externals these will also be named exports. + Index = NumGlobalImports + Globals.size(); + + WasmGlobal Global; + Global.Type = PtrType; + Global.IsMutable = false; + Global.HasImport = false; + Global.InitialValue = DataSection.getSectionOffset(); + Global.ImportIndex = 0; + SymbolIndices[&WS] = Index; + Globals.push_back(Global); } // If the symbol is visible outside this translation unit, export it. - if (WS.isExternal()) { - assert(WS.isDefined(false)); + if (WS.isExternal() && WS.isDefined(/*SetUsed=*/false)) { WasmExport Export; Export.FieldName = WS.getName(); Export.Index = Index; - if (WS.isFunction()) Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; else Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; - Exports.push_back(Export); } } + // Handle weak aliases + for (const MCSymbol &S : Asm.symbols()) { + if (!S.isVariable()) + continue; + assert(S.isExternal()); + assert(S.isDefined(/*SetUsed=*/false)); + + const auto &WS = static_cast(S); + + // Find the target symbol of this weak alias + const MCExpr *Expr = WS.getVariableValue(); + auto *Inner = dyn_cast(Expr); + const auto *ResolvedSym = cast(&Inner->getSymbol()); + uint32_t Index = SymbolIndices.find(ResolvedSym)->second; + DEBUG(dbgs() << "Weak alias: '" << WS << "' -> '" << ResolvedSym << "' = " << Index << "\n"); + SymbolIndices[&WS] = Index; + + WasmExport Export; + Export.FieldName = WS.getName(); + Export.Index = Index; + if (WS.isFunction()) + Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; + else + Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; + WeakSymbols.push_back(Export.FieldName); + Exports.push_back(Export); + } + // Add types for indirect function calls. for (const WasmRelocationEntry &Fixup : CodeRelocations) { if (Fixup.Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) @@ -1198,7 +1272,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, writeNameSection(Functions, Imports, NumFuncImports); writeCodeRelocSection(); writeDataRelocSection(DataSectionHeaderSize); - writeLinkingMetaDataSection(HasStackPointer, StackPointerGlobal); + writeLinkingMetaDataSection(WeakSymbols, HasStackPointer, StackPointerGlobal); // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. diff --git a/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp index 53dee3e8b9f3..fc5234950391 100644 --- a/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -735,7 +735,6 @@ void WinCOFFObjectWriter::recordRelocation( COFFSection *Sec = SectionMap[MCSec]; const MCSymbolRefExpr *SymB = Target.getSymB(); - bool CrossSection = false; if (SymB) { const MCSymbol *B = &SymB->getSymbol(); @@ -747,28 +746,9 @@ void WinCOFFObjectWriter::recordRelocation( return; } - if (!A.getFragment()) { - Asm.getContext().reportError( - Fixup.getLoc(), - Twine("symbol '") + A.getName() + - "' can not be undefined in a subtraction expression"); - return; - } - - CrossSection = &A.getSection() != &B->getSection(); - // Offset of the symbol in the section int64_t OffsetOfB = Layout.getSymbolOffset(*B); - // In the case where we have SymbA and SymB, we just need to store the delta - // between the two symbols. Update FixedValue to account for the delta, and - // skip recording the relocation. - if (!CrossSection) { - int64_t OffsetOfA = Layout.getSymbolOffset(A); - FixedValue = (OffsetOfA - OffsetOfB) + Target.getConstant(); - return; - } - // Offset of the relocation in the section int64_t OffsetOfRelocation = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); @@ -784,7 +764,7 @@ void WinCOFFObjectWriter::recordRelocation( Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); // Turn relocations for temporary symbols into section relocations. - if (A.isTemporary() || CrossSection) { + if (A.isTemporary()) { MCSection *TargetSection = &A.getSection(); assert( SectionMap.find(TargetSection) != SectionMap.end() && @@ -802,7 +782,7 @@ void WinCOFFObjectWriter::recordRelocation( Reloc.Data.VirtualAddress += Fixup.getOffset(); Reloc.Data.Type = TargetObjectWriter->getRelocType( - Target, Fixup, CrossSection, Asm.getBackend()); + Asm.getContext(), Target, Fixup, SymB, Asm.getBackend()); // FIXME: Can anyone explain what this does other than adjust for the size // of the offset? diff --git a/contrib/llvm/lib/Object/COFFObjectFile.cpp b/contrib/llvm/lib/Object/COFFObjectFile.cpp index 579c8dde366a..9a760d86e7e2 100644 --- a/contrib/llvm/lib/Object/COFFObjectFile.cpp +++ b/contrib/llvm/lib/Object/COFFObjectFile.cpp @@ -650,6 +650,23 @@ std::error_code COFFObjectFile::initDebugDirectoryPtr() { return std::error_code(); } +std::error_code COFFObjectFile::initLoadConfigPtr() { + // Get the RVA of the debug directory. Do nothing if it does not exist. + const data_directory *DataEntry; + if (getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataEntry)) + return std::error_code(); + + // Do nothing if the RVA is NULL. + if (DataEntry->RelativeVirtualAddress == 0) + return std::error_code(); + uintptr_t IntPtr = 0; + if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) + return EC; + + LoadConfig = (const void *)IntPtr; + return std::error_code(); +} + COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr), COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr), @@ -784,6 +801,9 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) if ((EC = initDebugDirectoryPtr())) return; + if ((EC = initLoadConfigPtr())) + return; + EC = std::error_code(); } diff --git a/contrib/llvm/lib/Object/IRSymtab.cpp b/contrib/llvm/lib/Object/IRSymtab.cpp index a6cd5dda12d3..7bca032a7be1 100644 --- a/contrib/llvm/lib/Object/IRSymtab.cpp +++ b/contrib/llvm/lib/Object/IRSymtab.cpp @@ -46,15 +46,15 @@ namespace { /// Stores the temporary state that is required to build an IR symbol table. struct Builder { SmallVector &Symtab; - SmallVector &Strtab; + StringTableBuilder &StrtabBuilder; + StringSaver Saver; - Builder(SmallVector &Symtab, SmallVector &Strtab) - : Symtab(Symtab), Strtab(Strtab) {} - - StringTableBuilder StrtabBuilder{StringTableBuilder::RAW}; - - BumpPtrAllocator Alloc; - StringSaver Saver{Alloc}; + // This ctor initializes a StringSaver using the passed in BumpPtrAllocator. + // The StringTableBuilder does not create a copy of any strings added to it, + // so this provides somewhere to store any strings that we create. + Builder(SmallVector &Symtab, StringTableBuilder &StrtabBuilder, + BumpPtrAllocator &Alloc) + : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc) {} DenseMap ComdatMap; Mangler Mang; @@ -240,7 +240,7 @@ Error Builder::build(ArrayRef IRMods) { return Err; COFFLinkerOptsOS.flush(); - setStr(Hdr.COFFLinkerOpts, COFFLinkerOpts); + setStr(Hdr.COFFLinkerOpts, Saver.save(COFFLinkerOpts)); // We are about to fill in the header's range fields, so reserve space for it // and copy it in afterwards. @@ -251,19 +251,15 @@ Error Builder::build(ArrayRef IRMods) { writeRange(Hdr.Uncommons, Uncommons); *reinterpret_cast(Symtab.data()) = Hdr; - - raw_svector_ostream OS(Strtab); - StrtabBuilder.finalizeInOrder(); - StrtabBuilder.write(OS); - return Error::success(); } } // end anonymous namespace Error irsymtab::build(ArrayRef Mods, SmallVector &Symtab, - SmallVector &Strtab) { - return Builder(Symtab, Strtab).build(Mods); + StringTableBuilder &StrtabBuilder, + BumpPtrAllocator &Alloc) { + return Builder(Symtab, StrtabBuilder, Alloc).build(Mods); } // Upgrade a vector of bitcode modules created by an old version of LLVM by @@ -285,9 +281,15 @@ static Expected upgrade(ArrayRef BMs) { OwnedMods.push_back(std::move(*MOrErr)); } - if (Error E = build(Mods, FC.Symtab, FC.Strtab)) + StringTableBuilder StrtabBuilder(StringTableBuilder::RAW); + BumpPtrAllocator Alloc; + if (Error E = build(Mods, FC.Symtab, StrtabBuilder, Alloc)) return std::move(E); + StrtabBuilder.finalizeInOrder(); + FC.Strtab.resize(StrtabBuilder.getSize()); + StrtabBuilder.write((uint8_t *)FC.Strtab.data()); + FC.TheReader = {{FC.Symtab.data(), FC.Symtab.size()}, {FC.Strtab.data(), FC.Strtab.size()}}; return std::move(FC); diff --git a/contrib/llvm/lib/Object/MachOObjectFile.cpp b/contrib/llvm/lib/Object/MachOObjectFile.cpp index 7804bbe06f83..2e4da9f15aa1 100644 --- a/contrib/llvm/lib/Object/MachOObjectFile.cpp +++ b/contrib/llvm/lib/Object/MachOObjectFile.cpp @@ -1951,13 +1951,29 @@ MachOObjectFile::section_rel_end(DataRefImpl Sec) const { return relocation_iterator(RelocationRef(Ret, this)); } +relocation_iterator MachOObjectFile::extrel_begin() const { + DataRefImpl Ret; + Ret.d.a = 0; // Would normally be a section index. + Ret.d.b = 0; // Index into the external relocations + return relocation_iterator(RelocationRef(Ret, this)); +} + +relocation_iterator MachOObjectFile::extrel_end() const { + MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); + DataRefImpl Ret; + Ret.d.a = 0; // Would normally be a section index. + Ret.d.b = DysymtabLoadCmd.nextrel; // Index into the external relocations + return relocation_iterator(RelocationRef(Ret, this)); +} + void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const { ++Rel.d.b; } uint64_t MachOObjectFile::getRelocationOffset(DataRefImpl Rel) const { - assert(getHeader().filetype == MachO::MH_OBJECT && - "Only implemented for MH_OBJECT"); + assert((getHeader().filetype == MachO::MH_OBJECT || + getHeader().filetype == MachO::MH_KEXT_BUNDLE) && + "Only implemented for MH_OBJECT && MH_KEXT_BUNDLE"); MachO::any_relocation_info RE = getRelocation(Rel); return getAnyRelocationAddress(RE); } @@ -4086,15 +4102,20 @@ MachOObjectFile::getThreadCommand(const LoadCommandInfo &L) const { MachO::any_relocation_info MachOObjectFile::getRelocation(DataRefImpl Rel) const { - DataRefImpl Sec; - Sec.d.a = Rel.d.a; uint32_t Offset; - if (is64Bit()) { - MachO::section_64 Sect = getSection64(Sec); - Offset = Sect.reloff; + if (getHeader().filetype == MachO::MH_OBJECT) { + DataRefImpl Sec; + Sec.d.a = Rel.d.a; + if (is64Bit()) { + MachO::section_64 Sect = getSection64(Sec); + Offset = Sect.reloff; + } else { + MachO::section Sect = getSection(Sec); + Offset = Sect.reloff; + } } else { - MachO::section Sect = getSection(Sec); - Offset = Sect.reloff; + MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); + Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations } auto P = reinterpret_cast( diff --git a/contrib/llvm/lib/Object/WasmObjectFile.cpp b/contrib/llvm/lib/Object/WasmObjectFile.cpp index 2304098c1dc9..d15860674aeb 100644 --- a/contrib/llvm/lib/Object/WasmObjectFile.cpp +++ b/contrib/llvm/lib/Object/WasmObjectFile.cpp @@ -28,6 +28,8 @@ #include #include +#define DEBUG_TYPE "wasm-object" + using namespace llvm; using namespace object; @@ -256,6 +258,7 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { while (Ptr < End) { uint8_t Type = readVarint7(Ptr); uint32_t Size = readVaruint32(Ptr); + const uint8_t *SubSectionEnd = Ptr + Size; switch (Type) { case wasm::WASM_NAMES_FUNCTION: { uint32_t Count = readVaruint32(Ptr); @@ -275,6 +278,9 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { Ptr += Size; break; } + if (Ptr != SubSectionEnd) + return make_error("Name sub-section ended prematurely", + object_error::parse_failed); } if (Ptr != End) @@ -283,6 +289,50 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { return Error::success(); } +Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, + const uint8_t *End) { + while (Ptr < End) { + uint8_t Type = readVarint7(Ptr); + uint32_t Size = readVaruint32(Ptr); + const uint8_t *SubSectionEnd = Ptr + Size; + switch (Type) { + case wasm::WASM_SYMBOL_INFO: { + uint32_t Count = readVaruint32(Ptr); + while (Count--) { + StringRef Symbol = readString(Ptr); + DEBUG(dbgs() << "reading syminfo: " << Symbol << "\n"); + uint32_t Flags = readVaruint32(Ptr); + auto iter = SymbolMap.find(Symbol); + if (iter == SymbolMap.end()) { + return make_error( + "Invalid symbol name in linking section", + object_error::parse_failed); + } + uint32_t SymIndex = iter->second; + assert(SymIndex < Symbols.size()); + Symbols[SymIndex].Flags = Flags; + DEBUG(dbgs() << "Set symbol flags index:" + << SymIndex << " name:" + << Symbols[SymIndex].Name << " exptected:" + << Symbol << " flags: " << Flags << "\n"); + } + break; + } + case wasm::WASM_STACK_POINTER: + default: + Ptr += Size; + break; + } + if (Ptr != SubSectionEnd) + return make_error( + "Linking sub-section ended prematurely", object_error::parse_failed); + } + if (Ptr != End) + return make_error("Linking section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + WasmSection* WasmObjectFile::findCustomSectionByName(StringRef Name) { for (WasmSection& Section : Sections) { if (Section.Type == wasm::WASM_SEC_CUSTOM && Section.Name == Name) @@ -325,6 +375,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr, case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: break; case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: @@ -332,7 +383,8 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr, Reloc.Addend = readVarint32(Ptr); break; default: - return make_error("Bad relocation type", + return make_error("Bad relocation type: " + + Twine(Reloc.Type), object_error::parse_failed); } Section->Relocations.push_back(Reloc); @@ -349,6 +401,9 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, if (Sec.Name == "name") { if (Error Err = parseNameSection(Ptr, End)) return Err; + } else if (Sec.Name == "linking") { + if (Error Err = parseLinkingSection(Ptr, End)) + return Err; } else if (Sec.Name.startswith("reloc.")) { if (Error Err = parseRelocSection(Sec.Name, Ptr, End)) return Err; @@ -400,14 +455,20 @@ Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) switch (Im.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: Im.SigIndex = readVaruint32(Ptr); + SymbolMap.try_emplace(Im.Field, Symbols.size()); Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::FUNCTION_IMPORT, Sections.size(), i); + DEBUG(dbgs() << "Adding import: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_GLOBAL: Im.Global.Type = readVarint7(Ptr); Im.Global.Mutable = readVaruint1(Ptr); + SymbolMap.try_emplace(Im.Field, Symbols.size()); Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT, Sections.size(), i); + DEBUG(dbgs() << "Adding import: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_MEMORY: Im.Memory = readLimits(Ptr); @@ -496,15 +557,20 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) Ex.Name = readString(Ptr); Ex.Kind = readUint8(Ptr); Ex.Index = readVaruint32(Ptr); - Exports.push_back(Ex); switch (Ex.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: + SymbolMap.try_emplace(Ex.Name, Symbols.size()); Symbols.emplace_back(Ex.Name, WasmSymbol::SymbolType::FUNCTION_EXPORT, Sections.size(), i); + DEBUG(dbgs() << "Adding export: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_GLOBAL: + SymbolMap.try_emplace(Ex.Name, Symbols.size()); Symbols.emplace_back(Ex.Name, WasmSymbol::SymbolType::GLOBAL_EXPORT, Sections.size(), i); + DEBUG(dbgs() << "Adding export: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_TABLE: @@ -513,6 +579,7 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) return make_error( "Unexpected export kind", object_error::parse_failed); } + Exports.push_back(Ex); } if (Ptr != End) return make_error("Export section ended prematurely", @@ -620,6 +687,10 @@ uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { uint32_t Result = SymbolRef::SF_None; const WasmSymbol &Sym = getWasmSymbol(Symb); + DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n"); + if (Sym.Flags & wasm::WASM_SYMBOL_FLAG_WEAK) + Result |= SymbolRef::SF_Weak; + switch (Sym.Type) { case WasmSymbol::SymbolType::FUNCTION_IMPORT: Result |= SymbolRef::SF_Undefined | SymbolRef::SF_Executable; @@ -629,6 +700,7 @@ uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { break; case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: Result |= SymbolRef::SF_Executable; + Result |= SymbolRef::SF_FormatSpecific; break; case WasmSymbol::SymbolType::GLOBAL_IMPORT: Result |= SymbolRef::SF_Undefined; @@ -662,8 +734,7 @@ const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const { } Expected WasmObjectFile::getSymbolName(DataRefImpl Symb) const { - const WasmSymbol &Sym = getWasmSymbol(Symb); - return Sym.Name; + return getWasmSymbol(Symb).Name; } Expected WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { @@ -671,8 +742,18 @@ Expected WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { } uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { - const WasmSymbol &Sym = getWasmSymbol(Symb); - return Sym.ElementIndex; + const WasmSymbol& Sym = getWasmSymbol(Symb); + switch (Sym.Type) { + case WasmSymbol::SymbolType::FUNCTION_IMPORT: + case WasmSymbol::SymbolType::GLOBAL_IMPORT: + return 0; + case WasmSymbol::SymbolType::FUNCTION_EXPORT: + case WasmSymbol::SymbolType::GLOBAL_EXPORT: + return Exports[Sym.ElementIndex].Index; + case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: + return Sym.ElementIndex; + } + llvm_unreachable("invalid symbol type"); } uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const { diff --git a/contrib/llvm/lib/Object/WindowsResource.cpp b/contrib/llvm/lib/Object/WindowsResource.cpp index 3f6080d48f9d..ff9b9ca35eb5 100644 --- a/contrib/llvm/lib/Object/WindowsResource.cpp +++ b/contrib/llvm/lib/Object/WindowsResource.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/WindowsResource.h" -#include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/MathExtras.h" @@ -21,6 +20,9 @@ #include #include +using namespace llvm; +using namespace object; + namespace llvm { namespace object { @@ -34,23 +36,19 @@ const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t); // 8-byte because it makes everyone happy. const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t); -static const size_t ResourceMagicSize = 16; - -static const size_t NullEntrySize = 16; - uint32_t WindowsResourceParser::TreeNode::StringCount = 0; uint32_t WindowsResourceParser::TreeNode::DataCount = 0; WindowsResource::WindowsResource(MemoryBufferRef Source) : Binary(Binary::ID_WinRes, Source) { - size_t LeadingSize = ResourceMagicSize + NullEntrySize; + size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE; BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize), support::little); } Expected> WindowsResource::createWindowsResource(MemoryBufferRef Source) { - if (Source.getBufferSize() < ResourceMagicSize + NullEntrySize) + if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE) return make_error( "File too small to be a resource file", object_error::invalid_file_type); @@ -103,12 +101,10 @@ static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID, } Error ResourceEntryRef::loadNext() { - uint32_t DataSize; - RETURN_IF_ERROR(Reader.readInteger(DataSize)); - uint32_t HeaderSize; - RETURN_IF_ERROR(Reader.readInteger(HeaderSize)); + const WinResHeaderPrefix *Prefix; + RETURN_IF_ERROR(Reader.readObject(Prefix)); - if (HeaderSize < MIN_HEADER_SIZE) + if (Prefix->HeaderSize < MIN_HEADER_SIZE) return make_error("Header size is too small.", object_error::parse_failed); @@ -116,13 +112,13 @@ Error ResourceEntryRef::loadNext() { RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName)); - RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); + RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT)); RETURN_IF_ERROR(Reader.readObject(Suffix)); - RETURN_IF_ERROR(Reader.readArray(Data, DataSize)); + RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize)); - RETURN_IF_ERROR(Reader.padToAlignment(sizeof(uint32_t))); + RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT)); return Error::success(); } @@ -246,14 +242,14 @@ WindowsResourceParser::TreeNode::addChild(ArrayRef NameRef, std::string NameString; ArrayRef CorrectedName; std::vector EndianCorrectedName; - if (llvm::sys::IsBigEndianHost) { + if (sys::IsBigEndianHost) { EndianCorrectedName.resize(NameRef.size() + 1); std::copy(NameRef.begin(), NameRef.end(), EndianCorrectedName.begin() + 1); EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; CorrectedName = makeArrayRef(EndianCorrectedName); } else CorrectedName = NameRef; - llvm::convertUTF16ToUTF8String(CorrectedName, NameString); + convertUTF16ToUTF8String(CorrectedName, NameString); auto Child = StringChildren.find(NameString); if (Child == StringChildren.end()) { @@ -282,17 +278,17 @@ void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer, // the directory strings or the relocations of the .rsrc section. uint32_t WindowsResourceParser::TreeNode::getTreeSize() const { uint32_t Size = (IDChildren.size() + StringChildren.size()) * - sizeof(llvm::object::coff_resource_dir_entry); + sizeof(coff_resource_dir_entry); // Reached a node pointing to a data entry. if (IsDataNode) { - Size += sizeof(llvm::object::coff_resource_data_entry); + Size += sizeof(coff_resource_data_entry); return Size; } // If the node does not point to data, it must have a directory table pointing // to other nodes. - Size += sizeof(llvm::object::coff_resource_dir_table); + Size += sizeof(coff_resource_dir_table); for (auto const &Child : StringChildren) { Size += Child.second->getTreeSize(); @@ -305,9 +301,9 @@ uint32_t WindowsResourceParser::TreeNode::getTreeSize() const { class WindowsResourceCOFFWriter { public: - WindowsResourceCOFFWriter(StringRef OutputFile, Machine MachineType, + WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, Error &E); - Error write(); + std::unique_ptr write(); private: void performFileLayout(); @@ -323,10 +319,10 @@ class WindowsResourceCOFFWriter { void writeDirectoryTree(); void writeDirectoryStringTable(); void writeFirstSectionRelocations(); - std::unique_ptr Buffer; - uint8_t *BufferStart; + std::unique_ptr OutputBuffer; + char *BufferStart; uint64_t CurrentOffset = 0; - Machine MachineType; + COFF::MachineTypes MachineType; const WindowsResourceParser::TreeNode &Resources; const ArrayRef> Data; uint64_t FileSize; @@ -343,28 +339,21 @@ class WindowsResourceCOFFWriter { }; WindowsResourceCOFFWriter::WindowsResourceCOFFWriter( - StringRef OutputFile, Machine MachineType, - const WindowsResourceParser &Parser, Error &E) + COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, + Error &E) : MachineType(MachineType), Resources(Parser.getTree()), Data(Parser.getData()), StringTable(Parser.getStringTable()) { performFileLayout(); - ErrorOr> BufferOrErr = - FileOutputBuffer::create(OutputFile, FileSize); - if (!BufferOrErr) { - E = errorCodeToError(BufferOrErr.getError()); - return; - } - - Buffer = std::move(*BufferOrErr); + OutputBuffer = MemoryBuffer::getNewMemBuffer(FileSize); } void WindowsResourceCOFFWriter::performFileLayout() { // Add size of COFF header. - FileSize = llvm::COFF::Header16Size; + FileSize = COFF::Header16Size; // one .rsrc section header for directory tree, another for resource data. - FileSize += 2 * llvm::COFF::SectionSize; + FileSize += 2 * COFF::SectionSize; performSectionOneLayout(); performSectionTwoLayout(); @@ -372,9 +361,9 @@ void WindowsResourceCOFFWriter::performFileLayout() { // We have reached the address of the symbol table. SymbolTableOffset = FileSize; - FileSize += llvm::COFF::Symbol16Size; // size of the @feat.00 symbol. - FileSize += 4 * llvm::COFF::Symbol16Size; // symbol + aux for each section. - FileSize += Data.size() * llvm::COFF::Symbol16Size; // 1 symbol per resource. + FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol. + FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section. + FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource. FileSize += 4; // four null bytes for the string table. } @@ -395,8 +384,8 @@ void WindowsResourceCOFFWriter::performSectionOneLayout() { // account for the relocations of section one. SectionOneRelocations = FileSize + SectionOneSize; FileSize += SectionOneSize; - FileSize += Data.size() * - llvm::COFF::RelocationSize; // one relocation for each resource. + FileSize += + Data.size() * COFF::RelocationSize; // one relocation for each resource. FileSize = alignTo(FileSize, SECTION_ALIGNMENT); } @@ -407,7 +396,7 @@ void WindowsResourceCOFFWriter::performSectionTwoLayout() { SectionTwoSize = 0; for (auto const &Entry : Data) { DataOffsets.push_back(SectionTwoSize); - SectionTwoSize += llvm::alignTo(Entry.size(), sizeof(uint64_t)); + SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t)); } FileSize += SectionTwoSize; FileSize = alignTo(FileSize, SECTION_ALIGNMENT); @@ -420,8 +409,8 @@ static std::time_t getTime() { return Now; } -Error WindowsResourceCOFFWriter::write() { - BufferStart = Buffer->getBufferStart(); +std::unique_ptr WindowsResourceCOFFWriter::write() { + BufferStart = const_cast(OutputBuffer->getBufferStart()); writeCOFFHeader(); writeFirstSectionHeader(); @@ -431,29 +420,24 @@ Error WindowsResourceCOFFWriter::write() { writeSymbolTable(); writeStringTable(); - if (auto EC = Buffer->commit()) { - return errorCodeToError(EC); - } - - return Error::success(); + return std::move(OutputBuffer); } void WindowsResourceCOFFWriter::writeCOFFHeader() { // Write the COFF header. - auto *Header = - reinterpret_cast(BufferStart); + auto *Header = reinterpret_cast(BufferStart); switch (MachineType) { - case Machine::ARM: - Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; + case COFF::IMAGE_FILE_MACHINE_ARMNT: + Header->Machine = COFF::IMAGE_FILE_MACHINE_ARMNT; break; - case Machine::X64: - Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; + case COFF::IMAGE_FILE_MACHINE_AMD64: + Header->Machine = COFF::IMAGE_FILE_MACHINE_AMD64; break; - case Machine::X86: - Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_I386; + case COFF::IMAGE_FILE_MACHINE_I386: + Header->Machine = COFF::IMAGE_FILE_MACHINE_I386; break; default: - Header->Machine = llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN; + Header->Machine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; } Header->NumberOfSections = 2; Header->TimeDateStamp = getTime(); @@ -461,15 +445,15 @@ void WindowsResourceCOFFWriter::writeCOFFHeader() { // One symbol for every resource plus 2 for each section and @feat.00 Header->NumberOfSymbols = Data.size() + 5; Header->SizeOfOptionalHeader = 0; - Header->Characteristics = llvm::COFF::IMAGE_FILE_32BIT_MACHINE; + Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE; } void WindowsResourceCOFFWriter::writeFirstSectionHeader() { // Write the first section header. - CurrentOffset += sizeof(llvm::object::coff_file_header); - auto *SectionOneHeader = reinterpret_cast( - BufferStart + CurrentOffset); - strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)llvm::COFF::NameSize); + CurrentOffset += sizeof(coff_file_header); + auto *SectionOneHeader = + reinterpret_cast(BufferStart + CurrentOffset); + strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize); SectionOneHeader->VirtualSize = 0; SectionOneHeader->VirtualAddress = 0; SectionOneHeader->SizeOfRawData = SectionOneSize; @@ -478,19 +462,16 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() { SectionOneHeader->PointerToLinenumbers = 0; SectionOneHeader->NumberOfRelocations = Data.size(); SectionOneHeader->NumberOfLinenumbers = 0; - SectionOneHeader->Characteristics = llvm::COFF::IMAGE_SCN_ALIGN_1BYTES; - SectionOneHeader->Characteristics += - llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; - SectionOneHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE; - SectionOneHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_READ; + SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; + SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; } void WindowsResourceCOFFWriter::writeSecondSectionHeader() { // Write the second section header. - CurrentOffset += sizeof(llvm::object::coff_section); - auto *SectionTwoHeader = reinterpret_cast( - BufferStart + CurrentOffset); - strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)llvm::COFF::NameSize); + CurrentOffset += sizeof(coff_section); + auto *SectionTwoHeader = + reinterpret_cast(BufferStart + CurrentOffset); + strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize); SectionTwoHeader->VirtualSize = 0; SectionTwoHeader->VirtualAddress = 0; SectionTwoHeader->SizeOfRawData = SectionTwoSize; @@ -499,14 +480,13 @@ void WindowsResourceCOFFWriter::writeSecondSectionHeader() { SectionTwoHeader->PointerToLinenumbers = 0; SectionTwoHeader->NumberOfRelocations = 0; SectionTwoHeader->NumberOfLinenumbers = 0; - SectionTwoHeader->Characteristics = - llvm::COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; - SectionTwoHeader->Characteristics += llvm::COFF::IMAGE_SCN_MEM_READ; + SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; + SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ; } void WindowsResourceCOFFWriter::writeFirstSection() { // Write section one. - CurrentOffset += sizeof(llvm::object::coff_section); + CurrentOffset += sizeof(coff_section); writeDirectoryTree(); writeDirectoryStringTable(); @@ -529,70 +509,65 @@ void WindowsResourceCOFFWriter::writeSecondSection() { void WindowsResourceCOFFWriter::writeSymbolTable() { // Now write the symbol table. // First, the feat symbol. - auto *Symbol = reinterpret_cast(BufferStart + - CurrentOffset); - strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)llvm::COFF::NameSize); + auto *Symbol = reinterpret_cast(BufferStart + CurrentOffset); + strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize); Symbol->Value = 0x11; Symbol->SectionNumber = 0xffff; - Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL; - Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC; + Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; + Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; Symbol->NumberOfAuxSymbols = 0; - CurrentOffset += sizeof(llvm::object::coff_symbol16); + CurrentOffset += sizeof(coff_symbol16); // Now write the .rsrc1 symbol + aux. - Symbol = reinterpret_cast(BufferStart + - CurrentOffset); - strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)llvm::COFF::NameSize); + Symbol = reinterpret_cast(BufferStart + CurrentOffset); + strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize); Symbol->Value = 0; Symbol->SectionNumber = 1; - Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL; - Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC; + Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; + Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; Symbol->NumberOfAuxSymbols = 1; - CurrentOffset += sizeof(llvm::object::coff_symbol16); - auto *Aux = reinterpret_cast( - BufferStart + CurrentOffset); + CurrentOffset += sizeof(coff_symbol16); + auto *Aux = reinterpret_cast(BufferStart + + CurrentOffset); Aux->Length = SectionOneSize; Aux->NumberOfRelocations = Data.size(); Aux->NumberOfLinenumbers = 0; Aux->CheckSum = 0; Aux->NumberLowPart = 0; Aux->Selection = 0; - CurrentOffset += sizeof(llvm::object::coff_aux_section_definition); + CurrentOffset += sizeof(coff_aux_section_definition); // Now write the .rsrc2 symbol + aux. - Symbol = reinterpret_cast(BufferStart + - CurrentOffset); - strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)llvm::COFF::NameSize); + Symbol = reinterpret_cast(BufferStart + CurrentOffset); + strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize); Symbol->Value = 0; Symbol->SectionNumber = 2; - Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL; - Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC; + Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; + Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; Symbol->NumberOfAuxSymbols = 1; - CurrentOffset += sizeof(llvm::object::coff_symbol16); - Aux = reinterpret_cast( - BufferStart + CurrentOffset); + CurrentOffset += sizeof(coff_symbol16); + Aux = reinterpret_cast(BufferStart + + CurrentOffset); Aux->Length = SectionTwoSize; Aux->NumberOfRelocations = 0; Aux->NumberOfLinenumbers = 0; Aux->CheckSum = 0; Aux->NumberLowPart = 0; Aux->Selection = 0; - CurrentOffset += sizeof(llvm::object::coff_aux_section_definition); + CurrentOffset += sizeof(coff_aux_section_definition); // Now write a symbol for each relocation. for (unsigned i = 0; i < Data.size(); i++) { char RelocationName[9]; sprintf(RelocationName, "$R%06X", DataOffsets[i]); - Symbol = reinterpret_cast(BufferStart + - CurrentOffset); - strncpy(Symbol->Name.ShortName, RelocationName, - (size_t)llvm::COFF::NameSize); + Symbol = reinterpret_cast(BufferStart + CurrentOffset); + strncpy(Symbol->Name.ShortName, RelocationName, (size_t)COFF::NameSize); Symbol->Value = DataOffsets[i]; Symbol->SectionNumber = 1; - Symbol->Type = llvm::COFF::IMAGE_SYM_DTYPE_NULL; - Symbol->StorageClass = llvm::COFF::IMAGE_SYM_CLASS_STATIC; + Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL; + Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; Symbol->NumberOfAuxSymbols = 0; - CurrentOffset += sizeof(llvm::object::coff_symbol16); + CurrentOffset += sizeof(coff_symbol16); } } @@ -607,18 +582,18 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() { // COFF objects. std::queue Queue; Queue.push(&Resources); - uint32_t NextLevelOffset = sizeof(llvm::object::coff_resource_dir_table) + - (Resources.getStringChildren().size() + - Resources.getIDChildren().size()) * - sizeof(llvm::object::coff_resource_dir_entry); + uint32_t NextLevelOffset = + sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() + + Resources.getIDChildren().size()) * + sizeof(coff_resource_dir_entry); std::vector DataEntriesTreeOrder; uint32_t CurrentRelativeOffset = 0; while (!Queue.empty()) { auto CurrentNode = Queue.front(); Queue.pop(); - auto *Table = reinterpret_cast( - BufferStart + CurrentOffset); + auto *Table = reinterpret_cast(BufferStart + + CurrentOffset); Table->Characteristics = CurrentNode->getCharacteristics(); Table->TimeDateStamp = 0; Table->MajorVersion = CurrentNode->getMajorVersion(); @@ -627,63 +602,63 @@ void WindowsResourceCOFFWriter::writeDirectoryTree() { auto &StringChildren = CurrentNode->getStringChildren(); Table->NumberOfNameEntries = StringChildren.size(); Table->NumberOfIDEntries = IDChildren.size(); - CurrentOffset += sizeof(llvm::object::coff_resource_dir_table); - CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_table); + CurrentOffset += sizeof(coff_resource_dir_table); + CurrentRelativeOffset += sizeof(coff_resource_dir_table); // Write the directory entries immediately following each directory table. for (auto const &Child : StringChildren) { - auto *Entry = reinterpret_cast( - BufferStart + CurrentOffset); + auto *Entry = reinterpret_cast(BufferStart + + CurrentOffset); Entry->Identifier.NameOffset = StringTableOffsets[Child.second->getStringIndex()]; if (Child.second->checkIsDataNode()) { Entry->Offset.DataEntryOffset = NextLevelOffset; - NextLevelOffset += sizeof(llvm::object::coff_resource_data_entry); + NextLevelOffset += sizeof(coff_resource_data_entry); DataEntriesTreeOrder.push_back(Child.second.get()); } else { Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); - NextLevelOffset += sizeof(llvm::object::coff_resource_dir_table) + + NextLevelOffset += sizeof(coff_resource_dir_table) + (Child.second->getStringChildren().size() + Child.second->getIDChildren().size()) * - sizeof(llvm::object::coff_resource_dir_entry); + sizeof(coff_resource_dir_entry); Queue.push(Child.second.get()); } - CurrentOffset += sizeof(llvm::object::coff_resource_dir_entry); - CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry); + CurrentOffset += sizeof(coff_resource_dir_entry); + CurrentRelativeOffset += sizeof(coff_resource_dir_entry); } for (auto const &Child : IDChildren) { - auto *Entry = reinterpret_cast( - BufferStart + CurrentOffset); + auto *Entry = reinterpret_cast(BufferStart + + CurrentOffset); Entry->Identifier.ID = Child.first; if (Child.second->checkIsDataNode()) { Entry->Offset.DataEntryOffset = NextLevelOffset; - NextLevelOffset += sizeof(llvm::object::coff_resource_data_entry); + NextLevelOffset += sizeof(coff_resource_data_entry); DataEntriesTreeOrder.push_back(Child.second.get()); } else { Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31); - NextLevelOffset += sizeof(llvm::object::coff_resource_dir_table) + + NextLevelOffset += sizeof(coff_resource_dir_table) + (Child.second->getStringChildren().size() + Child.second->getIDChildren().size()) * - sizeof(llvm::object::coff_resource_dir_entry); + sizeof(coff_resource_dir_entry); Queue.push(Child.second.get()); } - CurrentOffset += sizeof(llvm::object::coff_resource_dir_entry); - CurrentRelativeOffset += sizeof(llvm::object::coff_resource_dir_entry); + CurrentOffset += sizeof(coff_resource_dir_entry); + CurrentRelativeOffset += sizeof(coff_resource_dir_entry); } } RelocationAddresses.resize(Data.size()); // Now write all the resource data entries. for (auto DataNodes : DataEntriesTreeOrder) { - auto *Entry = reinterpret_cast( - BufferStart + CurrentOffset); + auto *Entry = reinterpret_cast(BufferStart + + CurrentOffset); RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset; Entry->DataRVA = 0; // Set to zero because it is a relocation. Entry->DataSize = Data[DataNodes->getDataIndex()].size(); Entry->Codepage = 0; Entry->Reserved = 0; - CurrentOffset += sizeof(llvm::object::coff_resource_data_entry); - CurrentRelativeOffset += sizeof(llvm::object::coff_resource_data_entry); + CurrentOffset += sizeof(coff_resource_data_entry); + CurrentRelativeOffset += sizeof(coff_resource_data_entry); } } @@ -710,33 +685,34 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { // .rsrc section. uint32_t NextSymbolIndex = 5; for (unsigned i = 0; i < Data.size(); i++) { - auto *Reloc = reinterpret_cast( - BufferStart + CurrentOffset); + auto *Reloc = + reinterpret_cast(BufferStart + CurrentOffset); Reloc->VirtualAddress = RelocationAddresses[i]; Reloc->SymbolTableIndex = NextSymbolIndex++; switch (MachineType) { - case Machine::ARM: - Reloc->Type = llvm::COFF::IMAGE_REL_ARM_ADDR32NB; + case COFF::IMAGE_FILE_MACHINE_ARMNT: + Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB; break; - case Machine::X64: - Reloc->Type = llvm::COFF::IMAGE_REL_AMD64_ADDR32NB; + case COFF::IMAGE_FILE_MACHINE_AMD64: + Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB; break; - case Machine::X86: - Reloc->Type = llvm::COFF::IMAGE_REL_I386_DIR32NB; + case COFF::IMAGE_FILE_MACHINE_I386: + Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB; break; default: Reloc->Type = 0; } - CurrentOffset += sizeof(llvm::object::coff_relocation); + CurrentOffset += sizeof(coff_relocation); } } -Error writeWindowsResourceCOFF(StringRef OutputFile, Machine MachineType, - const WindowsResourceParser &Parser) { +Expected> +writeWindowsResourceCOFF(COFF::MachineTypes MachineType, + const WindowsResourceParser &Parser) { Error E = Error::success(); - WindowsResourceCOFFWriter Writer(OutputFile, MachineType, Parser, E); + WindowsResourceCOFFWriter Writer(MachineType, Parser, E); if (E) - return E; + return std::move(E); return Writer.write(); } diff --git a/contrib/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp b/contrib/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp index ba3a2abe2097..83f3d55b8e55 100644 --- a/contrib/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp +++ b/contrib/llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp @@ -40,6 +40,7 @@ LLVM_YAML_DECLARE_ENUM_TRAITS(FrameCookieKind) LLVM_YAML_DECLARE_BITSET_TRAITS(CompileSym2Flags) LLVM_YAML_DECLARE_BITSET_TRAITS(CompileSym3Flags) LLVM_YAML_DECLARE_BITSET_TRAITS(ExportFlags) +LLVM_YAML_DECLARE_BITSET_TRAITS(PublicSymFlags) LLVM_YAML_DECLARE_BITSET_TRAITS(LocalSymFlags) LLVM_YAML_DECLARE_BITSET_TRAITS(ProcSymFlags) LLVM_YAML_DECLARE_BITSET_TRAITS(FrameProcedureOptions) @@ -93,6 +94,14 @@ void ScalarBitSetTraits::bitset(IO &io, ExportFlags &Flags) { } } +void ScalarBitSetTraits::bitset(IO &io, PublicSymFlags &Flags) { + auto FlagNames = getProcSymFlagNames(); + for (const auto &E : FlagNames) { + io.bitSetCase(Flags, E.Name.str().c_str(), + static_cast(E.Value)); + } +} + void ScalarBitSetTraits::bitset(IO &io, LocalSymFlags &Flags) { auto FlagNames = getLocalFlagNames(); for (const auto &E : FlagNames) { @@ -277,16 +286,15 @@ template <> void SymbolRecordImpl::map(IO &IO) { } template <> void SymbolRecordImpl::map(IO &IO) { - // TODO: Print the linkage name - - IO.mapRequired("PtrParent", Symbol.Parent); - IO.mapRequired("PtrEnd", Symbol.End); - IO.mapRequired("PtrNext", Symbol.Next); + IO.mapOptional("PtrParent", Symbol.Parent, 0U); + IO.mapOptional("PtrEnd", Symbol.End, 0U); + IO.mapOptional("PtrNext", Symbol.Next, 0U); IO.mapRequired("CodeSize", Symbol.CodeSize); IO.mapRequired("DbgStart", Symbol.DbgStart); IO.mapRequired("DbgEnd", Symbol.DbgEnd); IO.mapRequired("FunctionType", Symbol.FunctionType); - IO.mapRequired("Segment", Symbol.Segment); + IO.mapOptional("Offset", Symbol.CodeOffset, 0U); + IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("DisplayName", Symbol.Name); } @@ -298,9 +306,9 @@ template <> void SymbolRecordImpl::map(IO &IO) { } template <> void SymbolRecordImpl::map(IO &IO) { - IO.mapRequired("Type", Symbol.Index); - IO.mapRequired("Seg", Symbol.Segment); - IO.mapRequired("Off", Symbol.Offset); + IO.mapRequired("Flags", Symbol.Flags); + IO.mapOptional("Offset", Symbol.Offset, 0U); + IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Name", Symbol.Name); } @@ -316,8 +324,8 @@ template <> void SymbolRecordImpl::map(IO &IO) { } template <> void SymbolRecordImpl::map(IO &IO) { - IO.mapRequired("PtrParent", Symbol.Parent); - IO.mapRequired("PtrEnd", Symbol.End); + IO.mapOptional("PtrParent", Symbol.Parent, 0U); + IO.mapOptional("PtrEnd", Symbol.End, 0U); IO.mapRequired("Inlinee", Symbol.Inlinee); // TODO: The binary annotations } @@ -359,17 +367,17 @@ template <> void SymbolRecordImpl::map(IO &IO) { } template <> void SymbolRecordImpl::map(IO &IO) { - // TODO: Print the linkage name - IO.mapRequired("PtrParent", Symbol.Parent); - IO.mapRequired("PtrEnd", Symbol.End); + IO.mapOptional("PtrParent", Symbol.Parent, 0U); + IO.mapOptional("PtrEnd", Symbol.End, 0U); IO.mapRequired("CodeSize", Symbol.CodeSize); - IO.mapRequired("Segment", Symbol.Segment); + IO.mapOptional("Offset", Symbol.CodeOffset, 0U); + IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("BlockName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { - // TODO: Print the linkage name - IO.mapRequired("Segment", Symbol.Segment); + IO.mapOptional("Offset", Symbol.CodeOffset, 0U); + IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("DisplayName", Symbol.Name); @@ -419,8 +427,8 @@ template <> void SymbolRecordImpl::map(IO &IO) { } template <> void SymbolRecordImpl::map(IO &IO) { - // TODO: Map Linkage Name - IO.mapRequired("Segment", Symbol.Segment); + IO.mapOptional("Offset", Symbol.CodeOffset, 0U); + IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Type", Symbol.Type); } @@ -432,14 +440,13 @@ template <> void SymbolRecordImpl::map(IO &IO) { } template <> void SymbolRecordImpl::map(IO &IO) { - // TODO: Map Linkage Name - IO.mapRequired("Segment", Symbol.Segment); + IO.mapOptional("Offset", Symbol.CodeOffset, 0U); + IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("CallInstructionSize", Symbol.CallInstructionSize); IO.mapRequired("Type", Symbol.Type); } template <> void SymbolRecordImpl::map(IO &IO) { - // TODO: Map Linkage Name IO.mapRequired("Register", Symbol.Register); IO.mapRequired("CookieKind", Symbol.CookieKind); IO.mapRequired("Flags", Symbol.Flags); @@ -478,14 +485,16 @@ template <> void SymbolRecordImpl::map(IO &IO) { } template <> void SymbolRecordImpl::map(IO &IO) { - // TODO: Map linkage name IO.mapRequired("Type", Symbol.Type); + IO.mapOptional("Offset", Symbol.DataOffset, 0U); + IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("DisplayName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { - // TODO: Map linkage name IO.mapRequired("Type", Symbol.Type); + IO.mapOptional("Offset", Symbol.DataOffset, 0U); + IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("DisplayName", Symbol.Name); } } diff --git a/contrib/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp b/contrib/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp index a03b9cd50faa..2d1cb4b1b27b 100644 --- a/contrib/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp +++ b/contrib/llvm/lib/ObjectYAML/CodeViewYAMLTypes.cpp @@ -138,7 +138,7 @@ StringRef ScalarTraits::input(StringRef Scalar, void *Ctx, void ScalarTraits::output(const APSInt &S, void *, llvm::raw_ostream &OS) { - S.print(OS, true); + S.print(OS, S.isSigned()); } StringRef ScalarTraits::input(StringRef Scalar, void *Ctx, APSInt &S) { diff --git a/contrib/llvm/lib/ObjectYAML/WasmYAML.cpp b/contrib/llvm/lib/ObjectYAML/WasmYAML.cpp index 353d027f4e11..65703c6cf683 100644 --- a/contrib/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/contrib/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -47,14 +47,22 @@ static void commonSectionMapping(IO &IO, WasmYAML::Section &Section) { IO.mapOptional("Relocations", Section.Relocations); } +static void sectionMapping(IO &IO, WasmYAML::NameSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Name", Section.Name); + IO.mapOptional("FunctionNames", Section.FunctionNames); +} + +static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) { + commonSectionMapping(IO, Section); + IO.mapRequired("Name", Section.Name); + IO.mapRequired("SymbolInfo", Section.SymbolInfos); +} + static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) { commonSectionMapping(IO, Section); IO.mapRequired("Name", Section.Name); - if (Section.Name == "name") { - IO.mapOptional("FunctionNames", Section.FunctionNames); - } else { - IO.mapRequired("Payload", Section.Payload); - } + IO.mapRequired("Payload", Section.Payload); } static void sectionMapping(IO &IO, WasmYAML::TypeSection &Section) { @@ -121,11 +129,29 @@ void MappingTraits>::mapping( IO.mapRequired("Type", SectionType); switch (SectionType) { - case wasm::WASM_SEC_CUSTOM: - if (!IO.outputting()) - Section.reset(new WasmYAML::CustomSection()); - sectionMapping(IO, *cast(Section.get())); + case wasm::WASM_SEC_CUSTOM: { + StringRef SectionName; + if (IO.outputting()) { + auto CustomSection = cast(Section.get()); + SectionName = CustomSection->Name; + } else { + IO.mapRequired("Name", SectionName); + } + if (SectionName == "linking") { + if (!IO.outputting()) + Section.reset(new WasmYAML::LinkingSection()); + sectionMapping(IO, *cast(Section.get())); + } else if (SectionName == "name") { + if (!IO.outputting()) + Section.reset(new WasmYAML::NameSection()); + sectionMapping(IO, *cast(Section.get())); + } else { + if (!IO.outputting()) + Section.reset(new WasmYAML::CustomSection(SectionName)); + sectionMapping(IO, *cast(Section.get())); + } break; + } case wasm::WASM_SEC_TYPE: if (!IO.outputting()) Section.reset(new WasmYAML::TypeSection()); @@ -321,6 +347,12 @@ void MappingTraits::mapping( IO.mapRequired("Content", Segment.Content); } +void MappingTraits::mapping(IO &IO, + WasmYAML::SymbolInfo &Info) { + IO.mapRequired("Name", Info.Name); + IO.mapRequired("Flags", Info.Flags); +} + void ScalarEnumerationTraits::enumeration( IO &IO, WasmYAML::ValueType &Type) { #define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); diff --git a/contrib/llvm/lib/Option/OptTable.cpp b/contrib/llvm/lib/Option/OptTable.cpp index 52a81ff0e159..acb9e8d015bc 100644 --- a/contrib/llvm/lib/Option/OptTable.cpp +++ b/contrib/llvm/lib/Option/OptTable.cpp @@ -194,6 +194,37 @@ static unsigned matchOption(const OptTable::Info *I, StringRef Str, return 0; } +// Returns true if one of the Prefixes + In.Names matches Option +static bool optionMatches(const OptTable::Info &In, StringRef Option) { + if (In.Values && In.Prefixes) + for (size_t I = 0; In.Prefixes[I]; I++) + if (Option == std::string(In.Prefixes[I]) + In.Name) + return true; + return false; +} + +// This function is for flag value completion. +// Eg. When "-stdlib=" and "l" was passed to this function, it will return +// appropiriate values for stdlib, which starts with l. +std::vector +OptTable::suggestValueCompletions(StringRef Option, StringRef Arg) const { + // Search all options and return possible values. + for (const Info &In : OptionInfos.slice(FirstSearchableIndex)) { + if (!optionMatches(In, Option)) + continue; + + SmallVector Candidates; + StringRef(In.Values).split(Candidates, ",", -1, false); + + std::vector Result; + for (StringRef Val : Candidates) + if (Val.startswith(Arg)) + Result.push_back(Val); + return Result; + } + return {}; +} + std::vector OptTable::findByPrefix(StringRef Cur) const { std::vector Ret; for (const Info &In : OptionInfos.slice(FirstSearchableIndex)) { @@ -336,6 +367,9 @@ static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { case Option::FlagClass: break; + case Option::ValuesClass: + break; + case Option::SeparateClass: case Option::JoinedOrSeparateClass: case Option::RemainingArgsClass: case Option::RemainingArgsJoinedClass: Name += ' '; diff --git a/contrib/llvm/lib/Option/Option.cpp b/contrib/llvm/lib/Option/Option.cpp index 4832e659f026..bf9f040bde52 100644 --- a/contrib/llvm/lib/Option/Option.cpp +++ b/contrib/llvm/lib/Option/Option.cpp @@ -47,6 +47,7 @@ void Option::print(raw_ostream &O) const { P(UnknownClass); P(FlagClass); P(JoinedClass); + P(ValuesClass); P(SeparateClass); P(CommaJoinedClass); P(MultiArgClass); diff --git a/contrib/llvm/lib/Passes/PassBuilder.cpp b/contrib/llvm/lib/Passes/PassBuilder.cpp index afd66f55720a..78d5ea955e64 100644 --- a/contrib/llvm/lib/Passes/PassBuilder.cpp +++ b/contrib/llvm/lib/Passes/PassBuilder.cpp @@ -464,10 +464,15 @@ static void addPGOInstrPasses(ModulePassManager &MPM, bool DebugLogging, if (RunProfileGen) { MPM.addPass(PGOInstrumentationGen()); + FunctionPassManager FPM; + FPM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass())); + MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); + // Add the profile lowering pass. InstrProfOptions Options; if (!ProfileGenFile.empty()) Options.InstrProfileOutput = ProfileGenFile; + Options.DoCounterPromotion = true; MPM.addPass(InstrProfiling(Options)); } @@ -923,9 +928,6 @@ ModulePassManager PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level, MainFPM.add(AlignmentFromAssumptionsPass()); #endif - // FIXME: Conditionally run LoadCombine here, after it's ported - // (in case we still have this pass, given its questionable usefulness). - // FIXME: add peephole extensions to the PM here. MainFPM.addPass(InstCombinePass()); MainFPM.addPass(JumpThreadingPass()); diff --git a/contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 015b3c6c2021..4534e086b39e 100644 --- a/contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/contrib/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -1,4 +1,4 @@ -//===- CoverageMapping.cpp - Code coverage mapping support ------*- C++ -*-===// +//===- CoverageMapping.cpp - Code coverage mapping support ----------------===// // // The LLVM Compiler Infrastructure // @@ -200,6 +200,9 @@ Error CoverageMapping::loadFunctionRecord( const CoverageMappingRecord &Record, IndexedInstrProfReader &ProfileReader) { StringRef OrigFuncName = Record.FunctionName; + if (OrigFuncName.empty()) + return make_error(coveragemap_error::malformed); + if (Record.Filenames.empty()) OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName); else @@ -300,8 +303,8 @@ namespace { /// An instantiation set is a collection of functions that have the same source /// code, ie, template functions specializations. class FunctionInstantiationSetCollector { - typedef DenseMap, - std::vector> MapT; + using MapT = DenseMap, + std::vector>; MapT InstantiatedFunctions; public: @@ -315,7 +318,6 @@ class FunctionInstantiationSetCollector { } MapT::iterator begin() { return InstantiatedFunctions.begin(); } - MapT::iterator end() { return InstantiatedFunctions.end(); } }; diff --git a/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp index a34f359cd542..fff0a03ccbe0 100644 --- a/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/contrib/llvm/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -1,4 +1,4 @@ -//===- CoverageMappingReader.cpp - Code coverage mapping reader -*- C++ -*-===// +//===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===// // // The LLVM Compiler Infrastructure // @@ -62,7 +62,7 @@ void CoverageMappingIterator::increment() { } Error RawCoverageReader::readULEB128(uint64_t &Result) { - if (Data.size() < 1) + if (Data.empty()) return make_error(coveragemap_error::truncated); unsigned N = 0; Result = decodeULEB128(reinterpret_cast(Data.data()), &N); @@ -392,9 +392,9 @@ struct CovMapFuncRecordReader { // A class for reading coverage mapping function records for a module. template class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { - typedef typename CovMapTraits< - Version, IntPtrT>::CovMapFuncRecordType FuncRecordType; - typedef typename CovMapTraits::NameRefType NameRefType; + using FuncRecordType = + typename CovMapTraits::CovMapFuncRecordType; + using NameRefType = typename CovMapTraits::NameRefType; // Maps function's name references to the indexes of their records // in \c Records. @@ -419,6 +419,8 @@ class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { StringRef FuncName; if (Error Err = CFR->template getFuncName(ProfileNames, FuncName)) return Err; + if (FuncName.empty()) + return make_error(instrprof_error::malformed); Records.emplace_back(Version, FuncName, FuncHash, Mapping, FilenamesBegin, Filenames.size() - FilenamesBegin); return Error::success(); @@ -574,7 +576,7 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, Endian = support::endianness::little; Data = Data.substr(StringRef(TestingFormatMagic).size()); - if (Data.size() < 1) + if (Data.empty()) return make_error(coveragemap_error::truncated); unsigned N = 0; auto ProfileNamesSize = @@ -582,7 +584,7 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, if (N > Data.size()) return make_error(coveragemap_error::malformed); Data = Data.substr(N); - if (Data.size() < 1) + if (Data.empty()) return make_error(coveragemap_error::truncated); N = 0; uint64_t Address = @@ -596,7 +598,7 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, return E; CoverageMapping = Data.substr(ProfileNamesSize); // Skip the padding bytes because coverage map data has an alignment of 8. - if (CoverageMapping.size() < 1) + if (CoverageMapping.empty()) return make_error(coveragemap_error::truncated); size_t Pad = alignmentAdjustment(CoverageMapping.data(), 8); if (CoverageMapping.size() < Pad) diff --git a/contrib/llvm/lib/ProfileData/InstrProf.cpp b/contrib/llvm/lib/ProfileData/InstrProf.cpp index c9b82c303e33..005061c4f068 100644 --- a/contrib/llvm/lib/ProfileData/InstrProf.cpp +++ b/contrib/llvm/lib/ProfileData/InstrProf.cpp @@ -330,14 +330,15 @@ GlobalVariable *createPGOFuncNameVar(Function &F, StringRef PGOFuncName) { return createPGOFuncNameVar(*F.getParent(), F.getLinkage(), PGOFuncName); } -void InstrProfSymtab::create(Module &M, bool InLTO) { +Error InstrProfSymtab::create(Module &M, bool InLTO) { for (Function &F : M) { // Function may not have a name: like using asm("") to overwrite the name. // Ignore in this case. if (!F.hasName()) continue; const std::string &PGOFuncName = getPGOFuncName(F, InLTO); - addFuncName(PGOFuncName); + if (Error E = addFuncName(PGOFuncName)) + return E; MD5FuncMap.emplace_back(Function::getGUID(PGOFuncName), &F); // In ThinLTO, local function may have been promoted to global and have // suffix added to the function name. We need to add the stripped function @@ -346,13 +347,15 @@ void InstrProfSymtab::create(Module &M, bool InLTO) { auto pos = PGOFuncName.find('.'); if (pos != std::string::npos) { const std::string &OtherFuncName = PGOFuncName.substr(0, pos); - addFuncName(OtherFuncName); + if (Error E = addFuncName(OtherFuncName)) + return E; MD5FuncMap.emplace_back(Function::getGUID(OtherFuncName), &F); } } } finalizeSymtab(); + return Error::success(); } Error collectPGOFuncNameStrings(ArrayRef NameStrs, @@ -447,7 +450,8 @@ Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) { SmallVector Names; NameStrings.split(Names, getInstrProfNameSeparator()); for (StringRef &Name : Names) - Symtab.addFuncName(Name); + if (Error E = Symtab.addFuncName(Name)) + return E; while (P < EndP && *P == 0) P++; diff --git a/contrib/llvm/lib/ProfileData/InstrProfReader.cpp b/contrib/llvm/lib/ProfileData/InstrProfReader.cpp index d9f599f400da..1ed1fb8b6f0b 100644 --- a/contrib/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/contrib/llvm/lib/ProfileData/InstrProfReader.cpp @@ -200,7 +200,8 @@ TextInstrProfReader::readValueProfileData(InstrProfRecord &Record) { std::pair VD = Line->rsplit(':'); uint64_t TakenCount, Value; if (ValueKind == IPVK_IndirectCallTarget) { - Symtab->addFuncName(VD.first); + if (Error E = Symtab->addFuncName(VD.first)) + return E; Value = IndexedInstrProf::ComputeHash(VD.first); } else { READ_NUM(VD.first, Value); @@ -232,7 +233,8 @@ Error TextInstrProfReader::readNextRecord(InstrProfRecord &Record) { // Read the function name. Record.Name = *Line++; - Symtab->addFuncName(Record.Name); + if (Error E = Symtab->addFuncName(Record.Name)) + return E; // Read the function hash. if (Line.is_at_end()) @@ -482,8 +484,8 @@ InstrProfLookupTrait::ComputeHash(StringRef K) { return IndexedInstrProf::ComputeHash(HashType, K); } -typedef InstrProfLookupTrait::data_type data_type; -typedef InstrProfLookupTrait::offset_type offset_type; +using data_type = InstrProfLookupTrait::data_type; +using offset_type = InstrProfLookupTrait::offset_type; bool InstrProfLookupTrait::readValueProfilingData( const unsigned char *&D, const unsigned char *const End) { @@ -620,7 +622,7 @@ IndexedInstrProfReader::readSummary(IndexedInstrProf::ProfVersion Version, for (unsigned I = 0; I < SummarySize / sizeof(uint64_t); I++) Dst[I] = endian::byte_swap(Src[I]); - llvm::SummaryEntryVector DetailedSummary; + SummaryEntryVector DetailedSummary; for (unsigned I = 0; I < SummaryData->NumCutoffEntries; I++) { const IndexedInstrProf::Summary::Entry &Ent = SummaryData->getEntry(I); DetailedSummary.emplace_back((uint32_t)Ent.Cutoff, Ent.MinBlockCount, @@ -694,7 +696,9 @@ InstrProfSymtab &IndexedInstrProfReader::getSymtab() { return *Symtab.get(); std::unique_ptr NewSymtab = make_unique(); - Index->populateSymtab(*NewSymtab.get()); + if (Error E = Index->populateSymtab(*NewSymtab.get())) { + consumeError(error(InstrProfError::take(std::move(E)))); + } Symtab = std::move(NewSymtab); return *Symtab.get(); diff --git a/contrib/llvm/lib/ProfileData/InstrProfWriter.cpp b/contrib/llvm/lib/ProfileData/InstrProfWriter.cpp index b3402a6ea956..9efea78ed2a8 100644 --- a/contrib/llvm/lib/ProfileData/InstrProfWriter.cpp +++ b/contrib/llvm/lib/ProfileData/InstrProfWriter.cpp @@ -69,8 +69,7 @@ class ProfOStream { write(P[K].D[I]); } } else { - raw_string_ostream &SOStream = - static_cast(OS); + raw_string_ostream &SOStream = static_cast(OS); std::string &Data = SOStream.str(); // with flush for (int K = 0; K < NItems; K++) { for (int I = 0; I < P[K].N; I++) { @@ -91,14 +90,14 @@ class ProfOStream { class InstrProfRecordWriterTrait { public: - typedef StringRef key_type; - typedef StringRef key_type_ref; + using key_type = StringRef; + using key_type_ref = StringRef; - typedef const InstrProfWriter::ProfilingData *const data_type; - typedef const InstrProfWriter::ProfilingData *const data_type_ref; + using data_type = const InstrProfWriter::ProfilingData *const; + using data_type_ref = const InstrProfWriter::ProfilingData *const; - typedef uint64_t hash_value_type; - typedef uint64_t offset_type; + using hash_value_type = uint64_t; + using offset_type = uint64_t; support::endianness ValueProfDataEndianness = support::little; InstrProfSummaryBuilder *SummaryBuilder; @@ -363,17 +362,19 @@ void InstrProfWriter::writeRecordInText(const InstrProfRecord &Func, OS << "\n"; } -void InstrProfWriter::writeText(raw_fd_ostream &OS) { +Error InstrProfWriter::writeText(raw_fd_ostream &OS) { if (ProfileKind == PF_IRLevel) OS << "# IR level Instrumentation Flag\n:ir\n"; InstrProfSymtab Symtab; for (const auto &I : FunctionData) if (shouldEncodeData(I.getValue())) - Symtab.addFuncName(I.getKey()); + if (Error E = Symtab.addFuncName(I.getKey())) + return E; Symtab.finalizeSymtab(); for (const auto &I : FunctionData) if (shouldEncodeData(I.getValue())) for (const auto &Func : I.getValue()) writeRecordInText(Func.second, Symtab, OS); + return Error::success(); } diff --git a/contrib/llvm/lib/Support/APFloat.cpp b/contrib/llvm/lib/Support/APFloat.cpp index f36c25a0ce91..deb76cb565d1 100644 --- a/contrib/llvm/lib/Support/APFloat.cpp +++ b/contrib/llvm/lib/Support/APFloat.cpp @@ -37,10 +37,6 @@ using namespace llvm; -// TODO: Remove these and use APInt qualified types directly. -typedef APInt::WordType integerPart; -const unsigned int integerPartWidth = APInt::APINT_BITS_PER_WORD; - /// A macro used to combine two fcCategory enums into one key which can be used /// in a switch statement to classify how the interaction of two APFloat's /// categories affects an operation. @@ -51,7 +47,7 @@ const unsigned int integerPartWidth = APInt::APINT_BITS_PER_WORD; /* Assumed in hexadecimal significand parsing, and conversion to hexadecimal strings. */ -static_assert(integerPartWidth % 4 == 0, "Part width must be divisible by 4!"); +static_assert(APFloatBase::integerPartWidth % 4 == 0, "Part width must be divisible by 4!"); namespace llvm { /* Represents floating point arithmetic semantics. */ @@ -153,8 +149,7 @@ namespace llvm { const unsigned int maxExponent = 16383; const unsigned int maxPrecision = 113; const unsigned int maxPowerOfFiveExponent = maxExponent + maxPrecision - 1; - const unsigned int maxPowerOfFiveParts = 2 + ((maxPowerOfFiveExponent * 815) - / (351 * integerPartWidth)); + const unsigned int maxPowerOfFiveParts = 2 + ((maxPowerOfFiveExponent * 815) / (351 * APFloatBase::integerPartWidth)); unsigned int APFloatBase::semanticsPrecision(const fltSemantics &semantics) { return semantics.precision; @@ -180,7 +175,7 @@ namespace llvm { static inline unsigned int partCountForBits(unsigned int bits) { - return ((bits) + integerPartWidth - 1) / integerPartWidth; + return ((bits) + APFloatBase::integerPartWidth - 1) / APFloatBase::integerPartWidth; } /* Returns 0U-9U. Return values >= 10U are not digits. */ @@ -420,7 +415,7 @@ trailingHexadecimalFraction(StringRef::iterator p, StringRef::iterator end, /* Return the fraction lost were a bignum truncated losing the least significant BITS bits. */ static lostFraction -lostFractionThroughTruncation(const integerPart *parts, +lostFractionThroughTruncation(const APFloatBase::integerPart *parts, unsigned int partCount, unsigned int bits) { @@ -433,7 +428,7 @@ lostFractionThroughTruncation(const integerPart *parts, return lfExactlyZero; if (bits == lsb + 1) return lfExactlyHalf; - if (bits <= partCount * integerPartWidth && + if (bits <= partCount * APFloatBase::integerPartWidth && APInt::tcExtractBit(parts, bits - 1)) return lfMoreThanHalf; @@ -442,7 +437,7 @@ lostFractionThroughTruncation(const integerPart *parts, /* Shift DST right BITS bits noting lost fraction. */ static lostFraction -shiftRight(integerPart *dst, unsigned int parts, unsigned int bits) +shiftRight(APFloatBase::integerPart *dst, unsigned int parts, unsigned int bits) { lostFraction lost_fraction; @@ -489,22 +484,22 @@ HUerrBound(bool inexactMultiply, unsigned int HUerr1, unsigned int HUerr2) /* The number of ulps from the boundary (zero, or half if ISNEAREST) when the least significant BITS are truncated. BITS cannot be zero. */ -static integerPart -ulpsFromBoundary(const integerPart *parts, unsigned int bits, bool isNearest) -{ +static APFloatBase::integerPart +ulpsFromBoundary(const APFloatBase::integerPart *parts, unsigned int bits, + bool isNearest) { unsigned int count, partBits; - integerPart part, boundary; + APFloatBase::integerPart part, boundary; assert(bits != 0); bits--; - count = bits / integerPartWidth; - partBits = bits % integerPartWidth + 1; + count = bits / APFloatBase::integerPartWidth; + partBits = bits % APFloatBase::integerPartWidth + 1; - part = parts[count] & (~(integerPart) 0 >> (integerPartWidth - partBits)); + part = parts[count] & (~(APFloatBase::integerPart) 0 >> (APFloatBase::integerPartWidth - partBits)); if (isNearest) - boundary = (integerPart) 1 << (partBits - 1); + boundary = (APFloatBase::integerPart) 1 << (partBits - 1); else boundary = 0; @@ -518,32 +513,30 @@ ulpsFromBoundary(const integerPart *parts, unsigned int bits, bool isNearest) if (part == boundary) { while (--count) if (parts[count]) - return ~(integerPart) 0; /* A lot. */ + return ~(APFloatBase::integerPart) 0; /* A lot. */ return parts[0]; } else if (part == boundary - 1) { while (--count) if (~parts[count]) - return ~(integerPart) 0; /* A lot. */ + return ~(APFloatBase::integerPart) 0; /* A lot. */ return -parts[0]; } - return ~(integerPart) 0; /* A lot. */ + return ~(APFloatBase::integerPart) 0; /* A lot. */ } /* Place pow(5, power) in DST, and return the number of parts used. DST must be at least one part larger than size of the answer. */ static unsigned int -powerOf5(integerPart *dst, unsigned int power) -{ - static const integerPart firstEightPowers[] = { 1, 5, 25, 125, 625, 3125, - 15625, 78125 }; - integerPart pow5s[maxPowerOfFiveParts * 2 + 5]; +powerOf5(APFloatBase::integerPart *dst, unsigned int power) { + static const APFloatBase::integerPart firstEightPowers[] = { 1, 5, 25, 125, 625, 3125, 15625, 78125 }; + APFloatBase::integerPart pow5s[maxPowerOfFiveParts * 2 + 5]; pow5s[0] = 78125 * 5; unsigned int partsCount[16] = { 1 }; - integerPart scratch[maxPowerOfFiveParts], *p1, *p2, *pow5; + APFloatBase::integerPart scratch[maxPowerOfFiveParts], *p1, *p2, *pow5; unsigned int result; assert(power <= maxExponent); @@ -572,7 +565,7 @@ powerOf5(integerPart *dst, unsigned int power) } if (power & 1) { - integerPart *tmp; + APFloatBase::integerPart *tmp; APInt::tcFullMultiply(p2, p1, pow5, result, pc); result += pc; @@ -608,14 +601,14 @@ static const char NaNU[] = "NAN"; significant nibble. Write out exactly COUNT hexdigits, return COUNT. */ static unsigned int -partAsHex (char *dst, integerPart part, unsigned int count, +partAsHex (char *dst, APFloatBase::integerPart part, unsigned int count, const char *hexDigitChars) { unsigned int result = count; - assert(count != 0 && count <= integerPartWidth / 4); + assert(count != 0 && count <= APFloatBase::integerPartWidth / 4); - part >>= (integerPartWidth - 4 * count); + part >>= (APFloatBase::integerPartWidth - 4 * count); while (count--) { dst[count] = hexDigitChars[part & 0xf]; part >>= 4; @@ -889,11 +882,11 @@ unsigned int IEEEFloat::partCount() const { return partCountForBits(semantics->precision + 1); } -const integerPart *IEEEFloat::significandParts() const { +const IEEEFloat::integerPart *IEEEFloat::significandParts() const { return const_cast(this)->significandParts(); } -integerPart *IEEEFloat::significandParts() { +IEEEFloat::integerPart *IEEEFloat::significandParts() { if (partCount() > 1) return significand.parts; else @@ -916,7 +909,7 @@ void IEEEFloat::incrementSignificand() { } /* Add the significand of the RHS. Returns the carry flag. */ -integerPart IEEEFloat::addSignificand(const IEEEFloat &rhs) { +IEEEFloat::integerPart IEEEFloat::addSignificand(const IEEEFloat &rhs) { integerPart *parts; parts = significandParts(); @@ -929,8 +922,8 @@ integerPart IEEEFloat::addSignificand(const IEEEFloat &rhs) { /* Subtract the significand of the RHS with a borrow flag. Returns the borrow flag. */ -integerPart IEEEFloat::subtractSignificand(const IEEEFloat &rhs, - integerPart borrow) { +IEEEFloat::integerPart IEEEFloat::subtractSignificand(const IEEEFloat &rhs, + integerPart borrow) { integerPart *parts; parts = significandParts(); diff --git a/contrib/llvm/lib/Support/APInt.cpp b/contrib/llvm/lib/Support/APInt.cpp index e9716e3b1e87..c558ddd82161 100644 --- a/contrib/llvm/lib/Support/APInt.cpp +++ b/contrib/llvm/lib/Support/APInt.cpp @@ -546,10 +546,7 @@ unsigned APInt::countLeadingZerosSlowCase() const { return Count; } -unsigned APInt::countLeadingOnes() const { - if (isSingleWord()) - return llvm::countLeadingOnes(U.VAL << (APINT_BITS_PER_WORD - BitWidth)); - +unsigned APInt::countLeadingOnesSlowCase() const { unsigned highWordBits = BitWidth % APINT_BITS_PER_WORD; unsigned shift; if (!highWordBits) { @@ -573,9 +570,7 @@ unsigned APInt::countLeadingOnes() const { return Count; } -unsigned APInt::countTrailingZeros() const { - if (isSingleWord()) - return std::min(unsigned(llvm::countTrailingZeros(U.VAL)), BitWidth); +unsigned APInt::countTrailingZerosSlowCase() const { unsigned Count = 0; unsigned i = 0; for (; i < getNumWords() && U.pVal[i] == 0; ++i) diff --git a/contrib/llvm/lib/Support/BinaryStreamReader.cpp b/contrib/llvm/lib/Support/BinaryStreamReader.cpp index bfb658cfa0b7..e00527f2519e 100644 --- a/contrib/llvm/lib/Support/BinaryStreamReader.cpp +++ b/contrib/llvm/lib/Support/BinaryStreamReader.cpp @@ -109,6 +109,12 @@ Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) { return Error::success(); } +Error BinaryStreamReader::readSubstream(BinarySubstreamRef &Stream, + uint32_t Size) { + Stream.Offset = getOffset(); + return readStreamRef(Stream.StreamData, Size); +} + Error BinaryStreamReader::skip(uint32_t Amount) { if (Amount > bytesRemaining()) return make_error(stream_error_code::stream_too_short); diff --git a/contrib/llvm/lib/Support/CachePruning.cpp b/contrib/llvm/lib/Support/CachePruning.cpp index aca123639565..60d0964f2764 100644 --- a/contrib/llvm/lib/Support/CachePruning.cpp +++ b/contrib/llvm/lib/Support/CachePruning.cpp @@ -82,7 +82,7 @@ llvm::parseCachePruningPolicy(StringRef PolicyStr) { if (Value.back() != '%') return make_error("'" + Value + "' must be a percentage", inconvertibleErrorCode()); - StringRef SizeStr = Value.slice(0, Value.size() - 1); + StringRef SizeStr = Value.drop_back(); uint64_t Size; if (SizeStr.getAsInteger(0, Size)) return make_error("'" + SizeStr + "' not an integer", @@ -91,7 +91,28 @@ llvm::parseCachePruningPolicy(StringRef PolicyStr) { return make_error("'" + SizeStr + "' must be between 0 and 100", inconvertibleErrorCode()); - Policy.PercentageOfAvailableSpace = Size; + Policy.MaxSizePercentageOfAvailableSpace = Size; + } else if (Key == "cache_size_bytes") { + uint64_t Mult = 1; + switch (tolower(Value.back())) { + case 'k': + Mult = 1024; + Value = Value.drop_back(); + break; + case 'm': + Mult = 1024 * 1024; + Value = Value.drop_back(); + break; + case 'g': + Mult = 1024 * 1024 * 1024; + Value = Value.drop_back(); + break; + } + uint64_t Size; + if (Value.getAsInteger(0, Size)) + return make_error("'" + Value + "' not an integer", + inconvertibleErrorCode()); + Policy.MaxSizeBytes = Size * Mult; } else { return make_error("Unknown key: '" + Key + "'", inconvertibleErrorCode()); @@ -115,11 +136,12 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { if (!isPathDir) return false; - Policy.PercentageOfAvailableSpace = - std::min(Policy.PercentageOfAvailableSpace, 100u); + Policy.MaxSizePercentageOfAvailableSpace = + std::min(Policy.MaxSizePercentageOfAvailableSpace, 100u); if (Policy.Expiration == seconds(0) && - Policy.PercentageOfAvailableSpace == 0) { + Policy.MaxSizePercentageOfAvailableSpace == 0 && + Policy.MaxSizeBytes == 0) { DEBUG(dbgs() << "No pruning settings set, exit early\n"); // Nothing will be pruned, early exit return false; @@ -157,7 +179,8 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { writeTimestampFile(TimestampFile); } - bool ShouldComputeSize = (Policy.PercentageOfAvailableSpace > 0); + bool ShouldComputeSize = + (Policy.MaxSizePercentageOfAvailableSpace > 0 || Policy.MaxSizeBytes > 0); // Keep track of space std::set> FileSizes; @@ -216,14 +239,22 @@ bool llvm::pruneCache(StringRef Path, CachePruningPolicy Policy) { } sys::fs::space_info SpaceInfo = ErrOrSpaceInfo.get(); auto AvailableSpace = TotalSize + SpaceInfo.free; - auto FileAndSize = FileSizes.rbegin(); + + if (Policy.MaxSizePercentageOfAvailableSpace == 0) + Policy.MaxSizePercentageOfAvailableSpace = 100; + if (Policy.MaxSizeBytes == 0) + Policy.MaxSizeBytes = AvailableSpace; + auto TotalSizeTarget = std::min( + AvailableSpace * Policy.MaxSizePercentageOfAvailableSpace / 100ull, + Policy.MaxSizeBytes); + DEBUG(dbgs() << "Occupancy: " << ((100 * TotalSize) / AvailableSpace) - << "% target is: " << Policy.PercentageOfAvailableSpace - << "\n"); + << "% target is: " << Policy.MaxSizePercentageOfAvailableSpace + << "%, " << Policy.MaxSizeBytes << " bytes\n"); + + auto FileAndSize = FileSizes.rbegin(); // Remove the oldest accessed files first, till we get below the threshold - while (((100 * TotalSize) / AvailableSpace) > - Policy.PercentageOfAvailableSpace && - FileAndSize != FileSizes.rend()) { + while (TotalSize > TotalSizeTarget && FileAndSize != FileSizes.rend()) { // Remove the file. sys::fs::remove(FileAndSize->second); // Update size diff --git a/contrib/llvm/lib/Support/CommandLine.cpp b/contrib/llvm/lib/Support/CommandLine.cpp index de0ca940b405..0345a5e3d2a1 100644 --- a/contrib/llvm/lib/Support/CommandLine.cpp +++ b/contrib/llvm/lib/Support/CommandLine.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Config/config.h" @@ -1522,13 +1523,9 @@ bool parser::parse(Option &O, StringRef ArgName, // parser/parser implementation // static bool parseDouble(Option &O, StringRef Arg, double &Value) { - SmallString<32> TmpStr(Arg.begin(), Arg.end()); - const char *ArgStart = TmpStr.c_str(); - char *End; - Value = strtod(ArgStart, &End); - if (*End != 0) - return O.error("'" + Arg + "' value invalid for floating point argument!"); - return false; + if (to_float(Arg, Value)) + return false; + return O.error("'" + Arg + "' value invalid for floating point argument!"); } bool parser::parse(Option &O, StringRef ArgName, StringRef Arg, diff --git a/contrib/llvm/lib/Support/DataExtractor.cpp b/contrib/llvm/lib/Support/DataExtractor.cpp index 53c10bcc562e..0199b300ba72 100644 --- a/contrib/llvm/lib/Support/DataExtractor.cpp +++ b/contrib/llvm/lib/Support/DataExtractor.cpp @@ -68,6 +68,13 @@ uint16_t *DataExtractor::getU16(uint32_t *offset_ptr, uint16_t *dst, Data.data()); } +uint32_t DataExtractor::getU24(uint32_t *offset_ptr) const { + uint24_t ExtractedVal = + getU(offset_ptr, this, IsLittleEndian, Data.data()); + // The 3 bytes are in the correct byte order for the host. + return ExtractedVal.getAsUint32(sys::IsLittleEndianHost); +} + uint32_t DataExtractor::getU32(uint32_t *offset_ptr) const { return getU(offset_ptr, this, IsLittleEndian, Data.data()); } diff --git a/contrib/llvm/lib/Support/GraphWriter.cpp b/contrib/llvm/lib/Support/GraphWriter.cpp index f70b77da8de4..e04bd8bb3b9a 100644 --- a/contrib/llvm/lib/Support/GraphWriter.cpp +++ b/contrib/llvm/lib/Support/GraphWriter.cpp @@ -1,4 +1,4 @@ -//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===// +//===- GraphWriter.cpp - Implements GraphWriter support routines ----------===// // // The LLVM Compiler Infrastructure // @@ -12,10 +12,22 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/GraphWriter.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include + using namespace llvm; static cl::opt ViewBackground("view-background", cl::Hidden, @@ -99,8 +111,10 @@ static bool ExecGraphViewer(StringRef ExecPath, std::vector &args, } namespace { + struct GraphSession { std::string LogBuffer; + bool TryFindProgram(StringRef Names, std::string &ProgramPath) { raw_string_ostream Log(LogBuffer); SmallVector parts; @@ -115,7 +129,8 @@ struct GraphSession { return false; } }; -} // namespace + +} // end anonymous namespace static const char *getProgramName(GraphProgram::Name program) { switch (program) { diff --git a/contrib/llvm/lib/Support/Triple.cpp b/contrib/llvm/lib/Support/Triple.cpp index 320aede79fbb..2687a67556d3 100644 --- a/contrib/llvm/lib/Support/Triple.cpp +++ b/contrib/llvm/lib/Support/Triple.cpp @@ -174,6 +174,7 @@ StringRef Triple::getOSTypeName(OSType Kind) { switch (Kind) { case UnknownOS: return "unknown"; + case Ananas: return "ananas"; case CloudABI: return "cloudabi"; case Darwin: return "darwin"; case DragonFly: return "dragonfly"; @@ -455,6 +456,7 @@ static Triple::VendorType parseVendor(StringRef VendorName) { static Triple::OSType parseOS(StringRef OSName) { return StringSwitch(OSName) + .StartsWith("ananas", Triple::Ananas) .StartsWith("cloudabi", Triple::CloudABI) .StartsWith("darwin", Triple::Darwin) .StartsWith("dragonfly", Triple::DragonFly) diff --git a/contrib/llvm/lib/Support/Unix/Host.inc b/contrib/llvm/lib/Support/Unix/Host.inc index 457217125a22..0ba6a25aa198 100644 --- a/contrib/llvm/lib/Support/Unix/Host.inc +++ b/contrib/llvm/lib/Support/Unix/Host.inc @@ -45,5 +45,11 @@ std::string sys::getDefaultTargetTriple() { TargetTripleString += getOSVersion(); } + // Override the default target with an environment variable named by LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) + if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) + TargetTripleString = EnvTriple; +#endif + return Triple::normalize(TargetTripleString); } diff --git a/contrib/llvm/lib/Support/Unix/Memory.inc b/contrib/llvm/lib/Support/Unix/Memory.inc index edbc7938f0cb..dd39ef935bf9 100644 --- a/contrib/llvm/lib/Support/Unix/Memory.inc +++ b/contrib/llvm/lib/Support/Unix/Memory.inc @@ -195,6 +195,10 @@ Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__)) void *pa = ::mmap(start, PageSize*NumPages, PROT_READ|PROT_EXEC, flags, fd, 0); +#elif defined(__NetBSD__) && defined(PROT_MPROTECT) + void *pa = + ::mmap(start, PageSize * NumPages, + PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC), flags, fd, 0); #else void *pa = ::mmap(start, PageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, flags, fd, 0); diff --git a/contrib/llvm/lib/Support/Unix/Program.inc b/contrib/llvm/lib/Support/Unix/Program.inc index 2df0eaff47e5..1704fa479942 100644 --- a/contrib/llvm/lib/Support/Unix/Program.inc +++ b/contrib/llvm/lib/Support/Unix/Program.inc @@ -449,11 +449,22 @@ bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program, ArrayRef::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { - ArgLength += strlen(*I) + 1; + size_t length = strlen(*I); + + // Ensure that we do not exceed the MAX_ARG_STRLEN constant on Linux, which + // does not have a constant unlike what the man pages would have you + // believe. Since this limit is pretty high, perform the check + // unconditionally rather than trying to be aggressive and limiting it to + // Linux only. + if (length >= (32 * 4096)) + return false; + + ArgLength += length + 1; if (ArgLength > size_t(HalfArgMax)) { return false; } } + return true; } } diff --git a/contrib/llvm/lib/Support/Windows/Host.inc b/contrib/llvm/lib/Support/Windows/Host.inc index fe89fe0aad8c..7e196cf0ce18 100644 --- a/contrib/llvm/lib/Support/Windows/Host.inc +++ b/contrib/llvm/lib/Support/Windows/Host.inc @@ -18,5 +18,13 @@ using namespace llvm; std::string sys::getDefaultTargetTriple() { - return Triple::normalize(LLVM_DEFAULT_TARGET_TRIPLE); + const char *Triple = LLVM_DEFAULT_TARGET_TRIPLE; + + // Override the default target with an environment variable named by LLVM_TARGET_TRIPLE_ENV. +#if defined(LLVM_TARGET_TRIPLE_ENV) + if (const char *EnvTriple = std::getenv(LLVM_TARGET_TRIPLE_ENV)) + Triple = EnvTriple; +#endif + + return Triple::normalize(Triple); } diff --git a/contrib/llvm/lib/Support/YAMLParser.cpp b/contrib/llvm/lib/Support/YAMLParser.cpp index 01ae3214453d..e2f21a56a810 100644 --- a/contrib/llvm/lib/Support/YAMLParser.cpp +++ b/contrib/llvm/lib/Support/YAMLParser.cpp @@ -1,4 +1,4 @@ -//===--- YAMLParser.cpp - Simple YAML parser ------------------------------===// +//===- YAMLParser.cpp - Simple YAML parser --------------------------------===// // // The LLVM Compiler Infrastructure // @@ -13,15 +13,29 @@ #include "llvm/Support/YAMLParser.h" #include "llvm/ADT/AllocatorList.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace llvm; using namespace yaml; @@ -37,7 +51,7 @@ enum UnicodeEncodingForm { /// EncodingInfo - Holds the encoding type and length of the byte order mark if /// it exists. Length is in {0, 2, 3, 4}. -typedef std::pair EncodingInfo; +using EncodingInfo = std::pair; /// getUnicodeEncoding - Reads up to the first 4 bytes to determine the Unicode /// encoding form of \a Input. @@ -46,7 +60,7 @@ typedef std::pair EncodingInfo; /// @returns An EncodingInfo indicating the Unicode encoding form of the input /// and how long the byte order mark is if one exists. static EncodingInfo getUnicodeEncoding(StringRef Input) { - if (Input.size() == 0) + if (Input.empty()) return std::make_pair(UEF_Unknown, 0); switch (uint8_t(Input[0])) { @@ -95,8 +109,6 @@ static EncodingInfo getUnicodeEncoding(StringRef Input) { return std::make_pair(UEF_UTF8, 0); } -namespace llvm { -namespace yaml { /// Pin the vtables to this file. void Node::anchor() {} void NullNode::anchor() {} @@ -107,6 +119,9 @@ void MappingNode::anchor() {} void SequenceNode::anchor() {} void AliasNode::anchor() {} +namespace llvm { +namespace yaml { + /// Token - A single YAML token. struct Token { enum TokenKind { @@ -133,7 +148,7 @@ struct Token { TK_Alias, TK_Anchor, TK_Tag - } Kind; + } Kind = TK_Error; /// A string of length 0 or more whose begin() points to the logical location /// of the token in the input. @@ -142,14 +157,16 @@ struct Token { /// The value of a block scalar node. std::string Value; - Token() : Kind(TK_Error) {} + Token() = default; }; -} -} -typedef llvm::BumpPtrList TokenQueueT; +} // end namespace yaml +} // end namespace llvm + +using TokenQueueT = BumpPtrList; namespace { + /// @brief This struct is used to track simple keys. /// /// Simple keys are handled by creating an entry in SimpleKeys for each Token @@ -170,12 +187,13 @@ struct SimpleKey { return Tok == Other.Tok; } }; -} + +} // end anonymous namespace /// @brief The Unicode scalar value of a UTF-8 minimal well-formed code unit /// subsequence and the subsequence's length in code units (uint8_t). /// A length of 0 represents an error. -typedef std::pair UTF8Decoded; +using UTF8Decoded = std::pair; static UTF8Decoded decodeUTF8(StringRef Range) { StringRef::iterator Position= Range.begin(); @@ -229,6 +247,7 @@ static UTF8Decoded decodeUTF8(StringRef Range) { namespace llvm { namespace yaml { + /// @brief Scans YAML tokens from a MemoryBuffer. class Scanner { public: @@ -350,7 +369,8 @@ class Scanner { /// ns-char. StringRef::iterator skip_ns_char(StringRef::iterator Position); - typedef StringRef::iterator (Scanner::*SkipWhileFunc)(StringRef::iterator); + using SkipWhileFunc = StringRef::iterator (Scanner::*)(StringRef::iterator); + /// @brief Skip minimal well-formed code unit subsequences until Func /// returns its input. /// @@ -655,10 +675,10 @@ bool yaml::dumpTokens(StringRef Input, raw_ostream &OS) { } bool yaml::scanTokens(StringRef Input) { - llvm::SourceMgr SM; - llvm::yaml::Scanner scanner(Input, SM); - for (;;) { - llvm::yaml::Token T = scanner.getNext(); + SourceMgr SM; + Scanner scanner(Input, SM); + while (true) { + Token T = scanner.getNext(); if (T.Kind == Token::TK_StreamEnd) break; else if (T.Kind == Token::TK_Error) @@ -1744,7 +1764,7 @@ Stream::Stream(MemoryBufferRef InputBuffer, SourceMgr &SM, bool ShowColors, std::error_code *EC) : scanner(new Scanner(InputBuffer, SM, ShowColors, EC)), CurrentDoc() {} -Stream::~Stream() {} +Stream::~Stream() = default; bool Stream::failed() { return scanner->failed(); } @@ -1851,8 +1871,6 @@ bool Node::failed() const { return Doc->failed(); } - - StringRef ScalarNode::getValue(SmallVectorImpl &Storage) const { // TODO: Handle newlines properly. We need to remove leading whitespace. if (Value[0] == '"') { // Double quoted. diff --git a/contrib/llvm/lib/Support/YAMLTraits.cpp b/contrib/llvm/lib/Support/YAMLTraits.cpp index c410b1d56086..601084f9eae3 100644 --- a/contrib/llvm/lib/Support/YAMLTraits.cpp +++ b/contrib/llvm/lib/Support/YAMLTraits.cpp @@ -8,17 +8,27 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/YAMLTraits.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/LineIterator.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" -#include +#include +#include +#include +#include #include +#include +#include + using namespace llvm; using namespace yaml; @@ -26,11 +36,9 @@ using namespace yaml; // IO //===----------------------------------------------------------------------===// -IO::IO(void *Context) : Ctxt(Context) { -} +IO::IO(void *Context) : Ctxt(Context) {} -IO::~IO() { -} +IO::~IO() = default; void *IO::getContext() { return Ctxt; @@ -46,15 +54,13 @@ void IO::setContext(void *Context) { Input::Input(StringRef InputContent, void *Ctxt, SourceMgr::DiagHandlerTy DiagHandler, void *DiagHandlerCtxt) - : IO(Ctxt), Strm(new Stream(InputContent, SrcMgr, false, &EC)), - CurrentNode(nullptr) { + : IO(Ctxt), Strm(new Stream(InputContent, SrcMgr, false, &EC)) { if (DiagHandler) SrcMgr.setDiagHandler(DiagHandler, DiagHandlerCtxt); DocIterator = Strm->begin(); } -Input::~Input() { -} +Input::~Input() = default; std::error_code Input::error() { return EC; } @@ -398,13 +404,9 @@ bool Input::canElideEmptySequence() { //===----------------------------------------------------------------------===// Output::Output(raw_ostream &yout, void *context, int WrapColumn) - : IO(context), Out(yout), WrapColumn(WrapColumn), Column(0), - ColumnAtFlowStart(0), ColumnAtMapFlowStart(0), NeedBitValueComma(false), - NeedFlowSequenceComma(false), EnumerationMatchFound(false), - NeedsNewLine(false), WriteDefaultValues(false) {} + : IO(context), Out(yout), WrapColumn(WrapColumn) {} -Output::~Output() { -} +Output::~Output() = default; bool Output::outputting() { return true; @@ -911,12 +913,9 @@ void ScalarTraits::output(const double &Val, void *, raw_ostream &Out) { } StringRef ScalarTraits::input(StringRef Scalar, void *, double &Val) { - SmallString<32> buff(Scalar.begin(), Scalar.end()); - char *end; - Val = strtod(buff.c_str(), &end); - if (*end != '\0') - return "invalid floating point number"; - return StringRef(); + if (to_float(Scalar, Val)) + return StringRef(); + return "invalid floating point number"; } void ScalarTraits::output(const float &Val, void *, raw_ostream &Out) { @@ -924,12 +923,9 @@ void ScalarTraits::output(const float &Val, void *, raw_ostream &Out) { } StringRef ScalarTraits::input(StringRef Scalar, void *, float &Val) { - SmallString<32> buff(Scalar.begin(), Scalar.end()); - char *end; - Val = strtod(buff.c_str(), &end); - if (*end != '\0') - return "invalid floating point number"; - return StringRef(); + if (to_float(Scalar, Val)) + return StringRef(); + return "invalid floating point number"; } void ScalarTraits::output(const Hex8 &Val, void *, raw_ostream &Out) { diff --git a/contrib/llvm/lib/Support/raw_ostream.cpp b/contrib/llvm/lib/Support/raw_ostream.cpp index 1abc8ed8683d..9480cd46d28f 100644 --- a/contrib/llvm/lib/Support/raw_ostream.cpp +++ b/contrib/llvm/lib/Support/raw_ostream.cpp @@ -548,7 +548,11 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { pos += Size; #ifndef LLVM_ON_WIN32 +#if defined(__linux__) + bool ShouldWriteInChunks = true; +#else bool ShouldWriteInChunks = false; +#endif #else // Writing a large size of output to Windows console returns ENOMEM. It seems // that, prior to Windows 8, WriteFile() is redirecting to WriteConsole(), and diff --git a/contrib/llvm/lib/Target/AArch64/AArch64.h b/contrib/llvm/lib/Target/AArch64/AArch64.h index 3e0e3978b90b..37b9690d0434 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64.h +++ b/contrib/llvm/lib/Target/AArch64/AArch64.h @@ -31,6 +31,7 @@ class MachineFunctionPass; FunctionPass *createAArch64DeadRegisterDefinitions(); FunctionPass *createAArch64RedundantCopyEliminationPass(); +FunctionPass *createAArch64CondBrTuning(); FunctionPass *createAArch64ConditionalCompares(); FunctionPass *createAArch64AdvSIMDScalar(); FunctionPass *createAArch64ISelDag(AArch64TargetMachine &TM, @@ -55,6 +56,7 @@ void initializeAArch64A53Fix835769Pass(PassRegistry&); void initializeAArch64A57FPLoadBalancingPass(PassRegistry&); void initializeAArch64AdvSIMDScalarPass(PassRegistry&); void initializeAArch64CollectLOHPass(PassRegistry&); +void initializeAArch64CondBrTuningPass(PassRegistry &); void initializeAArch64ConditionalComparesPass(PassRegistry&); void initializeAArch64ConditionOptimizerPass(PassRegistry&); void initializeAArch64DeadRegisterDefinitionsPass(PassRegistry&); diff --git a/contrib/llvm/lib/Target/AArch64/AArch64CondBrTuning.cpp b/contrib/llvm/lib/Target/AArch64/AArch64CondBrTuning.cpp new file mode 100644 index 000000000000..f27bc97ec3f3 --- /dev/null +++ b/contrib/llvm/lib/Target/AArch64/AArch64CondBrTuning.cpp @@ -0,0 +1,336 @@ +//===-- AArch64CondBrTuning.cpp --- Conditional branch tuning for AArch64 -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This file contains a pass that transforms CBZ/CBNZ/TBZ/TBNZ instructions +/// into a conditional branch (B.cond), when the NZCV flags can be set for +/// "free". This is preferred on targets that have more flexibility when +/// scheduling B.cond instructions as compared to CBZ/CBNZ/TBZ/TBNZ (assuming +/// all other variables are equal). This can also reduce register pressure. +/// +/// A few examples: +/// +/// 1) add w8, w0, w1 -> cmn w0, w1 ; CMN is an alias of ADDS. +/// cbz w8, .LBB_2 -> b.eq .LBB0_2 +/// +/// 2) add w8, w0, w1 -> adds w8, w0, w1 ; w8 has multiple uses. +/// cbz w8, .LBB1_2 -> b.eq .LBB1_2 +/// +/// 3) sub w8, w0, w1 -> subs w8, w0, w1 ; w8 has multiple uses. +/// tbz w8, #31, .LBB6_2 -> b.ge .LBB6_2 +/// +//===----------------------------------------------------------------------===// + +#include "AArch64.h" +#include "AArch64Subtarget.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/MachineTraceMetrics.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSubtargetInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "aarch64-cond-br-tuning" +#define AARCH64_CONDBR_TUNING_NAME "AArch64 Conditional Branch Tuning" + +namespace { +class AArch64CondBrTuning : public MachineFunctionPass { + const AArch64InstrInfo *TII; + const TargetRegisterInfo *TRI; + + MachineRegisterInfo *MRI; + +public: + static char ID; + AArch64CondBrTuning() : MachineFunctionPass(ID) { + initializeAArch64CondBrTuningPass(*PassRegistry::getPassRegistry()); + } + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool runOnMachineFunction(MachineFunction &MF) override; + StringRef getPassName() const override { return AARCH64_CONDBR_TUNING_NAME; } + +private: + MachineInstr *getOperandDef(const MachineOperand &MO); + MachineInstr *convertToFlagSetting(MachineInstr &MI, bool IsFlagSetting); + MachineInstr *convertToCondBr(MachineInstr &MI); + bool tryToTuneBranch(MachineInstr &MI, MachineInstr &DefMI); +}; +} // end anonymous namespace + +char AArch64CondBrTuning::ID = 0; + +INITIALIZE_PASS(AArch64CondBrTuning, "aarch64-cond-br-tuning", + AARCH64_CONDBR_TUNING_NAME, false, false) + +void AArch64CondBrTuning::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +MachineInstr *AArch64CondBrTuning::getOperandDef(const MachineOperand &MO) { + if (!TargetRegisterInfo::isVirtualRegister(MO.getReg())) + return nullptr; + return MRI->getUniqueVRegDef(MO.getReg()); +} + +MachineInstr *AArch64CondBrTuning::convertToFlagSetting(MachineInstr &MI, + bool IsFlagSetting) { + // If this is already the flag setting version of the instruction (e.g., SUBS) + // just make sure the implicit-def of NZCV isn't marked dead. + if (IsFlagSetting) { + for (unsigned I = MI.getNumExplicitOperands(), E = MI.getNumOperands(); + I != E; ++I) { + MachineOperand &MO = MI.getOperand(I); + if (MO.isReg() && MO.isDead() && MO.getReg() == AArch64::NZCV) + MO.setIsDead(false); + } + return &MI; + } + bool Is64Bit; + unsigned NewOpc = TII->convertToFlagSettingOpc(MI.getOpcode(), Is64Bit); + unsigned NewDestReg = MI.getOperand(0).getReg(); + if (MRI->hasOneNonDBGUse(MI.getOperand(0).getReg())) + NewDestReg = Is64Bit ? AArch64::XZR : AArch64::WZR; + + MachineInstrBuilder MIB = BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), + TII->get(NewOpc), NewDestReg); + for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I) + MIB.add(MI.getOperand(I)); + + return MIB; +} + +MachineInstr *AArch64CondBrTuning::convertToCondBr(MachineInstr &MI) { + AArch64CC::CondCode CC; + MachineBasicBlock *TargetMBB = TII->getBranchDestBlock(MI); + switch (MI.getOpcode()) { + default: + llvm_unreachable("Unexpected opcode!"); + + case AArch64::CBZW: + case AArch64::CBZX: + CC = AArch64CC::EQ; + break; + case AArch64::CBNZW: + case AArch64::CBNZX: + CC = AArch64CC::NE; + break; + case AArch64::TBZW: + case AArch64::TBZX: + CC = AArch64CC::GE; + break; + case AArch64::TBNZW: + case AArch64::TBNZX: + CC = AArch64CC::LT; + break; + } + return BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(AArch64::Bcc)) + .addImm(CC) + .addMBB(TargetMBB); +} + +bool AArch64CondBrTuning::tryToTuneBranch(MachineInstr &MI, + MachineInstr &DefMI) { + // We don't want NZCV bits live across blocks. + if (MI.getParent() != DefMI.getParent()) + return false; + + bool IsFlagSetting = true; + unsigned MIOpc = MI.getOpcode(); + MachineInstr *NewCmp = nullptr, *NewBr = nullptr; + switch (DefMI.getOpcode()) { + default: + return false; + case AArch64::ADDWri: + case AArch64::ADDWrr: + case AArch64::ADDWrs: + case AArch64::ADDWrx: + case AArch64::ANDWri: + case AArch64::ANDWrr: + case AArch64::ANDWrs: + case AArch64::BICWrr: + case AArch64::BICWrs: + case AArch64::SUBWri: + case AArch64::SUBWrr: + case AArch64::SUBWrs: + case AArch64::SUBWrx: + IsFlagSetting = false; + case AArch64::ADDSWri: + case AArch64::ADDSWrr: + case AArch64::ADDSWrs: + case AArch64::ADDSWrx: + case AArch64::ANDSWri: + case AArch64::ANDSWrr: + case AArch64::ANDSWrs: + case AArch64::BICSWrr: + case AArch64::BICSWrs: + case AArch64::SUBSWri: + case AArch64::SUBSWrr: + case AArch64::SUBSWrs: + case AArch64::SUBSWrx: + switch (MIOpc) { + default: + llvm_unreachable("Unexpected opcode!"); + + case AArch64::CBZW: + case AArch64::CBNZW: + case AArch64::TBZW: + case AArch64::TBNZW: + // Check to see if the TBZ/TBNZ is checking the sign bit. + if ((MIOpc == AArch64::TBZW || MIOpc == AArch64::TBNZW) && + MI.getOperand(1).getImm() != 31) + return false; + + // There must not be any instruction between DefMI and MI that clobbers or + // reads NZCV. + MachineBasicBlock::iterator I(DefMI), E(MI); + for (I = std::next(I); I != E; ++I) { + if (I->modifiesRegister(AArch64::NZCV, TRI) || + I->readsRegister(AArch64::NZCV, TRI)) + return false; + } + DEBUG(dbgs() << " Replacing instructions:\n "); + DEBUG(DefMI.print(dbgs())); + DEBUG(dbgs() << " "); + DEBUG(MI.print(dbgs())); + + NewCmp = convertToFlagSetting(DefMI, IsFlagSetting); + NewBr = convertToCondBr(MI); + break; + } + break; + + case AArch64::ADDXri: + case AArch64::ADDXrr: + case AArch64::ADDXrs: + case AArch64::ADDXrx: + case AArch64::ANDXri: + case AArch64::ANDXrr: + case AArch64::ANDXrs: + case AArch64::BICXrr: + case AArch64::BICXrs: + case AArch64::SUBXri: + case AArch64::SUBXrr: + case AArch64::SUBXrs: + case AArch64::SUBXrx: + IsFlagSetting = false; + case AArch64::ADDSXri: + case AArch64::ADDSXrr: + case AArch64::ADDSXrs: + case AArch64::ADDSXrx: + case AArch64::ANDSXri: + case AArch64::ANDSXrr: + case AArch64::ANDSXrs: + case AArch64::BICSXrr: + case AArch64::BICSXrs: + case AArch64::SUBSXri: + case AArch64::SUBSXrr: + case AArch64::SUBSXrs: + case AArch64::SUBSXrx: + switch (MIOpc) { + default: + llvm_unreachable("Unexpected opcode!"); + + case AArch64::CBZX: + case AArch64::CBNZX: + case AArch64::TBZX: + case AArch64::TBNZX: { + // Check to see if the TBZ/TBNZ is checking the sign bit. + if ((MIOpc == AArch64::TBZX || MIOpc == AArch64::TBNZX) && + MI.getOperand(1).getImm() != 63) + return false; + // There must not be any instruction between DefMI and MI that clobbers or + // reads NZCV. + MachineBasicBlock::iterator I(DefMI), E(MI); + for (I = std::next(I); I != E; ++I) { + if (I->modifiesRegister(AArch64::NZCV, TRI) || + I->readsRegister(AArch64::NZCV, TRI)) + return false; + } + DEBUG(dbgs() << " Replacing instructions:\n "); + DEBUG(DefMI.print(dbgs())); + DEBUG(dbgs() << " "); + DEBUG(MI.print(dbgs())); + + NewCmp = convertToFlagSetting(DefMI, IsFlagSetting); + NewBr = convertToCondBr(MI); + break; + } + } + break; + } + assert(NewCmp && NewBr && "Expected new instructions."); + + DEBUG(dbgs() << " with instruction:\n "); + DEBUG(NewCmp->print(dbgs())); + DEBUG(dbgs() << " "); + DEBUG(NewBr->print(dbgs())); + + // If this was a flag setting version of the instruction, we use the original + // instruction by just clearing the dead marked on the implicit-def of NCZV. + // Therefore, we should not erase this instruction. + if (!IsFlagSetting) + DefMI.eraseFromParent(); + MI.eraseFromParent(); + return true; +} + +bool AArch64CondBrTuning::runOnMachineFunction(MachineFunction &MF) { + if (skipFunction(*MF.getFunction())) + return false; + + DEBUG(dbgs() << "********** AArch64 Conditional Branch Tuning **********\n" + << "********** Function: " << MF.getName() << '\n'); + + TII = static_cast(MF.getSubtarget().getInstrInfo()); + TRI = MF.getSubtarget().getRegisterInfo(); + MRI = &MF.getRegInfo(); + + bool Changed = false; + for (MachineBasicBlock &MBB : MF) { + bool LocalChange = false; + for (MachineBasicBlock::iterator I = MBB.getFirstTerminator(), + E = MBB.end(); + I != E; ++I) { + MachineInstr &MI = *I; + switch (MI.getOpcode()) { + default: + break; + case AArch64::CBZW: + case AArch64::CBZX: + case AArch64::CBNZW: + case AArch64::CBNZX: + case AArch64::TBZW: + case AArch64::TBZX: + case AArch64::TBNZW: + case AArch64::TBNZX: + MachineInstr *DefMI = getOperandDef(MI.getOperand(0)); + LocalChange = (DefMI && tryToTuneBranch(MI, *DefMI)); + break; + } + // If the optimization was successful, we can't optimize any other + // branches because doing so would clobber the NZCV flags. + if (LocalChange) { + Changed = true; + break; + } + } + } + return Changed; +} + +FunctionPass *llvm::createAArch64CondBrTuning() { + return new AArch64CondBrTuning(); +} diff --git a/contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp b/contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp index 544f67433fd5..ee54550c9900 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp +++ b/contrib/llvm/lib/Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp @@ -13,7 +13,9 @@ #include "AArch64.h" #include "AArch64RegisterInfo.h" +#include "AArch64Subtarget.h" #include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" @@ -84,6 +86,51 @@ void AArch64DeadRegisterDefinitions::processMachineBasicBlock( DEBUG(dbgs() << " Ignoring, XZR or WZR already used by the instruction\n"); continue; } + if (MF.getSubtarget().hasLSE()) { + // XZ/WZ for LSE can only be used when acquire semantics are not used, + // LDOPAL WZ is an invalid opcode. + switch (MI.getOpcode()) { + case AArch64::CASALb: + case AArch64::CASALh: + case AArch64::CASALs: + case AArch64::CASALd: + case AArch64::SWPALb: + case AArch64::SWPALh: + case AArch64::SWPALs: + case AArch64::SWPALd: + case AArch64::LDADDALb: + case AArch64::LDADDALh: + case AArch64::LDADDALs: + case AArch64::LDADDALd: + case AArch64::LDEORALb: + case AArch64::LDEORALh: + case AArch64::LDEORALs: + case AArch64::LDEORALd: + case AArch64::LDSETALb: + case AArch64::LDSETALh: + case AArch64::LDSETALs: + case AArch64::LDSETALd: + case AArch64::LDSMINALb: + case AArch64::LDSMINALh: + case AArch64::LDSMINALs: + case AArch64::LDSMINALd: + case AArch64::LDSMAXALb: + case AArch64::LDSMAXALh: + case AArch64::LDSMAXALs: + case AArch64::LDSMAXALd: + case AArch64::LDUMINALb: + case AArch64::LDUMINALh: + case AArch64::LDUMINALs: + case AArch64::LDUMINALd: + case AArch64::LDUMAXALb: + case AArch64::LDUMAXALh: + case AArch64::LDUMAXALs: + case AArch64::LDUMAXALd: + continue; + default: + break; + } + } const MCInstrDesc &Desc = MI.getDesc(); for (int I = 0, E = Desc.getNumDefs(); I != E; ++I) { MachineOperand &MO = MI.getOperand(I); diff --git a/contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp index 8c2c0a564c30..04687847c1a3 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/contrib/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -201,7 +201,7 @@ class AArch64DAGToDAGISel : public SelectionDAGISel { bool SelectCVTFixedPosOperand(SDValue N, SDValue &FixedPos, unsigned Width); - void SelectCMP_SWAP(SDNode *N); + bool SelectCMP_SWAP(SDNode *N); }; } // end anonymous namespace @@ -2609,9 +2609,13 @@ bool AArch64DAGToDAGISel::tryWriteRegister(SDNode *N) { } /// We've got special pseudo-instructions for these -void AArch64DAGToDAGISel::SelectCMP_SWAP(SDNode *N) { +bool AArch64DAGToDAGISel::SelectCMP_SWAP(SDNode *N) { unsigned Opcode; EVT MemTy = cast(N)->getMemoryVT(); + + // Leave IR for LSE if subtarget supports it. + if (Subtarget->hasLSE()) return false; + if (MemTy == MVT::i8) Opcode = AArch64::CMP_SWAP_8; else if (MemTy == MVT::i16) @@ -2637,6 +2641,8 @@ void AArch64DAGToDAGISel::SelectCMP_SWAP(SDNode *N) { ReplaceUses(SDValue(N, 0), SDValue(CmpSwap, 0)); ReplaceUses(SDValue(N, 1), SDValue(CmpSwap, 2)); CurDAG->RemoveDeadNode(N); + + return true; } void AArch64DAGToDAGISel::Select(SDNode *Node) { @@ -2660,8 +2666,9 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) { break; case ISD::ATOMIC_CMP_SWAP: - SelectCMP_SWAP(Node); - return; + if (SelectCMP_SWAP(Node)) + return; + break; case ISD::READ_REGISTER: if (tryReadRegister(Node)) diff --git a/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 083ca2156598..2965106fd270 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/contrib/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10563,11 +10563,20 @@ AArch64TargetLowering::shouldExpandAtomicLoadInIR(LoadInst *LI) const { TargetLowering::AtomicExpansionKind AArch64TargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { unsigned Size = AI->getType()->getPrimitiveSizeInBits(); - return Size <= 128 ? AtomicExpansionKind::LLSC : AtomicExpansionKind::None; + if (Size > 128) return AtomicExpansionKind::None; + // Nand not supported in LSE. + if (AI->getOperation() == AtomicRMWInst::Nand) return AtomicExpansionKind::LLSC; + // Currently leaving And and Sub to LLSC + if ((AI->getOperation() == AtomicRMWInst::And) || (AI->getOperation() == AtomicRMWInst::Sub)) + return AtomicExpansionKind::LLSC; + // Leave 128 bits to LLSC. + return (Subtarget->hasLSE() && Size < 128) ? AtomicExpansionKind::None : AtomicExpansionKind::LLSC; } bool AArch64TargetLowering::shouldExpandAtomicCmpXchgInIR( AtomicCmpXchgInst *AI) const { + // If subtarget has LSE, leave cmpxchg intact for codegen. + if (Subtarget->hasLSE()) return false; // At -O0, fast-regalloc cannot cope with the live vregs necessary to // implement cmpxchg without spilling. If the address being exchanged is also // on the stack and close enough to the spill slot, this can lead to a diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td b/contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td index 71826bec6b11..de283b70210f 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td +++ b/contrib/llvm/lib/Target/AArch64/AArch64InstrAtomics.td @@ -405,3 +405,49 @@ def CMP_SWAP_128 : Pseudo<(outs GPR64:$RdLo, GPR64:$RdHi, GPR32:$scratch), (ins GPR64:$addr, GPR64:$desiredLo, GPR64:$desiredHi, GPR64:$newLo, GPR64:$newHi), []>, Sched<[WriteAtomic]>; + +// v8.1 Atomic instructions: +def : Pat<(atomic_load_add_8 GPR64:$Rn, GPR32:$Rs), (LDADDALb GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_add_16 GPR64:$Rn, GPR32:$Rs), (LDADDALh GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_add_32 GPR64:$Rn, GPR32:$Rs), (LDADDALs GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_add_64 GPR64:$Rn, GPR64:$Rs), (LDADDALd GPR64:$Rs, GPR64sp:$Rn)>; + +def : Pat<(atomic_load_or_8 GPR64:$Rn, GPR32:$Rs), (LDSETALb GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_or_16 GPR64:$Rn, GPR32:$Rs), (LDSETALh GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_or_32 GPR64:$Rn, GPR32:$Rs), (LDSETALs GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_or_64 GPR64:$Rn, GPR64:$Rs), (LDSETALd GPR64:$Rs, GPR64sp:$Rn)>; + +def : Pat<(atomic_load_xor_8 GPR64:$Rn, GPR32:$Rs), (LDEORALb GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_xor_16 GPR64:$Rn, GPR32:$Rs), (LDEORALh GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_xor_32 GPR64:$Rn, GPR32:$Rs), (LDEORALs GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_xor_64 GPR64:$Rn, GPR64:$Rs), (LDEORALd GPR64:$Rs, GPR64sp:$Rn)>; + +def : Pat<(atomic_load_max_8 GPR64:$Rn, GPR32:$Rs), (LDSMAXALb GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_max_16 GPR64:$Rn, GPR32:$Rs), (LDSMAXALh GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_max_32 GPR64:$Rn, GPR32:$Rs), (LDSMAXALs GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_max_64 GPR64:$Rn, GPR64:$Rs), (LDSMAXALd GPR64:$Rs, GPR64sp:$Rn)>; + +def : Pat<(atomic_load_umax_8 GPR64:$Rn, GPR32:$Rs), (LDUMAXALb GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_umax_16 GPR64:$Rn, GPR32:$Rs), (LDUMAXALh GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_umax_32 GPR64:$Rn, GPR32:$Rs), (LDUMAXALs GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_umax_64 GPR64:$Rn, GPR64:$Rs), (LDUMAXALd GPR64:$Rs, GPR64sp:$Rn)>; + +def : Pat<(atomic_load_min_8 GPR64:$Rn, GPR32:$Rs), (LDSMINALb GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_min_16 GPR64:$Rn, GPR32:$Rs), (LDSMINALh GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_min_32 GPR64:$Rn, GPR32:$Rs), (LDSMINALs GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_min_64 GPR64:$Rn, GPR64:$Rs), (LDSMINALd GPR64:$Rs, GPR64sp:$Rn)>; + +def : Pat<(atomic_load_umin_8 GPR64:$Rn, GPR32:$Rs), (LDUMINALb GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_umin_16 GPR64:$Rn, GPR32:$Rs), (LDUMINALh GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_umin_32 GPR64:$Rn, GPR32:$Rs), (LDUMINALs GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_load_umin_64 GPR64:$Rn, GPR64:$Rs), (LDUMINALd GPR64:$Rs, GPR64sp:$Rn)>; + +def : Pat<(atomic_cmp_swap_8 GPR64:$Rn, GPR32:$Rold, GPR32:$Rnew), (CASALb GPR32:$Rold, GPR32:$Rnew, GPR64sp:$Rn)>; +def : Pat<(atomic_cmp_swap_16 GPR64:$Rn, GPR32:$Rold, GPR32:$Rnew), (CASALh GPR32:$Rold, GPR32:$Rnew, GPR64sp:$Rn)>; +def : Pat<(atomic_cmp_swap_32 GPR64:$Rn, GPR32:$Rold, GPR32:$Rnew), (CASALs GPR32:$Rold, GPR32:$Rnew, GPR64sp:$Rn)>; +def : Pat<(atomic_cmp_swap_64 GPR64:$Rn, GPR64:$Rold, GPR64:$Rnew), (CASALd GPR64:$Rold, GPR64:$Rnew, GPR64sp:$Rn)>; + +def : Pat<(atomic_swap_8 GPR64:$Rn, GPR32:$Rs), (SWPALb GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_swap_16 GPR64:$Rn, GPR32:$Rs), (SWPALh GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_swap_32 GPR64:$Rn, GPR32:$Rs), (SWPALs GPR32:$Rs, GPR64sp:$Rn)>; +def : Pat<(atomic_swap_64 GPR64:$Rn, GPR64:$Rs), (SWPALd GPR64:$Rs, GPR64sp:$Rn)>; diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index eea012382150..314e89bbca86 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -1036,7 +1036,7 @@ static bool UpdateOperandRegClass(MachineInstr &Instr) { /// \brief Return the opcode that does not set flags when possible - otherwise /// return the original opcode. The caller is responsible to do the actual /// substitution and legality checking. -static unsigned convertFlagSettingOpcode(const MachineInstr &MI) { +static unsigned convertToNonFlagSettingOpc(const MachineInstr &MI) { // Don't convert all compare instructions, because for some the zero register // encoding becomes the sp register. bool MIDefinesZeroReg = false; @@ -1145,7 +1145,7 @@ bool AArch64InstrInfo::optimizeCompareInstr( return true; } unsigned Opc = CmpInstr.getOpcode(); - unsigned NewOpc = convertFlagSettingOpcode(CmpInstr); + unsigned NewOpc = convertToNonFlagSettingOpc(CmpInstr); if (NewOpc == Opc) return false; const MCInstrDesc &MCID = get(NewOpc); @@ -3318,7 +3318,7 @@ static bool getMaddPatterns(MachineInstr &Root, // When NZCV is live bail out. if (Cmp_NZCV == -1) return false; - unsigned NewOpc = convertFlagSettingOpcode(Root); + unsigned NewOpc = convertToNonFlagSettingOpc(Root); // When opcode can't change bail out. // CHECKME: do we miss any cases for opcode conversion? if (NewOpc == Opc) diff --git a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h index 59f3405fe439..58e9ce583d44 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h +++ b/contrib/llvm/lib/Target/AArch64/AArch64InstrInfo.h @@ -119,6 +119,44 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo { } } + /// \brief Return the opcode that set flags when possible. The caller is + /// responsible for ensuring the opc has a flag setting equivalent. + static unsigned convertToFlagSettingOpc(unsigned Opc, bool &Is64Bit) { + switch (Opc) { + default: + llvm_unreachable("Opcode has no flag setting equivalent!"); + // 32-bit cases: + case AArch64::ADDWri: Is64Bit = false; return AArch64::ADDSWri; + case AArch64::ADDWrr: Is64Bit = false; return AArch64::ADDSWrr; + case AArch64::ADDWrs: Is64Bit = false; return AArch64::ADDSWrs; + case AArch64::ADDWrx: Is64Bit = false; return AArch64::ADDSWrx; + case AArch64::ANDWri: Is64Bit = false; return AArch64::ANDSWri; + case AArch64::ANDWrr: Is64Bit = false; return AArch64::ANDSWrr; + case AArch64::ANDWrs: Is64Bit = false; return AArch64::ANDSWrs; + case AArch64::BICWrr: Is64Bit = false; return AArch64::BICSWrr; + case AArch64::BICWrs: Is64Bit = false; return AArch64::BICSWrs; + case AArch64::SUBWri: Is64Bit = false; return AArch64::SUBSWri; + case AArch64::SUBWrr: Is64Bit = false; return AArch64::SUBSWrr; + case AArch64::SUBWrs: Is64Bit = false; return AArch64::SUBSWrs; + case AArch64::SUBWrx: Is64Bit = false; return AArch64::SUBSWrx; + // 64-bit cases: + case AArch64::ADDXri: Is64Bit = true; return AArch64::ADDSXri; + case AArch64::ADDXrr: Is64Bit = true; return AArch64::ADDSXrr; + case AArch64::ADDXrs: Is64Bit = true; return AArch64::ADDSXrs; + case AArch64::ADDXrx: Is64Bit = true; return AArch64::ADDSXrx; + case AArch64::ANDXri: Is64Bit = true; return AArch64::ANDSXri; + case AArch64::ANDXrr: Is64Bit = true; return AArch64::ANDSXrr; + case AArch64::ANDXrs: Is64Bit = true; return AArch64::ANDSXrs; + case AArch64::BICXrr: Is64Bit = true; return AArch64::BICSXrr; + case AArch64::BICXrs: Is64Bit = true; return AArch64::BICSXrs; + case AArch64::SUBXri: Is64Bit = true; return AArch64::SUBSXri; + case AArch64::SUBXrr: Is64Bit = true; return AArch64::SUBSXrr; + case AArch64::SUBXrs: Is64Bit = true; return AArch64::SUBSXrs; + case AArch64::SUBXrx: Is64Bit = true; return AArch64::SUBSXrx; + } + } + + /// Return true if this is a load/store that can be potentially paired/merged. bool isCandidateToMergeOrPair(MachineInstr &MI) const; diff --git a/contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp index 9243eb91cc1a..005f2d51e403 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp +++ b/contrib/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp @@ -795,6 +795,7 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI, int LoadSize = getMemScale(*LoadI); int StoreSize = getMemScale(*StoreI); unsigned LdRt = getLdStRegOp(*LoadI).getReg(); + const MachineOperand &StMO = getLdStRegOp(*StoreI); unsigned StRt = getLdStRegOp(*StoreI).getReg(); bool IsStoreXReg = TRI->getRegClass(AArch64::GPR64RegClassID)->contains(StRt); @@ -807,7 +808,13 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI, // Remove the load, if the destination register of the loads is the same // register for stored value. if (StRt == LdRt && LoadSize == 8) { - StoreI->clearRegisterKills(StRt, TRI); + for (MachineInstr &MI : make_range(StoreI->getIterator(), + LoadI->getIterator())) { + if (MI.killsRegister(StRt, TRI)) { + MI.clearRegisterKills(StRt, TRI); + break; + } + } DEBUG(dbgs() << "Remove load instruction:\n "); DEBUG(LoadI->print(dbgs())); DEBUG(dbgs() << "\n"); @@ -819,7 +826,7 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI, BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(), TII->get(IsStoreXReg ? AArch64::ORRXrs : AArch64::ORRWrs), LdRt) .addReg(IsStoreXReg ? AArch64::XZR : AArch64::WZR) - .addReg(StRt) + .add(StMO) .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, 0)); } else { // FIXME: Currently we disable this transformation in big-endian targets as @@ -860,14 +867,14 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI, BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(), TII->get(IsStoreXReg ? AArch64::ANDXri : AArch64::ANDWri), DestReg) - .addReg(StRt) + .add(StMO) .addImm(AndMaskEncoded); } else { BitExtMI = BuildMI(*LoadI->getParent(), LoadI, LoadI->getDebugLoc(), TII->get(IsStoreXReg ? AArch64::UBFMXri : AArch64::UBFMWri), DestReg) - .addReg(StRt) + .add(StMO) .addImm(Immr) .addImm(Imms); } @@ -876,7 +883,10 @@ AArch64LoadStoreOpt::promoteLoadFromStore(MachineBasicBlock::iterator LoadI, // Clear kill flags between store and load. for (MachineInstr &MI : make_range(StoreI->getIterator(), BitExtMI->getIterator())) - MI.clearRegisterKills(StRt, TRI); + if (MI.killsRegister(StRt, TRI)) { + MI.clearRegisterKills(StRt, TRI); + break; + } DEBUG(dbgs() << "Promoting load by replacing :\n "); DEBUG(StoreI->print(dbgs())); diff --git a/contrib/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp b/contrib/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp index 3b71d529db59..ccc9d2ad1b48 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp +++ b/contrib/llvm/lib/Target/AArch64/AArch64MacroFusion.cpp @@ -7,37 +7,27 @@ // //===----------------------------------------------------------------------===// // -// \file This file contains the AArch64 implementation of the DAG scheduling mutation -// to pair instructions back to back. +/// \file This file contains the AArch64 implementation of the DAG scheduling +/// mutation to pair instructions back to back. // //===----------------------------------------------------------------------===// #include "AArch64MacroFusion.h" #include "AArch64Subtarget.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/CodeGen/MacroFusion.h" #include "llvm/Target/TargetInstrInfo.h" -#define DEBUG_TYPE "misched" - -STATISTIC(NumFused, "Number of instr pairs fused"); - using namespace llvm; -static cl::opt EnableMacroFusion("aarch64-misched-fusion", cl::Hidden, - cl::desc("Enable scheduling for macro fusion."), cl::init(true)); - namespace { -/// \brief Verify that the instr pair, FirstMI and SecondMI, should be fused -/// together. Given an anchor instr, when the other instr is unspecified, then -/// check if the anchor instr may be part of a fused pair at all. +/// \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. static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, const TargetSubtargetInfo &TSI, const MachineInstr *FirstMI, - const MachineInstr *SecondMI) { - assert((FirstMI || SecondMI) && "At least one instr must be specified"); - + const MachineInstr &SecondMI) { const AArch64InstrInfo &II = static_cast(TII); const AArch64Subtarget &ST = static_cast(TSI); @@ -45,9 +35,7 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, unsigned FirstOpcode = FirstMI ? FirstMI->getOpcode() : static_cast(AArch64::INSTRUCTION_LIST_END); - unsigned SecondOpcode = - SecondMI ? SecondMI->getOpcode() - : static_cast(AArch64::INSTRUCTION_LIST_END); + unsigned SecondOpcode = SecondMI.getOpcode(); if (ST.hasArithmeticBccFusion()) // Fuse CMN, CMP, TST followed by Bcc. @@ -128,158 +116,49 @@ static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, if (ST.hasFuseAES()) // Fuse AES crypto operations. - switch(FirstOpcode) { + switch(SecondOpcode) { // AES encode. - case AArch64::AESErr: - return SecondOpcode == AArch64::AESMCrr || - SecondOpcode == AArch64::INSTRUCTION_LIST_END; + case AArch64::AESMCrr : + return FirstOpcode == AArch64::AESErr || + FirstOpcode == AArch64::INSTRUCTION_LIST_END; // AES decode. - case AArch64::AESDrr: - return SecondOpcode == AArch64::AESIMCrr || - SecondOpcode == AArch64::INSTRUCTION_LIST_END; + case AArch64::AESIMCrr: + return FirstOpcode == AArch64::AESDrr || + FirstOpcode == AArch64::INSTRUCTION_LIST_END; } if (ST.hasFuseLiterals()) // Fuse literal generation operations. - switch (FirstOpcode) { + switch (SecondOpcode) { // PC relative address. - case AArch64::ADRP: - return SecondOpcode == AArch64::ADDXri || - SecondOpcode == AArch64::INSTRUCTION_LIST_END; + case AArch64::ADDXri: + return FirstOpcode == AArch64::ADRP || + FirstOpcode == AArch64::INSTRUCTION_LIST_END; // 32 bit immediate. - case AArch64::MOVZWi: - return (SecondOpcode == AArch64::MOVKWi && - SecondMI->getOperand(3).getImm() == 16) || - SecondOpcode == AArch64::INSTRUCTION_LIST_END; - // Lower half of 64 bit immediate. - case AArch64::MOVZXi: - return (SecondOpcode == AArch64::MOVKXi && - SecondMI->getOperand(3).getImm() == 16) || - SecondOpcode == AArch64::INSTRUCTION_LIST_END; - // Upper half of 64 bit immediate. + case AArch64::MOVKWi: + return (FirstOpcode == AArch64::MOVZWi && + SecondMI.getOperand(3).getImm() == 16) || + FirstOpcode == AArch64::INSTRUCTION_LIST_END; + // Lower and upper half of 64 bit immediate. case AArch64::MOVKXi: - return FirstMI->getOperand(3).getImm() == 32 && - ((SecondOpcode == AArch64::MOVKXi && - SecondMI->getOperand(3).getImm() == 48) || - SecondOpcode == AArch64::INSTRUCTION_LIST_END); + return FirstOpcode == AArch64::INSTRUCTION_LIST_END || + (FirstOpcode == AArch64::MOVZXi && + SecondMI.getOperand(3).getImm() == 16) || + (FirstOpcode == AArch64::MOVKXi && + FirstMI->getOperand(3).getImm() == 32 && + SecondMI.getOperand(3).getImm() == 48); } return false; } -/// \brief Implement the fusion of instr pairs in the scheduling DAG, -/// anchored at the instr in AnchorSU.. -static bool scheduleAdjacentImpl(ScheduleDAGMI *DAG, SUnit &AnchorSU) { - const MachineInstr *AnchorMI = AnchorSU.getInstr(); - if (!AnchorMI || AnchorMI->isPseudo() || AnchorMI->isTransient()) - return false; - - // If the anchor instr is the ExitSU, then consider its predecessors; - // otherwise, its successors. - bool Preds = (&AnchorSU == &DAG->ExitSU); - SmallVectorImpl &AnchorDeps = Preds ? AnchorSU.Preds : AnchorSU.Succs; - - const MachineInstr *FirstMI = Preds ? nullptr : AnchorMI; - const MachineInstr *SecondMI = Preds ? AnchorMI : nullptr; - - // Check if the anchor instr may be fused. - if (!shouldScheduleAdjacent(*DAG->TII, DAG->MF.getSubtarget(), - FirstMI, SecondMI)) - return false; - - // Explorer for fusion candidates among the dependencies of the anchor instr. - for (SDep &Dep : AnchorDeps) { - // Ignore dependencies that don't enforce ordering. - if (Dep.isWeak()) - continue; - - SUnit &DepSU = *Dep.getSUnit(); - // Ignore the ExitSU if the dependents are successors. - if (!Preds && &DepSU == &DAG->ExitSU) - continue; - - const MachineInstr *DepMI = DepSU.getInstr(); - if (!DepMI || DepMI->isPseudo() || DepMI->isTransient()) - continue; - - FirstMI = Preds ? DepMI : AnchorMI; - SecondMI = Preds ? AnchorMI : DepMI; - if (!shouldScheduleAdjacent(*DAG->TII, DAG->MF.getSubtarget(), - FirstMI, SecondMI)) - continue; - - // Create a single weak edge between the adjacent instrs. The only effect is - // to cause bottom-up scheduling to heavily prioritize the clustered instrs. - SUnit &FirstSU = Preds ? DepSU : AnchorSU; - SUnit &SecondSU = Preds ? AnchorSU : DepSU; - DAG->addEdge(&SecondSU, SDep(&FirstSU, SDep::Cluster)); - - // Adjust the latency between the anchor instr and its - // predecessors/successors. - for (SDep &IDep : AnchorDeps) - if (IDep.getSUnit() == &DepSU) - IDep.setLatency(0); - - // Adjust the latency between the dependent instr and its - // successors/predecessors. - for (SDep &IDep : Preds ? DepSU.Succs : DepSU.Preds) - if (IDep.getSUnit() == &AnchorSU) - IDep.setLatency(0); - - DEBUG(dbgs() << DAG->MF.getName() << "(): Macro fuse "; - FirstSU.print(dbgs(), DAG); dbgs() << " - "; - SecondSU.print(dbgs(), DAG); dbgs() << " / "; - dbgs() << DAG->TII->getName(FirstMI->getOpcode()) << " - " << - DAG->TII->getName(SecondMI->getOpcode()) << '\n'; ); - - if (&SecondSU != &DAG->ExitSU) - // Make instructions dependent on FirstSU also dependent on SecondSU to - // prevent them from being scheduled between FirstSU and and SecondSU. - for (SUnit::const_succ_iterator - SI = FirstSU.Succs.begin(), SE = FirstSU.Succs.end(); - SI != SE; ++SI) { - if (!SI->getSUnit() || SI->getSUnit() == &SecondSU) - continue; - DEBUG(dbgs() << " Copy Succ "; - SI->getSUnit()->print(dbgs(), DAG); dbgs() << '\n';); - DAG->addEdge(SI->getSUnit(), SDep(&SecondSU, SDep::Artificial)); - } - - ++NumFused; - return true; - } - - return false; -} - -/// \brief Post-process the DAG to create cluster edges between instrs that may -/// be fused by the processor into a single operation. -class AArch64MacroFusion : public ScheduleDAGMutation { -public: - AArch64MacroFusion() {} - - void apply(ScheduleDAGInstrs *DAGInstrs) override; -}; - -void AArch64MacroFusion::apply(ScheduleDAGInstrs *DAGInstrs) { - ScheduleDAGMI *DAG = static_cast(DAGInstrs); - - // For each of the SUnits in the scheduling block, try to fuse the instr in it - // with one in its successors. - for (SUnit &ISU : DAG->SUnits) - scheduleAdjacentImpl(DAG, ISU); - - // Try to fuse the instr in the ExitSU with one in its predecessors. - scheduleAdjacentImpl(DAG, DAG->ExitSU); -} - } // end namespace namespace llvm { std::unique_ptr createAArch64MacroFusionDAGMutation () { - return EnableMacroFusion ? make_unique() : nullptr; + return createMacroFusionDAGMutation(shouldScheduleAdjacent); } } // end namespace llvm diff --git a/contrib/llvm/lib/Target/AArch64/AArch64MacroFusion.h b/contrib/llvm/lib/Target/AArch64/AArch64MacroFusion.h index e5efedd9fbfd..32d90d4c40d6 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64MacroFusion.h +++ b/contrib/llvm/lib/Target/AArch64/AArch64MacroFusion.h @@ -2,23 +2,18 @@ // // The LLVM Compiler Infrastructure // -// \fileThis file is distributed under the University of Illinois Open Source +// This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // -// This file contains the AArch64 definition of the DAG scheduling mutation -// to pair instructions back to back. +/// \file This file contains the AArch64 definition of the DAG scheduling +/// mutation to pair instructions back to back. // //===----------------------------------------------------------------------===// -#include "AArch64InstrInfo.h" #include "llvm/CodeGen/MachineScheduler.h" -//===----------------------------------------------------------------------===// -// AArch64MacroFusion - DAG post-processing to encourage fusion of macro ops. -//===----------------------------------------------------------------------===// - namespace llvm { /// Note that you have to add: diff --git a/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp b/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp index 9b3899e0681c..69124dbd0f83 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp +++ b/contrib/llvm/lib/Target/AArch64/AArch64RegisterBankInfo.cpp @@ -469,10 +469,6 @@ AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { getCopyMapping(DstRB.getID(), SrcRB.getID(), Size), /*NumOperands*/ 2); } - case TargetOpcode::G_SEQUENCE: - // FIXME: support this, but the generic code is really not going to do - // anything sane. - return getInvalidInstructionMapping(); default: break; } diff --git a/contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td b/contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td index 303398ea0b7f..5d1608ef04af 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td +++ b/contrib/llvm/lib/Target/AArch64/AArch64SchedA57.td @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// -// The Cortex-A57 is a traditional superscaler microprocessor with a +// The Cortex-A57 is a traditional superscalar microprocessor with a // conservative 3-wide in-order stage for decode and dispatch. Combined with the // much wider out-of-order issue stage, this produced a need to carefully // schedule micro-ops so that all three decoded each cycle are successfully diff --git a/contrib/llvm/lib/Target/AArch64/AArch64SchedFalkorDetails.td b/contrib/llvm/lib/Target/AArch64/AArch64SchedFalkorDetails.td index 3d737402022d..0aeb1f3e3058 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64SchedFalkorDetails.td +++ b/contrib/llvm/lib/Target/AArch64/AArch64SchedFalkorDetails.td @@ -32,8 +32,8 @@ //===----------------------------------------------------------------------===// // Define 0 micro-op types -def FalkorWr_none_1cyc : SchedWriteRes<[]> { - let Latency = 1; +def FalkorWr_LdStInc_none_3cyc : SchedWriteRes<[]> { + let Latency = 3; let NumMicroOps = 0; } def FalkorWr_none_3cyc : SchedWriteRes<[]> { @@ -505,7 +505,8 @@ def FalkorWr_4VXVY_4ST_4VSD_0cyc: SchedWriteRes<[FalkorUnitVXVY, FalkorUnitST, let NumMicroOps = 12; } -// Forwarding logic is modeled for multiply add/accumulate. +// Forwarding logic is modeled for multiply add/accumulate and +// load/store base register increment. // ----------------------------------------------------------------------------- def FalkorReadIMA32 : SchedReadAdvance<3, [FalkorWr_IMUL32_1X_2cyc]>; def FalkorReadIMA64 : SchedReadAdvance<4, [FalkorWr_IMUL64_1X_4cyc, FalkorWr_IMUL64_1X_5cyc]>; @@ -513,9 +514,13 @@ def FalkorReadVMA : SchedReadAdvance<3, [FalkorWr_VMUL32_1VXVY_4cyc, FalkorWr def FalkorReadFMA32 : SchedReadAdvance<1, [FalkorWr_FMUL32_1VXVY_5cyc, FalkorWr_FMUL32_2VXVY_5cyc]>; def FalkorReadFMA64 : SchedReadAdvance<2, [FalkorWr_FMUL64_1VXVY_6cyc, FalkorWr_FMUL64_2VXVY_6cyc]>; +def FalkorReadIncLd : SchedReadAdvance<2, [FalkorWr_LdStInc_none_3cyc]>; +def FalkorReadIncSt : SchedReadAdvance<1, [FalkorWr_LdStInc_none_3cyc]>; + // SchedPredicates and WriteVariants for Immediate Zero and LSLFast/ASRFast // ----------------------------------------------------------------------------- -def FalkorImmZPred : SchedPredicate<[{MI->getOperand(1).getImm() == 0}]>; +def FalkorImmZPred : SchedPredicate<[{MI->getOperand(1).isImm() && + MI->getOperand(1).getImm() == 0}]>; def FalkorOp1ZrReg : SchedPredicate<[{MI->getOperand(1).getReg() == AArch64::WZR || MI->getOperand(1).getReg() == AArch64::XZR}]>; @@ -770,84 +775,113 @@ def : InstRW<[FalkorWr_VMUL32_2VXVY_4cyc, FalkorReadVMA], // SIMD Load Instructions // ----------------------------------------------------------------------------- -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^LD1(i64|Onev(8b|4h|2s|1d|16b|8h|4s|2d))$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_3cyc], (instregex "^LD1(i64|Onev(8b|4h|2s|1d|16b|8h|4s|2d))_POST$")>; -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^LD1Rv(8b|4h|2s|1d|16b|8h|4s|2d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_3cyc], (instregex "^LD1Rv(8b|4h|2s|1d|16b|8h|4s|2d)_POST$")>; -def : InstRW<[FalkorWr_1LD_3cyc], (instrs LD2i64)>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_3cyc], (instrs LD2i64_POST)>; +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], (instregex "^LD1(i64|Onev(8b|4h|2s|1d|16b|8h|4s|2d))$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^LD1(i64|Onev(8b|4h|2s|1d|16b|8h|4s|2d))_POST$")>; +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], (instregex "^LD1Rv(8b|4h|2s|1d|16b|8h|4s|2d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^LD1Rv(8b|4h|2s|1d|16b|8h|4s|2d)_POST$")>; +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], (instrs LD2i64)>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instrs LD2i64_POST)>; -def : InstRW<[FalkorWr_1LD_1VXVY_4cyc], (instregex "^LD1i(8|16|32)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_1VXVY_4cyc], (instregex "^LD1i(8|16|32)_POST$")>; +def : InstRW<[FalkorWr_1LD_1VXVY_4cyc, FalkorReadIncLd], (instregex "^LD1i(8|16|32)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_1VXVY_4cyc, FalkorReadIncLd], + (instregex "^LD1i(8|16|32)_POST$")>; -def : InstRW<[FalkorWr_1LD_1none_3cyc], (instregex "^LD1Twov(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_1none_3cyc], (instregex "^LD1Twov(8b|4h|2s|1d)_POST$")>; -def : InstRW<[FalkorWr_1LD_1none_3cyc], (instregex "^LD2Twov(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_1none_3cyc], (instregex "^LD2Twov(8b|4h|2s|1d)_POST$")>; -def : InstRW<[FalkorWr_1LD_1none_3cyc], (instregex "^LD2Rv(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_1none_3cyc], (instregex "^LD2Rv(8b|4h|2s|1d)_POST$")>; +def : InstRW<[FalkorWr_1LD_1none_3cyc, FalkorReadIncLd], (instregex "^LD1Twov(8b|4h|2s|1d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_1none_3cyc, FalkorReadIncLd], + (instregex "^LD1Twov(8b|4h|2s|1d)_POST$")>; +def : InstRW<[FalkorWr_1LD_1none_3cyc, FalkorReadIncLd], (instregex "^LD2Twov(8b|4h|2s)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_1none_3cyc, FalkorReadIncLd], + (instregex "^LD2Twov(8b|4h|2s)_POST$")>; +def : InstRW<[FalkorWr_1LD_1none_3cyc, FalkorReadIncLd], (instregex "^LD2Rv(8b|4h|2s|1d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_1none_3cyc, FalkorReadIncLd], + (instregex "^LD2Rv(8b|4h|2s|1d)_POST$")>; -def : InstRW<[FalkorWr_2LD_3cyc], (instregex "^LD1Twov(16b|8h|4s|2d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_3cyc], (instregex "^LD1Twov(16b|8h|4s|2d)_POST$")>; -def : InstRW<[FalkorWr_2LD_3cyc], (instregex "^LD2Twov(16b|8h|4s|2d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_3cyc], (instregex "^LD2Twov(16b|8h|4s|2d)_POST$")>; -def : InstRW<[FalkorWr_2LD_3cyc], (instregex "^LD2Rv(16b|8h|4s|2d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_3cyc], (instregex "^LD2Rv(16b|8h|4s|2d)_POST$")>; -def : InstRW<[FalkorWr_2LD_3cyc], (instrs LD3i64)>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_3cyc], (instrs LD3i64_POST)>; -def : InstRW<[FalkorWr_2LD_3cyc], (instrs LD4i64)>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_3cyc], (instrs LD4i64_POST)>; +def : InstRW<[FalkorWr_2LD_3cyc, FalkorReadIncLd], (instregex "^LD1Twov(16b|8h|4s|2d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_3cyc, FalkorReadIncLd], + (instregex "^LD1Twov(16b|8h|4s|2d)_POST$")>; +def : InstRW<[FalkorWr_2LD_3cyc, FalkorReadIncLd], (instregex "^LD2Twov(16b|8h|4s|2d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_3cyc, FalkorReadIncLd], + (instregex "^LD2Twov(16b|8h|4s|2d)_POST$")>; +def : InstRW<[FalkorWr_2LD_3cyc, FalkorReadIncLd], (instregex "^LD2Rv(16b|8h|4s|2d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_3cyc, FalkorReadIncLd], + (instregex "^LD2Rv(16b|8h|4s|2d)_POST$")>; +def : InstRW<[FalkorWr_2LD_3cyc, FalkorReadIncLd], (instrs LD3i64)>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_3cyc, FalkorReadIncLd], + (instrs LD3i64_POST)>; +def : InstRW<[FalkorWr_2LD_3cyc, FalkorReadIncLd], (instrs LD4i64)>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_3cyc, FalkorReadIncLd], + (instrs LD4i64_POST)>; -def : InstRW<[FalkorWr_1LD_2VXVY_4cyc], (instregex "^LD2i(8|16|32)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_2VXVY_4cyc], (instregex "^LD2i(8|16|32)_POST$")>; +def : InstRW<[FalkorWr_1LD_2VXVY_4cyc, FalkorReadIncLd], (instregex "^LD2i(8|16|32)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_2VXVY_4cyc, FalkorReadIncLd], + (instregex "^LD2i(8|16|32)_POST$")>; -def : InstRW<[FalkorWr_2LD_1none_3cyc], (instregex "^LD1Threev(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_1none_3cyc], (instregex "^LD1Threev(8b|4h|2s|1d)_POST$")>; -def : InstRW<[FalkorWr_2LD_1none_3cyc], (instregex "^LD3Rv(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_1none_3cyc], (instregex "^LD3Rv(8b|4h|2s|1d)_POST$")>; +def : InstRW<[FalkorWr_2LD_1none_3cyc, FalkorReadIncLd], (instregex "^LD1Threev(8b|4h|2s|1d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_1none_3cyc, FalkorReadIncLd], + (instregex "^LD1Threev(8b|4h|2s|1d)_POST$")>; +def : InstRW<[FalkorWr_2LD_1none_3cyc, FalkorReadIncLd], (instregex "^LD3Rv(8b|4h|2s|1d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_1none_3cyc, FalkorReadIncLd], + (instregex "^LD3Rv(8b|4h|2s|1d)_POST$")>; -def : InstRW<[FalkorWr_3LD_3cyc], (instregex "^LD1Threev(16b|8h|4s|2d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_3LD_3cyc], (instregex "^LD1Threev(16b|8h|4s|2d)_POST$")>; -def : InstRW<[FalkorWr_3LD_3cyc], (instrs LD3Threev2d)>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_3LD_3cyc], (instrs LD3Threev2d_POST)>; -def : InstRW<[FalkorWr_3LD_3cyc], (instregex "^LD3Rv(16b|8h|4s|2d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_3LD_3cyc], (instregex "^LD3Rv(16b|8h|4s|2d)_POST$")>; +def : InstRW<[FalkorWr_3LD_3cyc, FalkorReadIncLd], (instregex "^LD1Threev(16b|8h|4s|2d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_3LD_3cyc, FalkorReadIncLd], + (instregex "^LD1Threev(16b|8h|4s|2d)_POST$")>; +def : InstRW<[FalkorWr_3LD_3cyc, FalkorReadIncLd], (instrs LD3Threev2d)>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_3LD_3cyc, FalkorReadIncLd], + (instrs LD3Threev2d_POST)>; +def : InstRW<[FalkorWr_3LD_3cyc, FalkorReadIncLd], (instregex "^LD3Rv(16b|8h|4s|2d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_3LD_3cyc, FalkorReadIncLd], + (instregex "^LD3Rv(16b|8h|4s|2d)_POST$")>; -def : InstRW<[FalkorWr_1LD_3VXVY_4cyc], (instregex "^LD3i(8|16|32)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_3VXVY_4cyc], (instregex "^LD3i(8|16|32)_POST$")>; +def : InstRW<[FalkorWr_1LD_3VXVY_4cyc, FalkorReadIncLd], (instregex "^LD3i(8|16|32)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_3VXVY_4cyc, FalkorReadIncLd], + (instregex "^LD3i(8|16|32)_POST$")>; -def : InstRW<[FalkorWr_2LD_2none_3cyc], (instregex "^LD1Fourv(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_2none_3cyc], (instregex "^LD1Fourv(8b|4h|2s|1d)_POST$")>; -def : InstRW<[FalkorWr_2LD_2none_3cyc], (instregex "^LD4Rv(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_2none_3cyc], (instregex "^LD4Rv(8b|4h|2s|1d)_POST$")>; +def : InstRW<[FalkorWr_2LD_2none_3cyc, FalkorReadIncLd], (instregex "^LD1Fourv(8b|4h|2s|1d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_2none_3cyc, FalkorReadIncLd], + (instregex "^LD1Fourv(8b|4h|2s|1d)_POST$")>; +def : InstRW<[FalkorWr_2LD_2none_3cyc, FalkorReadIncLd], (instregex "^LD4Rv(8b|4h|2s|1d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_2none_3cyc, FalkorReadIncLd], + (instregex "^LD4Rv(8b|4h|2s|1d)_POST$")>; -def : InstRW<[FalkorWr_4LD_3cyc], (instregex "^LD1Fourv(16b|8h|4s|2d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_4LD_3cyc], (instregex "^LD1Fourv(16b|8h|4s|2d)_POST$")>; -def : InstRW<[FalkorWr_4LD_3cyc], (instrs LD4Fourv2d)>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_4LD_3cyc], (instrs LD4Fourv2d_POST)>; -def : InstRW<[FalkorWr_4LD_3cyc], (instregex "^LD4Rv(16b|8h|4s|2d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_4LD_3cyc], (instregex "^LD4Rv(16b|8h|4s|2d)_POST$")>; +def : InstRW<[FalkorWr_4LD_3cyc, FalkorReadIncLd], (instregex "^LD1Fourv(16b|8h|4s|2d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_4LD_3cyc, FalkorReadIncLd], + (instregex "^LD1Fourv(16b|8h|4s|2d)_POST$")>; +def : InstRW<[FalkorWr_4LD_3cyc, FalkorReadIncLd], (instrs LD4Fourv2d)>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_4LD_3cyc, FalkorReadIncLd], + (instrs LD4Fourv2d_POST)>; +def : InstRW<[FalkorWr_4LD_3cyc, FalkorReadIncLd], (instregex "^LD4Rv(16b|8h|4s|2d)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_4LD_3cyc, FalkorReadIncLd], + (instregex "^LD4Rv(16b|8h|4s|2d)_POST$")>; -def : InstRW<[FalkorWr_1LD_4VXVY_4cyc], (instregex "^LD4i(8|16|32)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_4VXVY_4cyc], (instregex "^LD4i(8|16|32)_POST$")>; +def : InstRW<[FalkorWr_1LD_4VXVY_4cyc, FalkorReadIncLd], (instregex "^LD4i(8|16|32)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_4VXVY_4cyc, FalkorReadIncLd], + (instregex "^LD4i(8|16|32)_POST$")>; -def : InstRW<[FalkorWr_2LD_2VXVY_1none_4cyc], (instregex "^LD3Threev(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_2VXVY_1none_4cyc], - (instregex "^LD3Threev(8b|4h|2s|1d)_POST$")>; +def : InstRW<[FalkorWr_2LD_2VXVY_1none_4cyc, FalkorReadIncLd], + (instregex "^LD3Threev(8b|4h|2s)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_2VXVY_1none_4cyc, FalkorReadIncLd], + (instregex "^LD3Threev(8b|4h|2s)_POST$")>; -def : InstRW<[FalkorWr_2LD_2VXVY_2none_4cyc], (instregex "^LD4Fourv(8b|4h|2s|1d)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_2VXVY_2none_4cyc], - (instregex "^LD4Fourv(8b|4h|2s|1d)_POST$")>; +def : InstRW<[FalkorWr_2LD_2VXVY_2none_4cyc, FalkorReadIncLd], + (instregex "^LD4Fourv(8b|4h|2s)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_2VXVY_2none_4cyc, FalkorReadIncLd], + (instregex "^LD4Fourv(8b|4h|2s)_POST$")>; -def : InstRW<[FalkorWr_2LD_2VXVY_2LD_2VXVY_4cyc], (instregex "^LD3Threev(16b|8h|4s)$")>; +def : InstRW<[FalkorWr_2LD_2VXVY_2LD_2VXVY_4cyc, FalkorReadIncLd], + (instregex "^LD3Threev(16b|8h|4s)$")>; -def : InstRW<[FalkorWr_2LD_2VXVY_2LD_2VXVY_4cyc], (instregex "^LD4Fourv(16b|8h|4s)$")>; +def : InstRW<[FalkorWr_2LD_2VXVY_2LD_2VXVY_4cyc, FalkorReadIncLd], + (instregex "^LD4Fourv(16b|8h|4s)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_2VXVY_1XYZ_2LD_2VXVY_4cyc], - (instregex "^LD3Threev(16b|8h|4s)_POST$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_2VXVY_1XYZ_2LD_2VXVY_4cyc, FalkorReadIncLd], + (instregex "^LD3Threev(16b|8h|4s)_POST$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_2VXVY_2LD_1XYZ_2VXVY_4cyc], - (instregex "^LD4Fourv(16b|8h|4s)_POST$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_2VXVY_2LD_1XYZ_2VXVY_4cyc, FalkorReadIncLd], + (instregex "^LD4Fourv(16b|8h|4s)_POST$")>; // Arithmetic and Logical Instructions // ----------------------------------------------------------------------------- @@ -929,87 +963,105 @@ def : InstRW<[FalkorWr_5VXVY_7cyc], (instregex "^TBX(v8i8Four|v16i8Four)$")>; // SIMD Store Instructions // ----------------------------------------------------------------------------- -def : InstRW<[FalkorWr_1VSD_1ST_0cyc], (instregex "^STR(Q|D|S|H|B)ui$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1VSD_1ST_0cyc], +def : InstRW<[FalkorWr_1VSD_1ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^STR(Q|D|S|H|B)ui$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1VSD_1ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^STR(Q|D|S|H|B)(post|pre)$")>; -def : InstRW<[FalkorWr_STRVro], (instregex "^STR(D|S|H|B)ro(W|X)$")>; -def : InstRW<[FalkorWr_2VSD_2ST_0cyc], (instregex "^STPQi$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2VSD_2ST_0cyc], +def : InstRW<[FalkorWr_STRVro, ReadDefault, FalkorReadIncSt], + (instregex "^STR(D|S|H|B)ro(W|X)$")>; +def : InstRW<[FalkorWr_2VSD_2ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instregex "^STPQi$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2VSD_2ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], (instregex "^STPQ(post|pre)$")>; -def : InstRW<[FalkorWr_1VSD_1ST_0cyc], (instregex "^STP(D|S)(i)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1VSD_1ST_0cyc], +def : InstRW<[FalkorWr_1VSD_1ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instregex "^STP(D|S)(i)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1VSD_1ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], (instregex "^STP(D|S)(post|pre)$")>; -def : InstRW<[FalkorWr_STRQro], (instregex "^STRQro(W|X)$")>; -def : InstRW<[FalkorWr_1VSD_1ST_0cyc], (instregex "^STUR(Q|D|S|B|H)i$")>; -def : InstRW<[FalkorWr_1VSD_1ST_0cyc], (instrs STNPDi, STNPSi)>; -def : InstRW<[FalkorWr_2VSD_2ST_0cyc], (instrs STNPQi)>; +def : InstRW<[FalkorWr_STRQro, ReadDefault, FalkorReadIncSt], + (instregex "^STRQro(W|X)$")>; +def : InstRW<[FalkorWr_1VSD_1ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^STUR(Q|D|S|B|H)i$")>; +def : InstRW<[FalkorWr_1VSD_1ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instrs STNPDi, STNPSi)>; +def : InstRW<[FalkorWr_2VSD_2ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instrs STNPQi)>; -def : InstRW<[FalkorWr_1VSD_1ST_0cyc], (instregex "^ST1(One(v8b|v4h|v2s|v1d)|(i8|i16|i32|i64)|One(v16b|v8h|v4s|v2d)|Two(v8b|v4h|v2s|v1d))$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1VSD_1ST_0cyc], +def : InstRW<[FalkorWr_1VSD_1ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST1(One(v8b|v4h|v2s|v1d)|(i8|i16|i32|i64)|One(v16b|v8h|v4s|v2d)|Two(v8b|v4h|v2s|v1d))$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1VSD_1ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST1(One(v8b|v4h|v2s|v1d)_POST|(i8|i16|i32|i64)_POST)$")>; -def : InstRW<[FalkorWr_1VSD_1ST_0cyc], (instregex "^ST2(Two(v8b|v4h|v2s|v1d)|(i8|i16|i32|i64))$")>; -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_1VSD_1ST_0cyc], +def : InstRW<[FalkorWr_1VSD_1ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST2(Two(v8b|v4h|v2s)|(i8|i16|i32|i64))$")>; +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_1VSD_1ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST1(One(v16b|v8h|v4s|v2d)|Two(v8b|v4h|v2s|v1d))_POST$")>; -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_1VSD_1ST_0cyc], - (instregex "^ST2(Two(v8b|v4h|v2s|v1d)|(i8|i16|i32|i64))_POST$")>; +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_1VSD_1ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST2(Two(v8b|v4h|v2s)|(i8|i16|i32|i64))_POST$")>; -def : InstRW<[FalkorWr_2VSD_2ST_0cyc], (instregex "^ST1(Two(v16b|v8h|v4s|v2d)|(Three|Four)(v8b|v4h|v2s|v1d))$")>; -def : InstRW<[FalkorWr_2VSD_2ST_0cyc], (instregex "^ST2Two(v16b|v8h|v4s|v2d)$")>; -def : InstRW<[FalkorWr_2VSD_2ST_0cyc], (instregex "^ST3(i8|i16|i32|i64)$")>; -def : InstRW<[FalkorWr_2VSD_2ST_0cyc], (instregex "^ST4(i8|i16|i32|i64)$")>; +def : InstRW<[FalkorWr_2VSD_2ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST1(Two(v16b|v8h|v4s|v2d)|(Three|Four)(v8b|v4h|v2s|v1d))$")>; +def : InstRW<[FalkorWr_2VSD_2ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST2Two(v16b|v8h|v4s|v2d)$")>; +def : InstRW<[FalkorWr_2VSD_2ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST3(i8|i16|i32|i64)$")>; +def : InstRW<[FalkorWr_2VSD_2ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST4(i8|i16|i32|i64)$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VSD_2ST_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VSD_2ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST1(Two(v16b|v8h|v4s|v2d)|(Three|Four)(v8b|v4h|v2s|v1d))_POST$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VSD_2ST_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VSD_2ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST2Two(v16b|v8h|v4s|v2d)_POST$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VSD_2ST_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VSD_2ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST3(i8|i16|i32|i64)_POST$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VSD_2ST_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VSD_2ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST4(i8|i16|i32|i64)_POST$")>; -def : InstRW<[FalkorWr_1VXVY_2ST_2VSD_0cyc], - (instregex "^ST3Three(v8b|v4h|v2s|v1d)$")>; +def : InstRW<[FalkorWr_1VXVY_2ST_2VSD_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST3Three(v8b|v4h|v2s)$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_1VXVY_2ST_2VSD_0cyc], - (instregex "^ST3Three(v8b|v4h|v2s|v1d)_POST$")>; +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_1VXVY_2ST_2VSD_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST3Three(v8b|v4h|v2s)_POST$")>; -def : InstRW<[FalkorWr_3VSD_3ST_0cyc], (instregex "^ST1Three(v16b|v8h|v4s|v2d)$")>; -def : InstRW<[FalkorWr_3VSD_3ST_0cyc], (instrs ST3Threev2d)>; +def : InstRW<[FalkorWr_3VSD_3ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST1Three(v16b|v8h|v4s|v2d)$")>; +def : InstRW<[FalkorWr_3VSD_3ST_0cyc, ReadDefault, FalkorReadIncSt], + (instrs ST3Threev2d)>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_3VSD_3ST_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_3VSD_3ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST1Three(v16b|v8h|v4s|v2d)_POST$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_3VSD_3ST_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_3VSD_3ST_0cyc, ReadDefault, FalkorReadIncSt], (instrs ST3Threev2d_POST)>; -def : InstRW<[FalkorWr_2VXVY_2ST_2VSD_0cyc], - (instregex "^ST4Four(v8b|v4h|v2s|v1d)$")>; +def : InstRW<[FalkorWr_2VXVY_2ST_2VSD_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST4Four(v8b|v4h|v2s)$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VXVY_2ST_2VSD_0cyc], - (instregex "^ST4Four(v8b|v4h|v2s|v1d)_POST$")>; +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VXVY_2ST_2VSD_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST4Four(v8b|v4h|v2s)_POST$")>; -def : InstRW<[FalkorWr_4VSD_4ST_0cyc], (instregex "^ST1Four(v16b|v8h|v4s|v2d)$")>; -def : InstRW<[FalkorWr_4VSD_4ST_0cyc], (instrs ST4Fourv2d)>; +def : InstRW<[FalkorWr_4VSD_4ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^ST1Four(v16b|v8h|v4s|v2d)$")>; +def : InstRW<[FalkorWr_4VSD_4ST_0cyc, ReadDefault, FalkorReadIncSt], + (instrs ST4Fourv2d)>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_4VSD_4ST_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_4VSD_4ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST1Four(v16b|v8h|v4s|v2d)_POST$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_4VSD_4ST_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_4VSD_4ST_0cyc, ReadDefault, FalkorReadIncSt], (instrs ST4Fourv2d_POST)>; -def : InstRW<[FalkorWr_2VXVY_4ST_4VSD_0cyc], +def : InstRW<[FalkorWr_2VXVY_4ST_4VSD_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST3Three(v16b|v8h|v4s)$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VXVY_4ST_4VSD_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_2VXVY_4ST_4VSD_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST3Three(v16b|v8h|v4s)_POST$")>; -def : InstRW<[FalkorWr_4VXVY_4ST_4VSD_0cyc], +def : InstRW<[FalkorWr_4VXVY_4ST_4VSD_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST4Four(v16b|v8h|v4s)$")>; // FIXME: This is overly conservative in the imm POST case (no XYZ used in that case). -def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_4VXVY_4ST_4VSD_0cyc], +def : InstRW<[FalkorWr_1XYZ_1cyc, FalkorWr_4VXVY_4ST_4VSD_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^ST4Four(v16b|v8h|v4s)_POST$")>; // Branch Instructions @@ -1033,22 +1085,25 @@ def : InstRW<[FalkorWr_4VXVY_3cyc], (instrs SHA256SU1rrr)>; // FP Load Instructions // ----------------------------------------------------------------------------- -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^LDR((Q|D|S|H|B)ui|(Q|D|S)l)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_3cyc], +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^LDR((Q|D|S|H|B)ui|(Q|D|S)l)$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_3cyc, FalkorReadIncLd], (instregex "^LDR(Q|D|S|H|B)(post|pre)$")>; -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^LDUR(Q|D|S|H|B)i$")>; -def : InstRW<[FalkorWr_LDRro], (instregex "^LDR(Q|D|H|S|B)ro(W|X)$")>; -def : InstRW<[FalkorWr_2LD_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^LDUR(Q|D|S|H|B)i$")>; +def : InstRW<[FalkorWr_LDRro, FalkorReadIncLd], + (instregex "^LDR(Q|D|H|S|B)ro(W|X)$")>; +def : InstRW<[FalkorWr_2LD_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instrs LDNPQi)>; -def : InstRW<[FalkorWr_2LD_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_2LD_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instrs LDPQi)>; -def : InstRW<[FalkorWr_1LD_1none_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_1LD_1none_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instregex "LDNP(D|S)i$")>; -def : InstRW<[FalkorWr_1LD_1none_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_1LD_1none_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instregex "LDP(D|S)i$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_1none_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_1none_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instregex "LDP(D|S)(pre|post)$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_2LD_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_2LD_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instregex "^LDPQ(pre|post)$")>; // FP Data Processing Instructions @@ -1106,31 +1161,41 @@ def : InstRW<[FalkorWr_2VXVY_4cyc], (instregex "^(S|U)CVTF(v2i64|v4i32|v2f64|v // ----------------------------------------------------------------------------- def : InstRW<[FalkorWr_1ST_0cyc], (instrs PRFMui, PRFMl)>; def : InstRW<[FalkorWr_1ST_0cyc], (instrs PRFUMi)>; -def : InstRW<[FalkorWr_1LD_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_1LD_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instregex "^LDNP(W|X)i$")>; -def : InstRW<[FalkorWr_1LD_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_1LD_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instregex "^LDP(W|X)i$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_3cyc, FalkorWr_none_3cyc], +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], (instregex "^LDP(W|X)(post|pre)$")>; -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^LDR(BB|HH|W|X)ui$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_3cyc], +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^LDR(BB|HH|W|X)ui$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_3cyc, FalkorReadIncLd], (instregex "^LDR(BB|HH|W|X)(post|pre)$")>; -def : InstRW<[FalkorWr_LDRro], (instregex "^LDR(BB|HH|W|X)ro(W|X)$")>; -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^LDR(W|X)l$")>; -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^LDTR(B|H|W|X)i$")>; -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^LDUR(BB|HH|W|X)i$")>; +def : InstRW<[FalkorWr_LDRro, FalkorReadIncLd], + (instregex "^LDR(BB|HH|W|X)ro(W|X)$")>; +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^LDR(W|X)l$")>; +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^LDTR(B|H|W|X)i$")>; +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^LDUR(BB|HH|W|X)i$")>; def : InstRW<[FalkorWr_PRFMro], (instregex "^PRFMro(W|X)$")>; -def : InstRW<[FalkorWr_1LD_4cyc, FalkorWr_none_4cyc], +def : InstRW<[FalkorWr_1LD_4cyc, FalkorWr_none_4cyc, FalkorReadIncLd], (instrs LDPSWi)>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_4cyc, FalkorWr_none_4cyc], +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_4cyc, FalkorWr_none_4cyc, FalkorReadIncLd], (instregex "^LDPSW(post|pre)$")>; -def : InstRW<[FalkorWr_1LD_4cyc], (instregex "^LDRS(BW|BX|HW|HX|W)ui$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1LD_4cyc], +def : InstRW<[FalkorWr_1LD_4cyc, FalkorReadIncLd], + (instregex "^LDRS(BW|BX|HW|HX|W)ui$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1LD_4cyc, FalkorReadIncLd], (instregex "^LDRS(BW|BX|HW|HX|W)(post|pre)$")>; -def : InstRW<[FalkorWr_LDRSro], (instregex "^LDRS(BW|BX|HW|HX|W)ro(W|X)$")>; -def : InstRW<[FalkorWr_1LD_4cyc], (instrs LDRSWl)>; -def : InstRW<[FalkorWr_1LD_4cyc], (instregex "^LDTRS(BW|BX|HW|HX|W)i$")>; -def : InstRW<[FalkorWr_1LD_4cyc], (instregex "^LDURS(BW|BX|HW|HX|W)i$")>; +def : InstRW<[FalkorWr_LDRSro, FalkorReadIncLd], + (instregex "^LDRS(BW|BX|HW|HX|W)ro(W|X)$")>; +def : InstRW<[FalkorWr_1LD_4cyc, FalkorReadIncLd], + (instrs LDRSWl)>; +def : InstRW<[FalkorWr_1LD_4cyc, FalkorReadIncLd], + (instregex "^LDTRS(BW|BX|HW|HX|W)i$")>; +def : InstRW<[FalkorWr_1LD_4cyc, FalkorReadIncLd], + (instregex "^LDURS(BW|BX|HW|HX|W)i$")>; // Miscellaneous Data-Processing Instructions // ----------------------------------------------------------------------------- @@ -1178,32 +1243,46 @@ def : InstRW<[FalkorWr_1none_0cyc], (instrs BRK, DCPS1, DCPS2, DCPS3, HINT, HL def : InstRW<[FalkorWr_1ST_0cyc], (instrs SYSxt, SYSLxt)>; def : InstRW<[FalkorWr_1Z_0cyc], (instrs MSRpstateImm1, MSRpstateImm4)>; -def : InstRW<[FalkorWr_1LD_3cyc], (instregex "^(LDAR(B|H|W|X)|LDAXP(W|X)|LDAXR(B|H|W|X)|LDXP(W|X)|LDXR(B|H|W|X))$")>; +def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd], + (instregex "^(LDAR(B|H|W|X)|LDAXR(B|H|W|X)|LDXR(B|H|W|X))$")>; +def : InstRW<[FalkorWr_1LD_3cyc, FalkorWr_none_3cyc, FalkorReadIncLd], + (instregex "^(LDAXP(W|X)|LDXP(W|X))$")>; def : InstRW<[FalkorWr_1LD_3cyc], (instrs MRS, MOVbaseTLS)>; def : InstRW<[FalkorWr_1LD_1Z_3cyc], (instrs DRPS)>; def : InstRW<[FalkorWr_1SD_1ST_0cyc], (instrs MSR)>; -def : InstRW<[FalkorWr_1SD_1ST_0cyc], (instrs STNPWi, STNPXi)>; +def : InstRW<[FalkorWr_1SD_1ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instrs STNPWi, STNPXi)>; def : InstRW<[FalkorWr_2LD_1Z_3cyc], (instrs ERET)>; def : InstRW<[FalkorWr_1ST_1SD_1LD_3cyc], (instregex "^LDC.*$")>; -def : InstRW<[FalkorWr_1ST_1SD_1LD_0cyc], (instregex "^STLR(B|H|W|X)$")>; -def : InstRW<[FalkorWr_1ST_1SD_1LD_0cyc], (instregex "^STXP(W|X)$")>; -def : InstRW<[FalkorWr_1ST_1SD_1LD_0cyc], (instregex "^STXR(B|H|W|X)$")>; +def : InstRW<[FalkorWr_1ST_1SD_1LD_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^STLR(B|H|W|X)$")>; +def : InstRW<[FalkorWr_1ST_1SD_1LD_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instregex "^STXP(W|X)$")>; +def : InstRW<[FalkorWr_1ST_1SD_1LD_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instregex "^STXR(B|H|W|X)$")>; -def : InstRW<[FalkorWr_2LD_1ST_1SD_3cyc], (instregex "^STLXP(W|X)$")>; -def : InstRW<[FalkorWr_2LD_1ST_1SD_3cyc], (instregex "^STLXR(B|H|W|X)$")>; +def : InstRW<[FalkorWr_2LD_1ST_1SD_3cyc, ReadDefault, ReadDefault, ReadDefault, FalkorReadIncSt], + (instregex "^STLXP(W|X)$")>; +def : InstRW<[FalkorWr_2LD_1ST_1SD_3cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instregex "^STLXR(B|H|W|X)$")>; // Store Instructions // ----------------------------------------------------------------------------- -def : InstRW<[FalkorWr_1SD_1ST_0cyc], (instregex "^STP(W|X)i$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1SD_1ST_0cyc], +def : InstRW<[FalkorWr_1SD_1ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], + (instregex "^STP(W|X)i$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1SD_1ST_0cyc, ReadDefault, ReadDefault, FalkorReadIncSt], (instregex "^STP(W|X)(post|pre)$")>; -def : InstRW<[FalkorWr_1SD_1ST_0cyc], (instregex "^STR(BB|HH|W|X)ui$")>; -def : InstRW<[FalkorWr_none_1cyc, FalkorWr_1SD_1ST_0cyc], +def : InstRW<[FalkorWr_1SD_1ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^STR(BB|HH|W|X)ui$")>; +def : InstRW<[FalkorWr_LdStInc_none_3cyc, FalkorWr_1SD_1ST_0cyc, ReadDefault, FalkorReadIncSt], (instregex "^STR(BB|HH|W|X)(post|pre)$")>; -def : InstRW<[FalkorWr_STRro], (instregex "^STR(BB|HH|W|X)ro(W|X)$")>; -def : InstRW<[FalkorWr_1SD_1ST_0cyc], (instregex "^STTR(B|H|W|X)i$")>; -def : InstRW<[FalkorWr_1SD_1ST_0cyc], (instregex "^STUR(BB|HH|W|X)i$")>; +def : InstRW<[FalkorWr_STRro, ReadDefault, FalkorReadIncSt], + (instregex "^STR(BB|HH|W|X)ro(W|X)$")>; +def : InstRW<[FalkorWr_1SD_1ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^STTR(B|H|W|X)i$")>; +def : InstRW<[FalkorWr_1SD_1ST_0cyc, ReadDefault, FalkorReadIncSt], + (instregex "^STUR(BB|HH|W|X)i$")>; diff --git a/contrib/llvm/lib/Target/AArch64/AArch64SchedKryoDetails.td b/contrib/llvm/lib/Target/AArch64/AArch64SchedKryoDetails.td index 02cccccd3078..cf4cdabb8cbf 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64SchedKryoDetails.td +++ b/contrib/llvm/lib/Target/AArch64/AArch64SchedKryoDetails.td @@ -1374,7 +1374,9 @@ def KryoWrite_3cyc_LS_LS_400ln : let Latency = 3; let NumMicroOps = 2; } def : InstRW<[KryoWrite_3cyc_LS_LS_400ln], - (instregex "(LDAX?R(B|H|W|X)|LDAXP(W|X))")>; + (instregex "LDAX?R(B|H|W|X)")>; +def : InstRW<[KryoWrite_3cyc_LS_LS_400ln, WriteLDHi], + (instregex "LDAXP(W|X)")>; def KryoWrite_3cyc_LS_LS_401ln : SchedWriteRes<[KryoUnitLS, KryoUnitLS]> { let Latency = 3; let NumMicroOps = 2; @@ -1565,7 +1567,7 @@ def KryoWrite_3cyc_LS_258ln : SchedWriteRes<[KryoUnitLS]> { let Latency = 3; let NumMicroOps = 1; } -def : InstRW<[KryoWrite_3cyc_LS_258ln], +def : InstRW<[KryoWrite_3cyc_LS_258ln, WriteLDHi], (instregex "LDXP(W|X)")>; def KryoWrite_3cyc_LS_258_1ln : SchedWriteRes<[KryoUnitLS]> { diff --git a/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp index d4a8cecdb29f..6660f0babb8a 100644 --- a/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/contrib/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -47,6 +47,11 @@ static cl::opt EnableCCMP("aarch64-enable-ccmp", cl::desc("Enable the CCMP formation pass"), cl::init(true), cl::Hidden); +static cl::opt + EnableCondBrTuning("aarch64-enable-cond-br-tune", + cl::desc("Enable the conditional branch tuning pass"), + cl::init(true), cl::Hidden); + static cl::opt EnableMCR("aarch64-enable-mcr", cl::desc("Enable the machine combiner pass"), cl::init(true), cl::Hidden); @@ -429,6 +434,8 @@ bool AArch64PassConfig::addILPOpts() { addPass(createAArch64ConditionalCompares()); if (EnableMCR) addPass(&MachineCombinerID); + if (EnableCondBrTuning) + addPass(createAArch64CondBrTuning()); if (EnableEarlyIfConversion) addPass(&EarlyIfConverterID); if (EnableStPairSuppress) diff --git a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp index 43a6fa9ce089..3d075018904c 100644 --- a/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ b/contrib/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -43,26 +43,25 @@ class AArch64AsmBackend : public MCAsmBackend { const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { const static MCFixupKindInfo Infos[AArch64::NumTargetFixupKinds] = { - // This table *must* be in the order that the fixup_* kinds are defined in - // AArch64FixupKinds.h. - // - // Name Offset (bits) Size (bits) Flags - { "fixup_aarch64_pcrel_adr_imm21", 0, 32, PCRelFlagVal }, - { "fixup_aarch64_pcrel_adrp_imm21", 0, 32, PCRelFlagVal }, - { "fixup_aarch64_add_imm12", 10, 12, 0 }, - { "fixup_aarch64_ldst_imm12_scale1", 10, 12, 0 }, - { "fixup_aarch64_ldst_imm12_scale2", 10, 12, 0 }, - { "fixup_aarch64_ldst_imm12_scale4", 10, 12, 0 }, - { "fixup_aarch64_ldst_imm12_scale8", 10, 12, 0 }, - { "fixup_aarch64_ldst_imm12_scale16", 10, 12, 0 }, - { "fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal }, - { "fixup_aarch64_movw", 5, 16, 0 }, - { "fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal }, - { "fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal }, - { "fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal }, - { "fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal }, - { "fixup_aarch64_tlsdesc_call", 0, 0, 0 } - }; + // This table *must* be in the order that the fixup_* kinds are defined + // in AArch64FixupKinds.h. + // + // Name Offset (bits) Size (bits) Flags + {"fixup_aarch64_pcrel_adr_imm21", 0, 32, PCRelFlagVal}, + {"fixup_aarch64_pcrel_adrp_imm21", 0, 32, PCRelFlagVal}, + {"fixup_aarch64_add_imm12", 10, 12, 0}, + {"fixup_aarch64_ldst_imm12_scale1", 10, 12, 0}, + {"fixup_aarch64_ldst_imm12_scale2", 10, 12, 0}, + {"fixup_aarch64_ldst_imm12_scale4", 10, 12, 0}, + {"fixup_aarch64_ldst_imm12_scale8", 10, 12, 0}, + {"fixup_aarch64_ldst_imm12_scale16", 10, 12, 0}, + {"fixup_aarch64_ldr_pcrel_imm19", 5, 19, PCRelFlagVal}, + {"fixup_aarch64_movw", 5, 16, 0}, + {"fixup_aarch64_pcrel_branch14", 5, 14, PCRelFlagVal}, + {"fixup_aarch64_pcrel_branch19", 5, 19, PCRelFlagVal}, + {"fixup_aarch64_pcrel_branch26", 0, 26, PCRelFlagVal}, + {"fixup_aarch64_pcrel_call26", 0, 26, PCRelFlagVal}, + {"fixup_aarch64_tlsdesc_call", 0, 0, 0}}; if (Kind < FirstTargetFixupKind) return MCAsmBackend::getFixupKindInfo(Kind); @@ -72,8 +71,9 @@ class AArch64AsmBackend : public MCAsmBackend { return Infos[Kind - FirstTargetFixupKind]; } - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; bool mayNeedRelaxation(const MCInst &Inst) const override; bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, @@ -261,13 +261,15 @@ unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) con } } -void AArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, - bool IsPCRel, MCContext &Ctx) const { +void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsPCRel) const { unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); if (!Value) return; // Doesn't change encoding. MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind()); + MCContext &Ctx = Asm.getContext(); // Apply any target-specific value adjustments. Value = adjustFixupValue(Fixup, Value, Ctx); @@ -275,7 +277,7 @@ void AArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data, Value <<= Info.TargetOffset; unsigned Offset = Fixup.getOffset(); - assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); // Used to point to big endian bytes. unsigned FulleSizeInBytes = getFixupKindContainereSizeInBytes(Fixup.getKind()); @@ -289,7 +291,7 @@ void AArch64AsmBackend::applyFixup(const MCFixup &Fixup, char *Data, } } else { // Handle as big-endian - assert((Offset + FulleSizeInBytes) <= DataSize && "Invalid fixup size!"); + assert((Offset + FulleSizeInBytes) <= Data.size() && "Invalid fixup size!"); assert(NumBytes <= FulleSizeInBytes && "Invalid fixup size!"); for (unsigned i = 0; i != NumBytes; ++i) { unsigned Idx = FulleSizeInBytes - 1 - i; @@ -539,16 +541,14 @@ class ELFAArch64AsmBackend : public AArch64AsmBackend { return createAArch64ELFObjectWriter(OS, OSABI, IsLittleEndian, IsILP32); } - void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFixup &Fixup, const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) override; + void processFixupValue(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, bool &IsResolved) override; }; -void ELFAArch64AsmBackend::processFixupValue( - const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFixup &Fixup, - const MCFragment *DF, const MCValue &Target, uint64_t &Value, - bool &IsResolved) { +void ELFAArch64AsmBackend::processFixupValue(const MCAssembler &Asm, + const MCFixup &Fixup, + const MCValue &Target, + bool &IsResolved) { // The ADRP instruction adds some multiple of 0x1000 to the current PC & // ~0xfff. This means that the required offset to reach a symbol can vary by // up to one step depending on where the ADRP is in memory. For example: diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPU.td b/contrib/llvm/lib/Target/AMDGPU/AMDGPU.td index 6ab2b9ef0459..7494e5decd6f 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPU.td +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPU.td @@ -238,6 +238,36 @@ def FeatureSDWA : SubtargetFeature<"sdwa", "Support SDWA (Sub-DWORD Addressing) extension" >; +def FeatureSDWAOmod : SubtargetFeature<"sdwa-omod", + "HasSDWAOmod", + "true", + "Support OMod with SDWA (Sub-DWORD Addressing) extension" +>; + +def FeatureSDWAScalar : SubtargetFeature<"sdwa-scalar", + "HasSDWAScalar", + "true", + "Support scalar register with SDWA (Sub-DWORD Addressing) extension" +>; + +def FeatureSDWASdst : SubtargetFeature<"sdwa-sdst", + "HasSDWASdst", + "true", + "Support scalar dst for VOPC with SDWA (Sub-DWORD Addressing) extension" +>; + +def FeatureSDWAMac : SubtargetFeature<"sdwa-mav", + "HasSDWAMac", + "true", + "Support v_mac_f32/f16 with SDWA (Sub-DWORD Addressing) extension" +>; + +def FeatureSDWAClampVOPC : SubtargetFeature<"sdwa-clamp-vopc", + "HasSDWAClampVOPC", + "true", + "Support clamp for VOPC with SDWA (Sub-DWORD Addressing) extension" +>; + def FeatureDPP : SubtargetFeature<"dpp", "HasDPP", "true", @@ -421,8 +451,8 @@ def FeatureVolcanicIslands : SubtargetFeatureGeneration<"VOLCANIC_ISLANDS", FeatureWavefrontSize64, FeatureFlatAddressSpace, FeatureGCN, FeatureGCN3Encoding, FeatureCIInsts, Feature16BitInsts, FeatureSMemRealTime, FeatureVGPRIndexMode, FeatureMovrel, - FeatureScalarStores, FeatureInv2PiInlineImm, FeatureSDWA, - FeatureDPP + FeatureScalarStores, FeatureInv2PiInlineImm, + FeatureSDWA, FeatureSDWAClampVOPC, FeatureSDWAMac, FeatureDPP ] >; @@ -432,7 +462,8 @@ def FeatureGFX9 : SubtargetFeatureGeneration<"GFX9", FeatureGCN3Encoding, FeatureCIInsts, Feature16BitInsts, FeatureSMemRealTime, FeatureScalarStores, FeatureInv2PiInlineImm, FeatureApertureRegs, FeatureGFX9Insts, FeatureVOP3P, FeatureVGPRIndexMode, - FeatureFastFMAF32, FeatureSDWA, FeatureDPP, + FeatureFastFMAF32, FeatureDPP, + FeatureSDWA, FeatureSDWAOmod, FeatureSDWAScalar, FeatureSDWASdst, FeatureFlatInstOffsets, FeatureFlatGlobalInsts, FeatureFlatScratchInsts ] >; @@ -449,14 +480,14 @@ class SubtargetFeatureISAVersion ; def FeatureISAVersion6_0_1 : SubtargetFeatureISAVersion <6,0,1, [FeatureSouthernIslands, FeatureLDSBankCount32]>; - + def FeatureISAVersion7_0_0 : SubtargetFeatureISAVersion <7,0,0, [FeatureSeaIslands, FeatureLDSBankCount32]>; @@ -644,7 +675,11 @@ def isCIVI : Predicate < "Subtarget->getGeneration() >= AMDGPUSubtarget::SEA_ISLANDS">, AssemblerPredicate<"FeatureCIInsts">; -def HasFlatAddressSpace : Predicate<"Subtarget->hasFlatAddressSpace()">; +def HasFlatAddressSpace : Predicate<"Subtarget->hasFlatAddressSpace()">, + AssemblerPredicate<"FeatureFlatAddressSpace">; + +def HasFlatGlobalInsts : Predicate<"Subtarget->hasFlatGlobalInsts()">, + AssemblerPredicate<"FeatureFlatGlobalInsts">; def Has16BitInsts : Predicate<"Subtarget->has16BitInsts()">, AssemblerPredicate<"Feature16BitInsts">; diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index 5586b513b5fc..96f819fd0e68 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -3527,18 +3527,25 @@ SDValue AMDGPUTargetLowering::PerformDAGCombine(SDNode *N, //===----------------------------------------------------------------------===// SDValue AMDGPUTargetLowering::CreateLiveInRegister(SelectionDAG &DAG, - const TargetRegisterClass *RC, - unsigned Reg, EVT VT) const { + const TargetRegisterClass *RC, + unsigned Reg, EVT VT, + const SDLoc &SL, + bool RawReg) const { MachineFunction &MF = DAG.getMachineFunction(); MachineRegisterInfo &MRI = MF.getRegInfo(); - unsigned VirtualRegister; + unsigned VReg; + if (!MRI.isLiveIn(Reg)) { - VirtualRegister = MRI.createVirtualRegister(RC); - MRI.addLiveIn(Reg, VirtualRegister); + VReg = MRI.createVirtualRegister(RC); + MRI.addLiveIn(Reg, VReg); } else { - VirtualRegister = MRI.getLiveInVirtReg(Reg); + VReg = MRI.getLiveInVirtReg(Reg); } - return DAG.getRegister(VirtualRegister, VT); + + if (RawReg) + return DAG.getRegister(VReg, VT); + + return DAG.getCopyFromReg(DAG.getEntryNode(), SL, VReg, VT); } uint32_t AMDGPUTargetLowering::getImplicitParameterOffset( @@ -3657,6 +3664,8 @@ const char* AMDGPUTargetLowering::getTargetNodeName(unsigned Opcode) const { NODE_NAME_CASE(STORE_MSKOR) NODE_NAME_CASE(LOAD_CONSTANT) NODE_NAME_CASE(TBUFFER_STORE_FORMAT) + NODE_NAME_CASE(TBUFFER_STORE_FORMAT_X3) + NODE_NAME_CASE(TBUFFER_LOAD_FORMAT) NODE_NAME_CASE(ATOMIC_CMP_SWAP) NODE_NAME_CASE(ATOMIC_INC) NODE_NAME_CASE(ATOMIC_DEC) diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h index 0d066cdbdff4..a45234e2b39f 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -216,10 +216,25 @@ class AMDGPUTargetLowering : public TargetLowering { /// \brief Helper function that adds Reg to the LiveIn list of the DAG's /// MachineFunction. /// - /// \returns a RegisterSDNode representing Reg. - virtual SDValue CreateLiveInRegister(SelectionDAG &DAG, - const TargetRegisterClass *RC, - unsigned Reg, EVT VT) const; + /// \returns a RegisterSDNode representing Reg if \p RawReg is true, otherwise + /// a copy from the register. + SDValue CreateLiveInRegister(SelectionDAG &DAG, + const TargetRegisterClass *RC, + unsigned Reg, EVT VT, + const SDLoc &SL, + bool RawReg = false) const; + SDValue CreateLiveInRegister(SelectionDAG &DAG, + const TargetRegisterClass *RC, + unsigned Reg, EVT VT) const { + return CreateLiveInRegister(DAG, RC, Reg, VT, SDLoc(DAG.getEntryNode())); + } + + // Returns the raw live in register rather than a copy from it. + SDValue CreateLiveInRegisterRaw(SelectionDAG &DAG, + const TargetRegisterClass *RC, + unsigned Reg, EVT VT) const { + return CreateLiveInRegister(DAG, RC, Reg, VT, SDLoc(DAG.getEntryNode()), true); + } enum ImplicitParameter { FIRST_IMPLICIT, @@ -388,6 +403,8 @@ enum NodeType : unsigned { STORE_MSKOR, LOAD_CONSTANT, TBUFFER_STORE_FORMAT, + TBUFFER_STORE_FORMAT_X3, + TBUFFER_LOAD_FORMAT, ATOMIC_CMP_SWAP, ATOMIC_INC, ATOMIC_DEC, diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp index a01f5d37c7c1..69dc52986172 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.cpp @@ -66,7 +66,9 @@ int AMDGPUInstrInfo::getMaskedMIMGOp(uint16_t Opcode, unsigned Channels) const { // This must be kept in sync with the SIEncodingFamily class in SIInstrInfo.td enum SIEncodingFamily { SI = 0, - VI = 1 + VI = 1, + SDWA = 2, + SDWA9 = 3 }; // Wrapper for Tablegen'd function. enum Subtarget is not defined in any @@ -101,7 +103,12 @@ static SIEncodingFamily subtargetEncodingFamily(const AMDGPUSubtarget &ST) { } int AMDGPUInstrInfo::pseudoToMCOpcode(int Opcode) const { - int MCOp = AMDGPU::getMCOpcode(Opcode, subtargetEncodingFamily(ST)); + SIEncodingFamily Gen = subtargetEncodingFamily(ST); + if (get(Opcode).TSFlags & SIInstrFlags::SDWA) + Gen = ST.getGeneration() == AMDGPUSubtarget::GFX9 ? SIEncodingFamily::SDWA9 + : SIEncodingFamily::SDWA; + + int MCOp = AMDGPU::getMCOpcode(Opcode, Gen); // -1 means that Opcode is already a native instruction. if (MCOp == -1) diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td index e286558ce60d..bcf89bb78ad6 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUInstrInfo.td @@ -70,6 +70,10 @@ def AMDGPUElseBreakOp : SDTypeProfile<1, 2, [SDTCisVT<0, i64>, SDTCisVT<1, i64>, SDTCisVT<2, i64>] >; +def AMDGPUAddeSubeOp : SDTypeProfile<2, 3, + [SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, SDTCisVT<0, i32>, SDTCisVT<1, i1>, SDTCisVT<4, i1>] +>; + //===----------------------------------------------------------------------===// // AMDGPU DAG Nodes // @@ -179,6 +183,12 @@ def AMDGPUcarry : SDNode<"AMDGPUISD::CARRY", SDTIntBinOp, []>; // out = (src1 > src0) ? 1 : 0 def AMDGPUborrow : SDNode<"AMDGPUISD::BORROW", SDTIntBinOp, []>; +// TODO: remove AMDGPUadde/AMDGPUsube when ADDCARRY/SUBCARRY get their own +// nodes in TargetSelectionDAG.td. +def AMDGPUadde : SDNode<"ISD::ADDCARRY", AMDGPUAddeSubeOp, []>; + +def AMDGPUsube : SDNode<"ISD::SUBCARRY", AMDGPUAddeSubeOp, []>; + def AMDGPUSetCCOp : SDTypeProfile<1, 3, [ // setcc SDTCisVT<0, i64>, SDTCisSameAs<1, 2>, SDTCisVT<3, OtherVT> ]>; diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp index 790a69b84397..cc56216c355b 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp @@ -29,12 +29,20 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo() { using namespace TargetOpcode; const LLT S1= LLT::scalar(1); + const LLT V2S16 = LLT::vector(2, 16); const LLT S32 = LLT::scalar(32); const LLT S64 = LLT::scalar(64); const LLT P1 = LLT::pointer(1, 64); const LLT P2 = LLT::pointer(2, 64); setAction({G_ADD, S32}, Legal); + setAction({G_AND, S32}, Legal); + + setAction({G_BITCAST, V2S16}, Legal); + setAction({G_BITCAST, 1, S32}, Legal); + + setAction({G_BITCAST, S32}, Legal); + setAction({G_BITCAST, 1, V2S16}, Legal); // FIXME: i1 operands to intrinsics should always be legal, but other i1 // values may not be legal. We need to figure out how to distinguish @@ -61,6 +69,8 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo() { setAction({G_SELECT, S32}, Legal); setAction({G_SELECT, 1, S1}, Legal); + setAction({G_SHL, S32}, Legal); + setAction({G_STORE, S32}, Legal); setAction({G_STORE, 1, P1}, Legal); diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp index 8d157e2f98f2..ab5abf2039a5 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.cpp @@ -124,6 +124,11 @@ AMDGPUSubtarget::AMDGPUSubtarget(const Triple &TT, StringRef GPU, StringRef FS, HasScalarStores(false), HasInv2PiInlineImm(false), HasSDWA(false), + HasSDWAOmod(false), + HasSDWAScalar(false), + HasSDWASdst(false), + HasSDWAMac(false), + HasSDWAClampVOPC(false), HasDPP(false), FlatAddressSpace(false), FlatInstOffsets(false), diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h index 5f4f20316a6b..2b16289c723e 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUSubtarget.h @@ -149,6 +149,11 @@ class AMDGPUSubtarget : public AMDGPUGenSubtargetInfo { bool HasScalarStores; bool HasInv2PiInlineImm; bool HasSDWA; + bool HasSDWAOmod; + bool HasSDWAScalar; + bool HasSDWASdst; + bool HasSDWAMac; + bool HasSDWAClampVOPC; bool HasDPP; bool FlatAddressSpace; bool FlatInstOffsets; @@ -431,6 +436,26 @@ class AMDGPUSubtarget : public AMDGPUGenSubtargetInfo { return HasSDWA; } + bool hasSDWAOmod() const { + return HasSDWAOmod; + } + + bool hasSDWAScalar() const { + return HasSDWAScalar; + } + + bool hasSDWASdst() const { + return HasSDWASdst; + } + + bool hasSDWAMac() const { + return HasSDWAMac; + } + + bool hasSDWAClampVOPC() const { + return HasSDWAClampVOPC; + } + /// \brief Returns the offset in bytes from the start of the input buffer /// of the first explicit kernel argument. unsigned getExplicitKernelArgOffset(const MachineFunction &MF) const { diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp index b644eba536fa..04fe9f689806 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp @@ -342,6 +342,14 @@ void AMDGPUTargetMachine::adjustPassManager(PassManagerBuilder &Builder) { PM.add(createAMDGPUExternalAAWrapperPass()); } }); + + Builder.addExtension( + PassManagerBuilder::EP_CGSCCOptimizerLate, + [](const PassManagerBuilder &, legacy::PassManagerBase &PM) { + // Add infer address spaces pass to the opt pipeline after inlining + // but before SROA to increase SROA opportunities. + PM.add(createInferAddressSpacesPass()); + }); } //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp index 0d6689bd04c4..88245b01683a 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp @@ -184,9 +184,9 @@ void AMDGPUTTIImpl::getUnrollingPreferences(Loop *L, } } -unsigned AMDGPUTTIImpl::getNumberOfRegisters(bool Vec) { - if (Vec) - return 0; +unsigned AMDGPUTTIImpl::getHardwareNumberOfRegisters(bool Vec) const { + // The concept of vector registers doesn't really exist. Some packed vector + // operations operate on the normal 32-bit registers. // Number of VGPRs on SI. if (ST->getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS) @@ -195,8 +195,18 @@ unsigned AMDGPUTTIImpl::getNumberOfRegisters(bool Vec) { return 4 * 128; // XXX - 4 channels. Should these count as vector instead? } +unsigned AMDGPUTTIImpl::getNumberOfRegisters(bool Vec) const { + // This is really the number of registers to fill when vectorizing / + // interleaving loops, so we lie to avoid trying to use all registers. + return getHardwareNumberOfRegisters(Vec) >> 3; +} + unsigned AMDGPUTTIImpl::getRegisterBitWidth(bool Vector) const { - return Vector ? 0 : 32; + return 32; +} + +unsigned AMDGPUTTIImpl::getMinVectorRegisterBitWidth() const { + return 32; } unsigned AMDGPUTTIImpl::getLoadStoreVecRegBitWidth(unsigned AddrSpace) const { @@ -247,11 +257,11 @@ bool AMDGPUTTIImpl::isLegalToVectorizeStoreChain(unsigned ChainSizeInBytes, unsigned AMDGPUTTIImpl::getMaxInterleaveFactor(unsigned VF) { // Disable unrolling if the loop is not vectorized. + // TODO: Enable this again. if (VF == 1) return 1; - // Semi-arbitrary large amount. - return 64; + return 8; } int AMDGPUTTIImpl::getArithmeticInstrCost( diff --git a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h index a60b1bb1b59c..485e20411ab4 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h +++ b/contrib/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.h @@ -75,8 +75,10 @@ class AMDGPUTTIImpl final : public BasicTTIImplBase { return TTI::PSK_FastHardware; } - unsigned getNumberOfRegisters(bool Vector); - unsigned getRegisterBitWidth(bool Vector) const; + unsigned getHardwareNumberOfRegisters(bool Vector) const; + unsigned getNumberOfRegisters(bool Vector) const; + unsigned getRegisterBitWidth(bool Vector) const ; + unsigned getMinVectorRegisterBitWidth() const; unsigned getLoadStoreVecRegBitWidth(unsigned AddrSpace) const; bool isLegalToVectorizeMemChain(unsigned ChainSizeInBytes, diff --git a/contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp b/contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp index 392e9d89bd9b..7b8756050b75 100644 --- a/contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -152,6 +152,8 @@ class AMDGPUOperand : public MCParsedAsmOperand { ImmTyExpTgt, ImmTyExpCompr, ImmTyExpVM, + ImmTyDFMT, + ImmTyNFMT, ImmTyHwreg, ImmTyOff, ImmTySendMsg, @@ -260,6 +262,8 @@ class AMDGPUOperand : public MCParsedAsmOperand { return isOff() || isRegClass(AMDGPU::VGPR_32RegClassID); } + bool isSDWARegKind() const; + bool isImmTy(ImmTy ImmT) const { return isImm() && Imm.Type == ImmT; } @@ -292,6 +296,8 @@ class AMDGPUOperand : public MCParsedAsmOperand { bool isGLC() const { return isImmTy(ImmTyGLC); } bool isSLC() const { return isImmTy(ImmTySLC); } bool isTFE() const { return isImmTy(ImmTyTFE); } + bool isDFMT() const { return isImmTy(ImmTyDFMT) && isUInt<8>(getImm()); } + bool isNFMT() const { return isImmTy(ImmTyNFMT) && isUInt<8>(getImm()); } bool isBankMask() const { return isImmTy(ImmTyDppBankMask); } bool isRowMask() const { return isImmTy(ImmTyDppRowMask); } bool isBoundCtrl() const { return isImmTy(ImmTyDppBoundCtrl); } @@ -636,6 +642,8 @@ class AMDGPUOperand : public MCParsedAsmOperand { case ImmTyGLC: OS << "GLC"; break; case ImmTySLC: OS << "SLC"; break; case ImmTyTFE: OS << "TFE"; break; + case ImmTyDFMT: OS << "DFMT"; break; + case ImmTyNFMT: OS << "NFMT"; break; case ImmTyClampSI: OS << "ClampSI"; break; case ImmTyOModSI: OS << "OModSI"; break; case ImmTyDppCtrl: OS << "DppCtrl"; break; @@ -993,7 +1001,9 @@ class AMDGPUAsmParser : public MCTargetAsmParser { void errorExpTgt(); OperandMatchResultTy parseExpTgtImpl(StringRef Str, uint8_t &Val); - bool validateOperandLimitations(const MCInst &Inst); + bool validateInstruction(const MCInst &Inst, const SMLoc &IDLoc); + bool validateConstantBusLimitations(const MCInst &Inst); + bool validateEarlyClobberLimitations(const MCInst &Inst); bool usesConstantBus(const MCInst &Inst, unsigned OpIdx); bool isInlineConstant(const MCInst &Inst, unsigned OpIdx) const; unsigned findImplicitSGPRReadInVOP(const MCInst &Inst) const; @@ -1029,6 +1039,8 @@ class AMDGPUAsmParser : public MCTargetAsmParser { void cvtMubuf(MCInst &Inst, const OperandVector &Operands) { cvtMubufImpl(Inst, Operands, false, false); } void cvtMubufAtomic(MCInst &Inst, const OperandVector &Operands) { cvtMubufImpl(Inst, Operands, true, false); } void cvtMubufAtomicReturn(MCInst &Inst, const OperandVector &Operands) { cvtMubufImpl(Inst, Operands, true, true); } + void cvtMtbuf(MCInst &Inst, const OperandVector &Operands); + AMDGPUOperand::Ptr defaultGLC() const; AMDGPUOperand::Ptr defaultSLC() const; AMDGPUOperand::Ptr defaultTFE() const; @@ -1042,6 +1054,7 @@ class AMDGPUAsmParser : public MCTargetAsmParser { AMDGPUOperand::Ptr defaultSMRDOffset20() const; AMDGPUOperand::Ptr defaultSMRDLiteralOffset() const; AMDGPUOperand::Ptr defaultOffsetU12() const; + AMDGPUOperand::Ptr defaultOffsetS13() const; OperandMatchResultTy parseOModOperand(OperandVector &Operands); @@ -1243,6 +1256,15 @@ bool AMDGPUOperand::isRegClass(unsigned RCID) const { return isRegKind() && AsmParser->getMRI()->getRegClass(RCID).contains(getReg()); } +bool AMDGPUOperand::isSDWARegKind() const { + if (AsmParser->isVI()) + return isVReg(); + else if (AsmParser->isGFX9()) + return isRegKind(); + else + return false; +} + uint64_t AMDGPUOperand::applyInputFPModifiers(uint64_t Val, unsigned Size) const { assert(isImmTy(ImmTyNone) && Imm.Mods.hasFPModifiers()); @@ -2083,7 +2105,7 @@ bool AMDGPUAsmParser::usesConstantBus(const MCInst &Inst, unsigned OpIdx) { isSGPR(mc2PseudoReg(MO.getReg()), getContext().getRegisterInfo()); } -bool AMDGPUAsmParser::validateOperandLimitations(const MCInst &Inst) { +bool AMDGPUAsmParser::validateConstantBusLimitations(const MCInst &Inst) { const unsigned Opcode = Inst.getOpcode(); const MCInstrDesc &Desc = MII.get(Opcode); unsigned ConstantBusUseCount = 0; @@ -2137,6 +2159,60 @@ bool AMDGPUAsmParser::validateOperandLimitations(const MCInst &Inst) { return ConstantBusUseCount <= 1; } +bool AMDGPUAsmParser::validateEarlyClobberLimitations(const MCInst &Inst) { + + const unsigned Opcode = Inst.getOpcode(); + const MCInstrDesc &Desc = MII.get(Opcode); + + const int DstIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdst); + if (DstIdx == -1 || + Desc.getOperandConstraint(DstIdx, MCOI::EARLY_CLOBBER) == -1) { + return true; + } + + const MCRegisterInfo *TRI = getContext().getRegisterInfo(); + + const int Src0Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src0); + const int Src1Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src1); + const int Src2Idx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::src2); + + assert(DstIdx != -1); + const MCOperand &Dst = Inst.getOperand(DstIdx); + assert(Dst.isReg()); + const unsigned DstReg = mc2PseudoReg(Dst.getReg()); + + const int SrcIndices[] = { Src0Idx, Src1Idx, Src2Idx }; + + for (int SrcIdx : SrcIndices) { + if (SrcIdx == -1) break; + const MCOperand &Src = Inst.getOperand(SrcIdx); + if (Src.isReg()) { + const unsigned SrcReg = mc2PseudoReg(Src.getReg()); + if (isRegIntersect(DstReg, SrcReg, TRI)) { + return false; + } + } + } + + return true; +} + +bool AMDGPUAsmParser::validateInstruction(const MCInst &Inst, + const SMLoc &IDLoc) { + if (!validateConstantBusLimitations(Inst)) { + Error(IDLoc, + "invalid operand (violates constant bus restrictions)"); + return false; + } + if (!validateEarlyClobberLimitations(Inst)) { + Error(IDLoc, + "destination must be different than all sources"); + return false; + } + + return true; +} + bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, OperandVector &Operands, MCStreamer &Out, @@ -2169,9 +2245,8 @@ bool AMDGPUAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, switch (Result) { default: break; case Match_Success: - if (!validateOperandLimitations(Inst)) { - return Error(IDLoc, - "invalid operand (violates constant bus restrictions)"); + if (!validateInstruction(Inst, IDLoc)) { + return true; } Inst.setLoc(IDLoc); Out.EmitInstruction(Inst, getSTI()); @@ -2554,11 +2629,21 @@ AMDGPUAsmParser::parseIntWithPrefix(const char *Prefix, int64_t &Int) { return MatchOperand_ParseFail; Parser.Lex(); + + bool IsMinus = false; + if (getLexer().getKind() == AsmToken::Minus) { + Parser.Lex(); + IsMinus = true; + } + if (getLexer().isNot(AsmToken::Integer)) return MatchOperand_ParseFail; if (getParser().parseAbsoluteExpression(Int)) return MatchOperand_ParseFail; + + if (IsMinus) + Int = -Int; break; } } @@ -3743,6 +3828,44 @@ void AMDGPUAsmParser::cvtMubufImpl(MCInst &Inst, addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); } +void AMDGPUAsmParser::cvtMtbuf(MCInst &Inst, const OperandVector &Operands) { + OptionalImmIndexMap OptionalIdx; + + for (unsigned i = 1, e = Operands.size(); i != e; ++i) { + AMDGPUOperand &Op = ((AMDGPUOperand &)*Operands[i]); + + // Add the register arguments + if (Op.isReg()) { + Op.addRegOperands(Inst, 1); + continue; + } + + // Handle the case where soffset is an immediate + if (Op.isImm() && Op.getImmTy() == AMDGPUOperand::ImmTyNone) { + Op.addImmOperands(Inst, 1); + continue; + } + + // Handle tokens like 'offen' which are sometimes hard-coded into the + // asm string. There are no MCInst operands for these. + if (Op.isToken()) { + continue; + } + assert(Op.isImm()); + + // Handle optional arguments + OptionalIdx[Op.getImmTy()] = i; + } + + addOptionalImmOperand(Inst, Operands, OptionalIdx, + AMDGPUOperand::ImmTyOffset); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyDFMT); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyNFMT); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyGLC); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySLC); + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyTFE); +} + //===----------------------------------------------------------------------===// // mimg //===----------------------------------------------------------------------===// @@ -3870,6 +3993,10 @@ AMDGPUOperand::Ptr AMDGPUAsmParser::defaultOffsetU12() const { return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyOffset); } +AMDGPUOperand::Ptr AMDGPUAsmParser::defaultOffsetS13() const { + return AMDGPUOperand::CreateImm(this, 0, SMLoc(), AMDGPUOperand::ImmTyOffset); +} + //===----------------------------------------------------------------------===// // vop3 //===----------------------------------------------------------------------===// @@ -3919,6 +4046,8 @@ static const OptionalOperand AMDGPUOptionalOperandTable[] = { {"offset1", AMDGPUOperand::ImmTyOffset1, false, nullptr}, {"gds", AMDGPUOperand::ImmTyGDS, true, nullptr}, {"offset", AMDGPUOperand::ImmTyOffset, false, nullptr}, + {"dfmt", AMDGPUOperand::ImmTyDFMT, false, nullptr}, + {"nfmt", AMDGPUOperand::ImmTyNFMT, false, nullptr}, {"glc", AMDGPUOperand::ImmTyGLC, true, nullptr}, {"slc", AMDGPUOperand::ImmTySLC, true, nullptr}, {"tfe", AMDGPUOperand::ImmTyTFE, true, nullptr}, @@ -4475,12 +4604,11 @@ void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands, if (Inst.getOpcode() != AMDGPU::V_NOP_sdwa_gfx9 && Inst.getOpcode() != AMDGPU::V_NOP_sdwa_vi) { - // V_NOP_sdwa_vi has no optional sdwa arguments + // v_nop_sdwa_sdwa_vi/gfx9 has no optional sdwa arguments switch (BasicInstType) { case SIInstrFlags::VOP1: addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI, 0); - if (isGFX9() && - AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::omod) != -1) { + if (AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::omod) != -1) { addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyOModSI, 0); } addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstSel, SdwaSel::DWORD); @@ -4490,8 +4618,7 @@ void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands, case SIInstrFlags::VOP2: addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI, 0); - if (isGFX9() && - AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::omod) != -1) { + if (AMDGPU::getNamedOperandIdx(Inst.getOpcode(), AMDGPU::OpName::omod) != -1) { addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyOModSI, 0); } addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaDstSel, SdwaSel::DWORD); @@ -4501,9 +4628,7 @@ void AMDGPUAsmParser::cvtSDWA(MCInst &Inst, const OperandVector &Operands, break; case SIInstrFlags::VOPC: - if (isVI()) { - addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI, 0); - } + addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTyClampSI, 0); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc0Sel, SdwaSel::DWORD); addOptionalImmOperand(Inst, Operands, OptionalIdx, AMDGPUOperand::ImmTySdwaSrc1Sel, SdwaSel::DWORD); break; diff --git a/contrib/llvm/lib/Target/AMDGPU/BUFInstructions.td b/contrib/llvm/lib/Target/AMDGPU/BUFInstructions.td index 2aca65ac8430..2e96c14eaa32 100644 --- a/contrib/llvm/lib/Target/AMDGPU/BUFInstructions.td +++ b/contrib/llvm/lib/Target/AMDGPU/BUFInstructions.td @@ -57,6 +57,11 @@ class MUBUFAddr64Table { string OpName = NAME # suffix; } +class MTBUFAddr64Table { + bit IsAddr64 = is_addr64; + string OpName = NAME # suffix; +} + //===----------------------------------------------------------------------===// // MTBUF classes //===----------------------------------------------------------------------===// @@ -78,14 +83,31 @@ class MTBUF_Pseudo offen = 0; + bits<1> idxen = 0; + bits<1> addr64 = 0; + bits<1> has_vdata = 1; + bits<1> has_vaddr = 1; + bits<1> has_glc = 1; + bits<1> glc_value = 0; // the value for glc if no such operand + bits<4> dfmt_value = 1; // the value for dfmt if no such operand + bits<3> nfmt_value = 0; // the value for nfmt if no such operand + bits<1> has_srsrc = 1; + bits<1> has_soffset = 1; + bits<1> has_offset = 1; + bits<1> has_slc = 1; + bits<1> has_tfe = 1; + bits<1> has_dfmt = 1; + bits<1> has_nfmt = 1; } class MTBUF_Real : - InstSI , - Enc64 { + InstSI { let isPseudo = 0; let isCodeGenOnly = 0; @@ -97,57 +119,168 @@ class MTBUF_Real : let DisableEncoding = ps.DisableEncoding; let TSFlags = ps.TSFlags; - bits<8> vdata; bits<12> offset; - bits<1> offen; - bits<1> idxen; - bits<1> glc; - bits<1> addr64; - bits<4> dfmt; - bits<3> nfmt; - bits<8> vaddr; - bits<7> srsrc; - bits<1> slc; - bits<1> tfe; - bits<8> soffset; - - let Inst{11-0} = offset; - let Inst{12} = offen; - let Inst{13} = idxen; - let Inst{14} = glc; - let Inst{22-19} = dfmt; - let Inst{25-23} = nfmt; - let Inst{31-26} = 0x3a; //encoding - let Inst{39-32} = vaddr; - let Inst{47-40} = vdata; - let Inst{52-48} = srsrc{6-2}; - let Inst{54} = slc; - let Inst{55} = tfe; - let Inst{63-56} = soffset; + bits<1> glc; + bits<4> dfmt; + bits<3> nfmt; + bits<8> vaddr; + bits<8> vdata; + bits<7> srsrc; + bits<1> slc; + bits<1> tfe; + bits<8> soffset; } -class MTBUF_Load_Pseudo : MTBUF_Pseudo < - opName, (outs regClass:$dst), - (ins u16imm:$offset, i1imm:$offen, i1imm:$idxen, i1imm:$glc, i1imm:$addr64, - i8imm:$dfmt, i8imm:$nfmt, VGPR_32:$vaddr, SReg_128:$srsrc, - i1imm:$slc, i1imm:$tfe, SCSrc_b32:$soffset), - " $dst, $offset, $offen, $idxen, $glc, $addr64, $dfmt,"# - " $nfmt, $vaddr, $srsrc, $slc, $tfe, $soffset"> { +class getMTBUFInsDA vdataList, + list vaddrList=[]> { + RegisterClass vdataClass = !if(!empty(vdataList), ?, !head(vdataList)); + RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList)); + dag InsNoData = !if(!empty(vaddrList), + (ins SReg_128:$srsrc, SCSrc_b32:$soffset, + offset:$offset, DFMT:$dfmt, NFMT:$nfmt, GLC:$glc, slc:$slc, tfe:$tfe), + (ins vaddrClass:$vaddr, SReg_128:$srsrc, SCSrc_b32:$soffset, + offset:$offset, DFMT:$dfmt, NFMT:$nfmt, GLC:$glc, slc:$slc, tfe:$tfe) + ); + dag InsData = !if(!empty(vaddrList), + (ins vdataClass:$vdata, SReg_128:$srsrc, + SCSrc_b32:$soffset, offset:$offset, DFMT:$dfmt, NFMT:$nfmt, GLC:$glc, + slc:$slc, tfe:$tfe), + (ins vdataClass:$vdata, vaddrClass:$vaddr, SReg_128:$srsrc, + SCSrc_b32:$soffset, offset:$offset, DFMT:$dfmt, NFMT:$nfmt, GLC:$glc, + slc:$slc, tfe:$tfe) + ); + dag ret = !if(!empty(vdataList), InsNoData, InsData); +} + +class getMTBUFIns vdataList=[]> { + dag ret = + !if(!eq(addrKind, BUFAddrKind.Offset), getMTBUFInsDA.ret, + !if(!eq(addrKind, BUFAddrKind.OffEn), getMTBUFInsDA.ret, + !if(!eq(addrKind, BUFAddrKind.IdxEn), getMTBUFInsDA.ret, + !if(!eq(addrKind, BUFAddrKind.BothEn), getMTBUFInsDA.ret, + !if(!eq(addrKind, BUFAddrKind.Addr64), getMTBUFInsDA.ret, + (ins)))))); +} + +class getMTBUFAsmOps { + string Pfx = + !if(!eq(addrKind, BUFAddrKind.Offset), "off, $srsrc, $dfmt, $nfmt, $soffset", + !if(!eq(addrKind, BUFAddrKind.OffEn), + "$vaddr, $srsrc, $dfmt, $nfmt, $soffset offen", + !if(!eq(addrKind, BUFAddrKind.IdxEn), + "$vaddr, $srsrc, $dfmt, $nfmt, $soffset idxen", + !if(!eq(addrKind, BUFAddrKind.BothEn), + "$vaddr, $srsrc, $dfmt, $nfmt, $soffset idxen offen", + !if(!eq(addrKind, BUFAddrKind.Addr64), + "$vaddr, $srsrc, $dfmt, $nfmt, $soffset addr64", + ""))))); + string ret = Pfx # "$offset"; +} + +class MTBUF_SetupAddr { + bits<1> offen = !if(!eq(addrKind, BUFAddrKind.OffEn), 1, + !if(!eq(addrKind, BUFAddrKind.BothEn), 1 , 0)); + + bits<1> idxen = !if(!eq(addrKind, BUFAddrKind.IdxEn), 1, + !if(!eq(addrKind, BUFAddrKind.BothEn), 1 , 0)); + + bits<1> addr64 = !if(!eq(addrKind, BUFAddrKind.Addr64), 1, 0); + + bits<1> has_vaddr = !if(!eq(addrKind, BUFAddrKind.Offset), 0, 1); +} + +class MTBUF_Load_Pseudo pattern=[], + // Workaround bug bz30254 + int addrKindCopy = addrKind> + : MTBUF_Pseudo.ret, + " $vdata, " # getMTBUFAsmOps.ret # "$glc$slc$tfe", + pattern>, + MTBUF_SetupAddr { + let PseudoInstr = opName # "_" # getAddrName.ret; let mayLoad = 1; let mayStore = 0; } -class MTBUF_Store_Pseudo : MTBUF_Pseudo < - opName, (outs), - (ins regClass:$vdata, u16imm:$offset, i1imm:$offen, i1imm:$idxen, i1imm:$glc, - i1imm:$addr64, i8imm:$dfmt, i8imm:$nfmt, VGPR_32:$vaddr, - SReg_128:$srsrc, i1imm:$slc, i1imm:$tfe, SCSrc_b32:$soffset), - " $vdata, $offset, $offen, $idxen, $glc, $addr64, $dfmt,"# - " $nfmt, $vaddr, $srsrc, $slc, $tfe, $soffset"> { +multiclass MTBUF_Pseudo_Loads { + + def _OFFSET : MTBUF_Load_Pseudo , + MTBUFAddr64Table<0>; + + def _ADDR64 : MTBUF_Load_Pseudo , + MTBUFAddr64Table<1>; + + def _OFFEN : MTBUF_Load_Pseudo ; + def _IDXEN : MTBUF_Load_Pseudo ; + def _BOTHEN : MTBUF_Load_Pseudo ; + + let DisableWQM = 1 in { + def _OFFSET_exact : MTBUF_Load_Pseudo ; + def _OFFEN_exact : MTBUF_Load_Pseudo ; + def _IDXEN_exact : MTBUF_Load_Pseudo ; + def _BOTHEN_exact : MTBUF_Load_Pseudo ; + } +} + +class MTBUF_Store_Pseudo pattern=[], + // Workaround bug bz30254 + int addrKindCopy = addrKind, + RegisterClass vdataClassCopy = vdataClass> + : MTBUF_Pseudo.ret, + " $vdata, " # getMTBUFAsmOps.ret # "$glc$slc$tfe", + pattern>, + MTBUF_SetupAddr { + let PseudoInstr = opName # "_" # getAddrName.ret; let mayLoad = 0; let mayStore = 1; } +multiclass MTBUF_Pseudo_Stores { + + def _OFFSET : MTBUF_Store_Pseudo , + MTBUFAddr64Table<0>; + + def _ADDR64 : MTBUF_Store_Pseudo , + MTBUFAddr64Table<1>; + + def _OFFEN : MTBUF_Store_Pseudo ; + def _IDXEN : MTBUF_Store_Pseudo ; + def _BOTHEN : MTBUF_Store_Pseudo ; + + let DisableWQM = 1 in { + def _OFFSET_exact : MTBUF_Store_Pseudo ; + def _OFFEN_exact : MTBUF_Store_Pseudo ; + def _IDXEN_exact : MTBUF_Store_Pseudo ; + def _BOTHEN_exact : MTBUF_Store_Pseudo ; + } +} + + //===----------------------------------------------------------------------===// // MUBUF classes //===----------------------------------------------------------------------===// @@ -676,14 +809,14 @@ def BUFFER_WBINVL1 : MUBUF_Invalidate <"buffer_wbinvl1", // MTBUF Instructions //===----------------------------------------------------------------------===// -//def TBUFFER_LOAD_FORMAT_X : MTBUF_ <0, "tbuffer_load_format_x", []>; -//def TBUFFER_LOAD_FORMAT_XY : MTBUF_ <1, "tbuffer_load_format_xy", []>; -//def TBUFFER_LOAD_FORMAT_XYZ : MTBUF_ <2, "tbuffer_load_format_xyz", []>; -def TBUFFER_LOAD_FORMAT_XYZW : MTBUF_Load_Pseudo <"tbuffer_load_format_xyzw", VReg_128>; -def TBUFFER_STORE_FORMAT_X : MTBUF_Store_Pseudo <"tbuffer_store_format_x", VGPR_32>; -def TBUFFER_STORE_FORMAT_XY : MTBUF_Store_Pseudo <"tbuffer_store_format_xy", VReg_64>; -def TBUFFER_STORE_FORMAT_XYZ : MTBUF_Store_Pseudo <"tbuffer_store_format_xyz", VReg_128>; -def TBUFFER_STORE_FORMAT_XYZW : MTBUF_Store_Pseudo <"tbuffer_store_format_xyzw", VReg_128>; +defm TBUFFER_LOAD_FORMAT_X : MTBUF_Pseudo_Loads <"tbuffer_load_format_x", VGPR_32>; +defm TBUFFER_LOAD_FORMAT_XY : MTBUF_Pseudo_Loads <"tbuffer_load_format_xy", VReg_64>; +defm TBUFFER_LOAD_FORMAT_XYZ : MTBUF_Pseudo_Loads <"tbuffer_load_format_xyz", VReg_128>; +defm TBUFFER_LOAD_FORMAT_XYZW : MTBUF_Pseudo_Loads <"tbuffer_load_format_xyzw", VReg_128>; +defm TBUFFER_STORE_FORMAT_X : MTBUF_Pseudo_Stores <"tbuffer_store_format_x", VGPR_32>; +defm TBUFFER_STORE_FORMAT_XY : MTBUF_Pseudo_Stores <"tbuffer_store_format_xy", VReg_64>; +defm TBUFFER_STORE_FORMAT_XYZ : MTBUF_Pseudo_Stores <"tbuffer_store_format_xyz", VReg_128>; +defm TBUFFER_STORE_FORMAT_XYZW : MTBUF_Pseudo_Stores <"tbuffer_store_format_xyzw", VReg_128>; } // End let SubtargetPredicate = isGCN @@ -1093,22 +1226,98 @@ defm : MUBUFScratchStorePat : Pat< - (SItbuffer_store v4i32:$rsrc, vt:$vdata, num_channels, i32:$vaddr, - i32:$soffset, imm:$inst_offset, imm:$dfmt, - imm:$nfmt, imm:$offen, imm:$idxen, - imm:$glc, imm:$slc, imm:$tfe), - (opcode - $vdata, (as_i16imm $inst_offset), (as_i1imm $offen), (as_i1imm $idxen), - (as_i1imm $glc), 0, (as_i8imm $dfmt), (as_i8imm $nfmt), $vaddr, $rsrc, - (as_i1imm $slc), (as_i1imm $tfe), $soffset) ->; +//===----------------------------------------------------------------------===// +// tbuffer_load/store_format patterns +//===----------------------------------------------------------------------===// -def : MTBUF_StoreResource ; -def : MTBUF_StoreResource ; -def : MTBUF_StoreResource ; -def : MTBUF_StoreResource ; +multiclass MTBUF_LoadIntrinsicPat { + def : Pat< + (vt (name v4i32:$rsrc, 0, 0, i32:$soffset, imm:$offset, + imm:$dfmt, imm:$nfmt, imm:$glc, imm:$slc)), + (!cast(opcode # _OFFSET) $rsrc, $soffset, (as_i16imm $offset), + (as_i8imm $dfmt), (as_i8imm $nfmt), (as_i1imm $glc), (as_i1imm $slc), 0) + >; + + def : Pat< + (vt (name v4i32:$rsrc, i32:$vindex, 0, i32:$soffset, imm:$offset, + imm:$dfmt, imm:$nfmt, imm:$glc, imm:$slc)), + (!cast(opcode # _IDXEN) $vindex, $rsrc, $soffset, (as_i16imm $offset), + (as_i8imm $dfmt), (as_i8imm $nfmt), (as_i1imm $glc), (as_i1imm $slc), 0) + >; + + def : Pat< + (vt (name v4i32:$rsrc, 0, i32:$voffset, i32:$soffset, imm:$offset, + imm:$dfmt, imm:$nfmt, imm:$glc, imm:$slc)), + (!cast(opcode # _OFFEN) $voffset, $rsrc, $soffset, (as_i16imm $offset), + (as_i8imm $dfmt), (as_i8imm $nfmt), (as_i1imm $glc), (as_i1imm $slc), 0) + >; + + def : Pat< + (vt (name v4i32:$rsrc, i32:$vindex, i32:$voffset, i32:$soffset, imm:$offset, + imm:$dfmt, imm:$nfmt, imm:$glc, imm:$slc)), + (!cast(opcode # _BOTHEN) + (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1), + $rsrc, $soffset, (as_i16imm $offset), + (as_i8imm $dfmt), (as_i8imm $nfmt), (as_i1imm $glc), (as_i1imm $slc), 0) + >; +} + +defm : MTBUF_LoadIntrinsicPat; +defm : MTBUF_LoadIntrinsicPat; +defm : MTBUF_LoadIntrinsicPat; +defm : MTBUF_LoadIntrinsicPat; +defm : MTBUF_LoadIntrinsicPat; +defm : MTBUF_LoadIntrinsicPat; + +multiclass MTBUF_StoreIntrinsicPat { + def : Pat< + (name vt:$vdata, v4i32:$rsrc, 0, 0, i32:$soffset, imm:$offset, + imm:$dfmt, imm:$nfmt, imm:$glc, imm:$slc), + (!cast(opcode # _OFFSET_exact) $vdata, $rsrc, $soffset, + (as_i16imm $offset), (as_i8imm $dfmt), + (as_i8imm $nfmt), (as_i1imm $glc), + (as_i1imm $slc), 0) + >; + + def : Pat< + (name vt:$vdata, v4i32:$rsrc, i32:$vindex, 0, i32:$soffset, imm:$offset, + imm:$dfmt, imm:$nfmt, imm:$glc, imm:$slc), + (!cast(opcode # _IDXEN_exact) $vdata, $vindex, $rsrc, $soffset, + (as_i16imm $offset), (as_i8imm $dfmt), + (as_i8imm $nfmt), (as_i1imm $glc), + (as_i1imm $slc), 0) + >; + + def : Pat< + (name vt:$vdata, v4i32:$rsrc, 0, i32:$voffset, i32:$soffset, imm:$offset, + imm:$dfmt, imm:$nfmt, imm:$glc, imm:$slc), + (!cast(opcode # _OFFEN_exact) $vdata, $voffset, $rsrc, $soffset, + (as_i16imm $offset), (as_i8imm $dfmt), + (as_i8imm $nfmt), (as_i1imm $glc), + (as_i1imm $slc), 0) + >; + + def : Pat< + (name vt:$vdata, v4i32:$rsrc, i32:$vindex, i32:$voffset, i32:$soffset, + imm:$offset, imm:$dfmt, imm:$nfmt, imm:$glc, imm:$slc), + (!cast(opcode # _BOTHEN_exact) + $vdata, + (REG_SEQUENCE VReg_64, $vindex, sub0, $voffset, sub1), + $rsrc, $soffset, (as_i16imm $offset), + (as_i8imm $dfmt), (as_i8imm $nfmt), (as_i1imm $glc), (as_i1imm $slc), 0) + >; +} + +defm : MTBUF_StoreIntrinsicPat; +defm : MTBUF_StoreIntrinsicPat; +defm : MTBUF_StoreIntrinsicPat; +defm : MTBUF_StoreIntrinsicPat; +defm : MTBUF_StoreIntrinsicPat; +defm : MTBUF_StoreIntrinsicPat; +defm : MTBUF_StoreIntrinsicPat; +defm : MTBUF_StoreIntrinsicPat; } // End let Predicates = [isGCN] @@ -1224,21 +1433,44 @@ def BUFFER_WBINVL1_si : MUBUF_Real_si <0x71, BUFFER_WBINVL1>; class MTBUF_Real_si op, MTBUF_Pseudo ps> : MTBUF_Real, + Enc64, SIMCInstr { let AssemblerPredicate=isSICI; let DecoderNamespace="SICI"; - bits<1> addr64; - let Inst{15} = addr64; + let Inst{11-0} = !if(ps.has_offset, offset, ?); + let Inst{12} = ps.offen; + let Inst{13} = ps.idxen; + let Inst{14} = !if(ps.has_glc, glc, ps.glc_value); + let Inst{15} = ps.addr64; let Inst{18-16} = op; + let Inst{22-19} = !if(ps.has_dfmt, dfmt, ps.dfmt_value); + let Inst{25-23} = !if(ps.has_nfmt, nfmt, ps.nfmt_value); + let Inst{31-26} = 0x3a; //encoding + let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); + let Inst{47-40} = !if(ps.has_vdata, vdata, ?); + let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?); + let Inst{54} = !if(ps.has_slc, slc, ?); + let Inst{55} = !if(ps.has_tfe, tfe, ?); + let Inst{63-56} = !if(ps.has_soffset, soffset, ?); } -def TBUFFER_LOAD_FORMAT_XYZW_si : MTBUF_Real_si <3, TBUFFER_LOAD_FORMAT_XYZW>; -def TBUFFER_STORE_FORMAT_X_si : MTBUF_Real_si <4, TBUFFER_STORE_FORMAT_X>; -def TBUFFER_STORE_FORMAT_XY_si : MTBUF_Real_si <5, TBUFFER_STORE_FORMAT_XY>; -def TBUFFER_STORE_FORMAT_XYZ_si : MTBUF_Real_si <6, TBUFFER_STORE_FORMAT_XYZ>; -def TBUFFER_STORE_FORMAT_XYZW_si : MTBUF_Real_si <7, TBUFFER_STORE_FORMAT_XYZW>; +multiclass MTBUF_Real_AllAddr_si op> { + def _OFFSET_si : MTBUF_Real_si (NAME#"_OFFSET")>; + def _ADDR64_si : MTBUF_Real_si (NAME#"_ADDR64")>; + def _OFFEN_si : MTBUF_Real_si (NAME#"_OFFEN")>; + def _IDXEN_si : MTBUF_Real_si (NAME#"_IDXEN")>; + def _BOTHEN_si : MTBUF_Real_si (NAME#"_BOTHEN")>; +} +defm TBUFFER_LOAD_FORMAT_X : MTBUF_Real_AllAddr_si <0>; +defm TBUFFER_LOAD_FORMAT_XY : MTBUF_Real_AllAddr_si <1>; +//defm TBUFFER_LOAD_FORMAT_XYZ : MTBUF_Real_AllAddr_si <2>; +defm TBUFFER_LOAD_FORMAT_XYZW : MTBUF_Real_AllAddr_si <3>; +defm TBUFFER_STORE_FORMAT_X : MTBUF_Real_AllAddr_si <4>; +defm TBUFFER_STORE_FORMAT_XY : MTBUF_Real_AllAddr_si <5>; +defm TBUFFER_STORE_FORMAT_XYZ : MTBUF_Real_AllAddr_si <6>; +defm TBUFFER_STORE_FORMAT_XYZW : MTBUF_Real_AllAddr_si <7>; //===----------------------------------------------------------------------===// // CI @@ -1350,16 +1582,39 @@ def BUFFER_WBINVL1_VOL_vi : MUBUF_Real_vi <0x3f, BUFFER_WBINVL1_VOL>; class MTBUF_Real_vi op, MTBUF_Pseudo ps> : MTBUF_Real, + Enc64, SIMCInstr { let AssemblerPredicate=isVI; let DecoderNamespace="VI"; + let Inst{11-0} = !if(ps.has_offset, offset, ?); + let Inst{12} = ps.offen; + let Inst{13} = ps.idxen; + let Inst{14} = !if(ps.has_glc, glc, ps.glc_value); let Inst{18-15} = op; + let Inst{22-19} = !if(ps.has_dfmt, dfmt, ps.dfmt_value); + let Inst{25-23} = !if(ps.has_nfmt, nfmt, ps.nfmt_value); + let Inst{31-26} = 0x3a; //encoding + let Inst{39-32} = !if(ps.has_vaddr, vaddr, ?); + let Inst{47-40} = !if(ps.has_vdata, vdata, ?); + let Inst{52-48} = !if(ps.has_srsrc, srsrc{6-2}, ?); + let Inst{54} = !if(ps.has_slc, slc, ?); + let Inst{55} = !if(ps.has_tfe, tfe, ?); + let Inst{63-56} = !if(ps.has_soffset, soffset, ?); } -def TBUFFER_LOAD_FORMAT_XYZW_vi : MTBUF_Real_vi <3, TBUFFER_LOAD_FORMAT_XYZW>; -def TBUFFER_STORE_FORMAT_X_vi : MTBUF_Real_vi <4, TBUFFER_STORE_FORMAT_X>; -def TBUFFER_STORE_FORMAT_XY_vi : MTBUF_Real_vi <5, TBUFFER_STORE_FORMAT_XY>; -def TBUFFER_STORE_FORMAT_XYZ_vi : MTBUF_Real_vi <6, TBUFFER_STORE_FORMAT_XYZ>; -def TBUFFER_STORE_FORMAT_XYZW_vi : MTBUF_Real_vi <7, TBUFFER_STORE_FORMAT_XYZW>; +multiclass MTBUF_Real_AllAddr_vi op> { + def _OFFSET_vi : MTBUF_Real_vi (NAME#"_OFFSET")>; + def _OFFEN_vi : MTBUF_Real_vi (NAME#"_OFFEN")>; + def _IDXEN_vi : MTBUF_Real_vi (NAME#"_IDXEN")>; + def _BOTHEN_vi : MTBUF_Real_vi (NAME#"_BOTHEN")>; +} +defm TBUFFER_LOAD_FORMAT_X : MTBUF_Real_AllAddr_vi <0>; +defm TBUFFER_LOAD_FORMAT_XY : MTBUF_Real_AllAddr_vi <1>; +//defm TBUFFER_LOAD_FORMAT_XYZ : MTBUF_Real_AllAddr_vi <2>; +defm TBUFFER_LOAD_FORMAT_XYZW : MTBUF_Real_AllAddr_vi <3>; +defm TBUFFER_STORE_FORMAT_X : MTBUF_Real_AllAddr_vi <4>; +defm TBUFFER_STORE_FORMAT_XY : MTBUF_Real_AllAddr_vi <5>; +defm TBUFFER_STORE_FORMAT_XYZ : MTBUF_Real_AllAddr_vi <6>; +defm TBUFFER_STORE_FORMAT_XYZW : MTBUF_Real_AllAddr_vi <7>; diff --git a/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp index 88c92b9582fd..04308fb3aaf6 100644 --- a/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp @@ -49,6 +49,17 @@ addOperand(MCInst &Inst, const MCOperand& Opnd) { MCDisassembler::SoftFail; } +static int insertNamedMCOperand(MCInst &MI, const MCOperand &Op, + uint16_t NameIdx) { + int OpIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), NameIdx); + if (OpIdx != -1) { + auto I = MI.begin(); + std::advance(I, OpIdx); + MI.insert(I, Op); + } + return OpIdx; +} + static DecodeStatus decodeSoppBrTarget(MCInst &Inst, unsigned Imm, uint64_t Addr, const void *Decoder) { auto DAsm = static_cast(Decoder); @@ -106,12 +117,12 @@ static DecodeStatus decodeOperand_VSrcV216(MCInst &Inst, return addOperand(Inst, DAsm->decodeOperand_VSrcV216(Imm)); } -#define DECODE_SDWA9(DecName) \ -DECODE_OPERAND(decodeSDWA9##DecName, decodeSDWA9##DecName) +#define DECODE_SDWA(DecName) \ +DECODE_OPERAND(decodeSDWA##DecName, decodeSDWA##DecName) -DECODE_SDWA9(Src32) -DECODE_SDWA9(Src16) -DECODE_SDWA9(VopcDst) +DECODE_SDWA(Src32) +DECODE_SDWA(Src16) +DECODE_SDWA(VopcDst) #include "AMDGPUGenDisassemblerTables.inc" @@ -149,6 +160,7 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, raw_ostream &WS, raw_ostream &CS) const { CommentStream = &CS; + bool IsSDWA = false; // ToDo: AMDGPUDisassembler supports only VI ISA. if (!STI.getFeatureBits()[AMDGPU::FeatureGCN3Encoding]) @@ -170,10 +182,10 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, if (Res) break; Res = tryDecodeInst(DecoderTableSDWA64, MI, QW, Address); - if (Res) break; + if (Res) { IsSDWA = true; break; } Res = tryDecodeInst(DecoderTableSDWA964, MI, QW, Address); - if (Res) break; + if (Res) { IsSDWA = true; break; } } // Reinitialize Bytes as DPP64 could have eaten too much @@ -200,17 +212,36 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size, MI.getOpcode() == AMDGPU::V_MAC_F32_e64_si || MI.getOpcode() == AMDGPU::V_MAC_F16_e64_vi)) { // Insert dummy unused src2_modifiers. - int Src2ModIdx = AMDGPU::getNamedOperandIdx(MI.getOpcode(), - AMDGPU::OpName::src2_modifiers); - auto I = MI.begin(); - std::advance(I, Src2ModIdx); - MI.insert(I, MCOperand::createImm(0)); + insertNamedMCOperand(MI, MCOperand::createImm(0), + AMDGPU::OpName::src2_modifiers); } + if (Res && IsSDWA) + Res = convertSDWAInst(MI); + Size = Res ? (MaxInstBytesNum - Bytes.size()) : 0; return Res; } +DecodeStatus AMDGPUDisassembler::convertSDWAInst(MCInst &MI) const { + if (STI.getFeatureBits()[AMDGPU::FeatureGFX9]) { + if (AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::sdst) != -1) + // VOPC - insert clamp + insertNamedMCOperand(MI, MCOperand::createImm(0), AMDGPU::OpName::clamp); + } else if (STI.getFeatureBits()[AMDGPU::FeatureVolcanicIslands]) { + int SDst = AMDGPU::getNamedOperandIdx(MI.getOpcode(), AMDGPU::OpName::sdst); + if (SDst != -1) { + // VOPC - insert VCC register as sdst + insertNamedMCOperand(MI, MCOperand::createReg(AMDGPU::VCC), + AMDGPU::OpName::sdst); + } else { + // VOP1/2 - insert omod if present in instruction + insertNamedMCOperand(MI, MCOperand::createImm(0), AMDGPU::OpName::omod); + } + } + return MCDisassembler::Success; +} + const char* AMDGPUDisassembler::getRegClassName(unsigned RegClassID) const { return getContext().getRegisterInfo()-> getRegClassName(&AMDGPUMCRegisterClasses[RegClassID]); @@ -524,8 +555,6 @@ MCOperand AMDGPUDisassembler::decodeSrcOp(const OpWidthTy Width, unsigned Val) c return createSRegOperand(getTtmpClassId(Width), Val - TTMP_MIN); } - assert(Width == OPW16 || Width == OPW32 || Width == OPW64); - if (INLINE_INTEGER_C_MIN <= Val && Val <= INLINE_INTEGER_C_MAX) return decodeIntImmed(Val); @@ -592,36 +621,43 @@ MCOperand AMDGPUDisassembler::decodeSpecialReg64(unsigned Val) const { return errOperand(Val, "unknown operand encoding " + Twine(Val)); } -MCOperand AMDGPUDisassembler::decodeSDWA9Src(const OpWidthTy Width, - unsigned Val) const { +MCOperand AMDGPUDisassembler::decodeSDWASrc(const OpWidthTy Width, + unsigned Val) const { using namespace AMDGPU::SDWA; - if (SDWA9EncValues::SRC_VGPR_MIN <= Val && - Val <= SDWA9EncValues::SRC_VGPR_MAX) { - return createRegOperand(getVgprClassId(Width), - Val - SDWA9EncValues::SRC_VGPR_MIN); - } - if (SDWA9EncValues::SRC_SGPR_MIN <= Val && - Val <= SDWA9EncValues::SRC_SGPR_MAX) { - return createSRegOperand(getSgprClassId(Width), - Val - SDWA9EncValues::SRC_SGPR_MIN); + if (STI.getFeatureBits()[AMDGPU::FeatureGFX9]) { + if (SDWA9EncValues::SRC_VGPR_MIN <= Val && + Val <= SDWA9EncValues::SRC_VGPR_MAX) { + return createRegOperand(getVgprClassId(Width), + Val - SDWA9EncValues::SRC_VGPR_MIN); + } + if (SDWA9EncValues::SRC_SGPR_MIN <= Val && + Val <= SDWA9EncValues::SRC_SGPR_MAX) { + return createSRegOperand(getSgprClassId(Width), + Val - SDWA9EncValues::SRC_SGPR_MIN); + } + + return decodeSpecialReg32(Val - SDWA9EncValues::SRC_SGPR_MIN); + } else if (STI.getFeatureBits()[AMDGPU::FeatureVolcanicIslands]) { + return createRegOperand(getVgprClassId(Width), Val); } - - return decodeSpecialReg32(Val - SDWA9EncValues::SRC_SGPR_MIN); + llvm_unreachable("unsupported target"); } -MCOperand AMDGPUDisassembler::decodeSDWA9Src16(unsigned Val) const { - return decodeSDWA9Src(OPW16, Val); +MCOperand AMDGPUDisassembler::decodeSDWASrc16(unsigned Val) const { + return decodeSDWASrc(OPW16, Val); } -MCOperand AMDGPUDisassembler::decodeSDWA9Src32(unsigned Val) const { - return decodeSDWA9Src(OPW32, Val); +MCOperand AMDGPUDisassembler::decodeSDWASrc32(unsigned Val) const { + return decodeSDWASrc(OPW32, Val); } -MCOperand AMDGPUDisassembler::decodeSDWA9VopcDst(unsigned Val) const { +MCOperand AMDGPUDisassembler::decodeSDWAVopcDst(unsigned Val) const { using namespace AMDGPU::SDWA; + assert(STI.getFeatureBits()[AMDGPU::FeatureGFX9] && + "SDWAVopcDst should be present only on GFX9"); if (Val & SDWA9EncValues::VOPC_DST_VCC_MASK) { Val &= SDWA9EncValues::VOPC_DST_SGPR_MASK; if (Val > AMDGPU::EncValues::SGPR_MAX) { diff --git a/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h index 5fa3cf1a223f..3d71db909e20 100644 --- a/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h +++ b/contrib/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h @@ -65,6 +65,8 @@ class AMDGPUDisassembler : public MCDisassembler { uint64_t Inst, uint64_t Address) const; + DecodeStatus convertSDWAInst(MCInst &MI) const; + MCOperand decodeOperand_VGPR_32(unsigned Val) const; MCOperand decodeOperand_VS_32(unsigned Val) const; MCOperand decodeOperand_VS_64(unsigned Val) const; @@ -105,10 +107,10 @@ class AMDGPUDisassembler : public MCDisassembler { MCOperand decodeSpecialReg32(unsigned Val) const; MCOperand decodeSpecialReg64(unsigned Val) const; - MCOperand decodeSDWA9Src(const OpWidthTy Width, unsigned Val) const; - MCOperand decodeSDWA9Src16(unsigned Val) const; - MCOperand decodeSDWA9Src32(unsigned Val) const; - MCOperand decodeSDWA9VopcDst(unsigned Val) const; + MCOperand decodeSDWASrc(const OpWidthTy Width, unsigned Val) const; + MCOperand decodeSDWASrc16(unsigned Val) const; + MCOperand decodeSDWASrc32(unsigned Val) const; + MCOperand decodeSDWAVopcDst(unsigned Val) const; }; //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Target/AMDGPU/FLATInstructions.td b/contrib/llvm/lib/Target/AMDGPU/FLATInstructions.td index 98eda288bcac..edca6fcd812c 100644 --- a/contrib/llvm/lib/Target/AMDGPU/FLATInstructions.td +++ b/contrib/llvm/lib/Target/AMDGPU/FLATInstructions.td @@ -31,8 +31,6 @@ class FLAT_Pseudo is_flat_global = 0; + bits<1> is_flat_scratch = 0; + bits<1> has_vdst = 1; bits<1> has_data = 1; bits<1> has_glc = 1; bits<1> glcValue = 0; + + // TODO: M0 if it could possibly access LDS (before gfx9? only)? + let Uses = !if(is_flat_global, [EXEC], [EXEC, FLAT_SCR]); } class FLAT_Real op, FLAT_Pseudo ps> : @@ -68,7 +72,10 @@ class FLAT_Real op, FLAT_Pseudo ps> : // Only valid on gfx9 bits<1> lds = 0; // XXX - What does this actually do? - bits<2> seg; // Segment, 00=flat, 01=scratch, 10=global, 11=reserved + + // Segment, 00=flat, 01=scratch, 10=global, 11=reserved + bits<2> seg = !if(ps.is_flat_global, 0b10, + !if(ps.is_flat_scratch, 0b01, 0)); // Signed offset. Highest bit ignored for flat and treated as 12-bit // unsigned for flat acceses. @@ -81,7 +88,7 @@ class FLAT_Real op, FLAT_Pseudo ps> : // Only valid on GFX9+ let Inst{12-0} = offset; let Inst{13} = lds; - let Inst{15-14} = 0; + let Inst{15-14} = seg; let Inst{16} = !if(ps.has_glc, glc, ps.glcValue); let Inst{17} = slc; @@ -106,6 +113,16 @@ class FLAT_Load_Pseudo : + FLAT_Load_Pseudo { + let is_flat_global = 1; +} + +class FLAT_Scratch_Load_Pseudo : + FLAT_Load_Pseudo { + let is_flat_scratch = 1; +} + class FLAT_Store_Pseudo : FLAT_Pseudo< opName, @@ -119,6 +136,16 @@ class FLAT_Store_Pseudo : + FLAT_Store_Pseudo { + let is_flat_global = 1; +} + +class FLAT_Scratch_Store_Pseudo : + FLAT_Store_Pseudo { + let is_flat_scratch = 1; +} + multiclass FLAT_Atomic_Pseudo< string opName, RegisterClass vdst_rc, @@ -306,6 +333,26 @@ defm FLAT_ATOMIC_FMAX_X2 : FLAT_Atomic_Pseudo <"flat_atomic_fmax_x2", } // End SubtargetPredicate = isCI +let SubtargetPredicate = HasFlatGlobalInsts in { +def GLOBAL_LOAD_UBYTE : FLAT_Global_Load_Pseudo <"global_load_ubyte", VGPR_32>; +def GLOBAL_LOAD_SBYTE : FLAT_Global_Load_Pseudo <"global_load_sbyte", VGPR_32>; +def GLOBAL_LOAD_USHORT : FLAT_Global_Load_Pseudo <"global_load_ushort", VGPR_32>; +def GLOBAL_LOAD_SSHORT : FLAT_Global_Load_Pseudo <"global_load_sshort", VGPR_32>; +def GLOBAL_LOAD_DWORD : FLAT_Global_Load_Pseudo <"global_load_dword", VGPR_32>; +def GLOBAL_LOAD_DWORDX2 : FLAT_Global_Load_Pseudo <"global_load_dwordx2", VReg_64>; +def GLOBAL_LOAD_DWORDX3 : FLAT_Global_Load_Pseudo <"global_load_dwordx3", VReg_96>; +def GLOBAL_LOAD_DWORDX4 : FLAT_Global_Load_Pseudo <"global_load_dwordx4", VReg_128>; + +def GLOBAL_STORE_BYTE : FLAT_Global_Store_Pseudo <"global_store_byte", VGPR_32>; +def GLOBAL_STORE_SHORT : FLAT_Global_Store_Pseudo <"global_store_short", VGPR_32>; +def GLOBAL_STORE_DWORD : FLAT_Global_Store_Pseudo <"global_store_dword", VGPR_32>; +def GLOBAL_STORE_DWORDX2 : FLAT_Global_Store_Pseudo <"global_store_dwordx2", VReg_64>; +def GLOBAL_STORE_DWORDX3 : FLAT_Global_Store_Pseudo <"global_store_dwordx3", VReg_96>; +def GLOBAL_STORE_DWORDX4 : FLAT_Global_Store_Pseudo <"global_store_dwordx4", VReg_128>; + +} // End SubtargetPredicate = HasFlatGlobalInsts + + //===----------------------------------------------------------------------===// // Flat Patterns //===----------------------------------------------------------------------===// @@ -557,3 +604,18 @@ defm FLAT_ATOMIC_XOR_X2 : FLAT_Real_Atomics_vi <0x6a, FLAT_ATOMIC_XOR_X2>; defm FLAT_ATOMIC_INC_X2 : FLAT_Real_Atomics_vi <0x6b, FLAT_ATOMIC_INC_X2>; defm FLAT_ATOMIC_DEC_X2 : FLAT_Real_Atomics_vi <0x6c, FLAT_ATOMIC_DEC_X2>; +def GLOBAL_LOAD_UBYTE_vi : FLAT_Real_vi <0x10, GLOBAL_LOAD_UBYTE>; +def GLOBAL_LOAD_SBYTE_vi : FLAT_Real_vi <0x11, GLOBAL_LOAD_SBYTE>; +def GLOBAL_LOAD_USHORT_vi : FLAT_Real_vi <0x12, GLOBAL_LOAD_USHORT>; +def GLOBAL_LOAD_SSHORT_vi : FLAT_Real_vi <0x13, GLOBAL_LOAD_SSHORT>; +def GLOBAL_LOAD_DWORD_vi : FLAT_Real_vi <0x14, GLOBAL_LOAD_DWORD>; +def GLOBAL_LOAD_DWORDX2_vi : FLAT_Real_vi <0x15, GLOBAL_LOAD_DWORDX2>; +def GLOBAL_LOAD_DWORDX4_vi : FLAT_Real_vi <0x17, GLOBAL_LOAD_DWORDX4>; +def GLOBAL_LOAD_DWORDX3_vi : FLAT_Real_vi <0x16, GLOBAL_LOAD_DWORDX3>; + +def GLOBAL_STORE_BYTE_vi : FLAT_Real_vi <0x18, GLOBAL_STORE_BYTE>; +def GLOBAL_STORE_SHORT_vi : FLAT_Real_vi <0x1a, GLOBAL_STORE_SHORT>; +def GLOBAL_STORE_DWORD_vi : FLAT_Real_vi <0x1c, GLOBAL_STORE_DWORD>; +def GLOBAL_STORE_DWORDX2_vi : FLAT_Real_vi <0x1d, GLOBAL_STORE_DWORDX2>; +def GLOBAL_STORE_DWORDX4_vi : FLAT_Real_vi <0x1f, GLOBAL_STORE_DWORDX4>; +def GLOBAL_STORE_DWORDX3_vi : FLAT_Real_vi <0x1e, GLOBAL_STORE_DWORDX3>; diff --git a/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp b/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp index b84640230eee..7c31c8e397ba 100644 --- a/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.cpp @@ -72,6 +72,11 @@ void AMDGPUInstPrinter::printU16ImmDecOperand(const MCInst *MI, unsigned OpNo, O << formatDec(MI->getOperand(OpNo).getImm() & 0xffff); } +void AMDGPUInstPrinter::printS16ImmDecOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + O << formatDec(static_cast(MI->getOperand(OpNo).getImm())); +} + void AMDGPUInstPrinter::printU32ImmOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O) { @@ -118,6 +123,16 @@ void AMDGPUInstPrinter::printOffset(const MCInst *MI, unsigned OpNo, } } +void AMDGPUInstPrinter::printOffsetS13(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + uint16_t Imm = MI->getOperand(OpNo).getImm(); + if (Imm != 0) { + O << ((OpNo == 0)? "offset:" : " offset:"); + printS16ImmDecOperand(MI, OpNo, O); + } +} + void AMDGPUInstPrinter::printOffset0(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O) { @@ -216,6 +231,24 @@ void AMDGPUInstPrinter::printExpVM(const MCInst *MI, unsigned OpNo, O << " vm"; } +void AMDGPUInstPrinter::printDFMT(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + if (MI->getOperand(OpNo).getImm()) { + O << " dfmt:"; + printU8ImmDecOperand(MI, OpNo, O); + } +} + +void AMDGPUInstPrinter::printNFMT(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + if (MI->getOperand(OpNo).getImm()) { + O << " nfmt:"; + printU8ImmDecOperand(MI, OpNo, O); + } +} + void AMDGPUInstPrinter::printRegOperand(unsigned RegNo, raw_ostream &O, const MCRegisterInfo &MRI) { switch (RegNo) { @@ -379,7 +412,6 @@ void AMDGPUInstPrinter::printImmediateV216(uint32_t Imm, const MCSubtargetInfo &STI, raw_ostream &O) { uint16_t Lo16 = static_cast(Imm); - assert(Lo16 == static_cast(Imm >> 16)); printImmediate16(Lo16, STI, O); } diff --git a/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h b/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h index c8094c4b840a..7bbf99a85f40 100644 --- a/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h +++ b/contrib/llvm/lib/Target/AMDGPU/InstPrinter/AMDGPUInstPrinter.h @@ -42,6 +42,7 @@ class AMDGPUInstPrinter : public MCInstPrinter { void printU4ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printU8ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printU16ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printS16ImmDecOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printU32ImmOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); void printNamedBit(const MCInst *MI, unsigned OpNo, raw_ostream &O, @@ -52,6 +53,9 @@ class AMDGPUInstPrinter : public MCInstPrinter { void printMBUFOffset(const MCInst *MI, unsigned OpNo, raw_ostream &O); void printOffset(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); + void printOffsetS13(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O); + void printOffset0(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); void printOffset1(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, @@ -84,6 +88,10 @@ class AMDGPUInstPrinter : public MCInstPrinter { const MCSubtargetInfo &STI, raw_ostream &O); void printExpVM(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, raw_ostream &O); + void printDFMT(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printNFMT(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); void printRegOperand(unsigned RegNo, raw_ostream &O); void printVOPDst(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp index 0a9c2b94c1ee..2b408ff10caa 100644 --- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp @@ -30,14 +30,9 @@ class AMDGPUAsmBackend : public MCAsmBackend { unsigned getNumFixupKinds() const override { return AMDGPU::NumTargetFixupKinds; }; - void processFixupValue(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFixup &Fixup, const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) override; - - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, const MCRelaxableFragment *DF, const MCAsmLayout &Layout) const override { @@ -102,36 +97,11 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, } } -void AMDGPUAsmBackend::processFixupValue(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFixup &Fixup, const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) { - MCValue Res; - - // When we have complex expressions like: BB0_1 + (BB0_2 - 4), which are - // used for long branches, this function will be called with - // IsResolved = false and Value set to some pre-computed value. In - // the example above, the value would be: - // (BB0_1 + (BB0_2 - 4)) - CurrentOffsetFromStartOfFunction. - // This is not what we want. We just want the expression computation - // only. The reason the MC layer subtracts the current offset from the - // expression is because the fixup is of kind FK_PCRel_4. - // For these scenarios, evaluateAsValue gives us the computation that we - // want. - if (!IsResolved && Fixup.getValue()->evaluateAsValue(Res, Layout) && - Res.isAbsolute()) { - Value = Res.getConstant(); - IsResolved = true; - - } - if (IsResolved) - Value = adjustFixupValue(Fixup, Value, &Asm.getContext()); -} - -void AMDGPUAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, - bool IsPCRel, MCContext &Ctx) const { +void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsPCRel) const { + Value = adjustFixupValue(Fixup, Value, &Asm.getContext()); if (!Value) return; // Doesn't change encoding. @@ -142,7 +112,7 @@ void AMDGPUAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); uint32_t Offset = Fixup.getOffset(); - assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); // For each byte of the fragment that the fixup touches, mask in the bits from // the fixup value. diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h index a856b17a228f..1b062064ace1 100644 --- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h +++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCCodeEmitter.h @@ -52,15 +52,15 @@ class AMDGPUMCCodeEmitter : public MCCodeEmitter { return 0; } - virtual unsigned getSDWA9SrcEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const { + virtual unsigned getSDWASrcEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { return 0; } - virtual unsigned getSDWA9VopcDstEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const { + virtual unsigned getSDWAVopcDstEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { return 0; } diff --git a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp index e02acf516c0d..376c9bfe5ccf 100644 --- a/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/MCTargetDesc/SIMCCodeEmitter.cpp @@ -70,13 +70,13 @@ class SIMCCodeEmitter : public AMDGPUMCCodeEmitter { SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const override; - unsigned getSDWA9SrcEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const override; + unsigned getSDWASrcEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; - unsigned getSDWA9VopcDstEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const override; + unsigned getSDWAVopcDstEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; }; } // end anonymous namespace @@ -252,9 +252,7 @@ uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO, case AMDGPU::OPERAND_REG_INLINE_C_V2INT16: case AMDGPU::OPERAND_REG_INLINE_C_V2FP16: { uint16_t Lo16 = static_cast(Imm); - assert(Lo16 == static_cast(Imm >> 16)); uint32_t Encoding = getLit16Encoding(Lo16, STI); - assert(Encoding != 255 && "packed constants can only be inline immediates"); return Encoding; } default: @@ -328,11 +326,11 @@ unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo, } unsigned -SIMCCodeEmitter::getSDWA9SrcEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const { +SIMCCodeEmitter::getSDWASrcEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { using namespace AMDGPU::SDWA; - + uint64_t RegEnc = 0; const MCOperand &MO = MI.getOperand(OpNo); @@ -347,9 +345,9 @@ SIMCCodeEmitter::getSDWA9SrcEncoding(const MCInst &MI, unsigned OpNo, } unsigned -SIMCCodeEmitter::getSDWA9VopcDstEncoding(const MCInst &MI, unsigned OpNo, - SmallVectorImpl &Fixups, - const MCSubtargetInfo &STI) const { +SIMCCodeEmitter::getSDWAVopcDstEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { using namespace AMDGPU::SDWA; uint64_t RegEnc = 0; @@ -365,6 +363,25 @@ SIMCCodeEmitter::getSDWA9VopcDstEncoding(const MCInst &MI, unsigned OpNo, return RegEnc; } +static bool needsPCRel(const MCExpr *Expr) { + switch (Expr->getKind()) { + case MCExpr::SymbolRef: + return true; + case MCExpr::Binary: { + auto *BE = cast(Expr); + if (BE->getOpcode() == MCBinaryExpr::Sub) + return false; + return needsPCRel(BE->getLHS()) || needsPCRel(BE->getRHS()); + } + case MCExpr::Unary: + return needsPCRel(cast(Expr)->getSubExpr()); + case MCExpr::Target: + case MCExpr::Constant: + return false; + } + llvm_unreachable("invalid kind"); +} + uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl &Fixups, @@ -373,12 +390,21 @@ uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, return MRI.getEncodingValue(MO.getReg()); if (MO.isExpr() && MO.getExpr()->getKind() != MCExpr::Constant) { - const auto *Expr = dyn_cast(MO.getExpr()); + // FIXME: If this is expression is PCRel or not should not depend on what + // the expression looks like. Given that this is just a general expression, + // it should probably be FK_Data_4 and whatever is producing + // + // s_add_u32 s2, s2, (extern_const_addrspace+16 + // + // And expecting a PCRel should instead produce + // + // .Ltmp1: + // s_add_u32 s2, s2, (extern_const_addrspace+16)-.Ltmp1 MCFixupKind Kind; - if (Expr && Expr->getSymbol().isExternal()) - Kind = FK_Data_4; - else + if (needsPCRel(MO.getExpr())) Kind = FK_PCRel_4; + else + Kind = FK_Data_4; Fixups.push_back(MCFixup::create(4, MO.getExpr(), Kind, MI.getLoc())); } diff --git a/contrib/llvm/lib/Target/AMDGPU/Processors.td b/contrib/llvm/lib/Target/AMDGPU/Processors.td index f6f2582aa11b..d30d1d382588 100644 --- a/contrib/llvm/lib/Target/AMDGPU/Processors.td +++ b/contrib/llvm/lib/Target/AMDGPU/Processors.td @@ -80,7 +80,7 @@ def : Proc<"cayman", R600_VLIW4_Itin, // Southern Islands //===----------------------------------------------------------------------===// -def : ProcessorModel<"gfx600", SIFullSpeedModel, +def : ProcessorModel<"gfx600", SIFullSpeedModel, [FeatureISAVersion6_0_0]>; def : ProcessorModel<"SI", SIFullSpeedModel, @@ -95,7 +95,7 @@ def : ProcessorModel<"gfx601", SIQuarterSpeedModel, [FeatureISAVersion6_0_1] >; -def : ProcessorModel<"pitcairn", SIQuarterSpeedModel, +def : ProcessorModel<"pitcairn", SIQuarterSpeedModel, [FeatureISAVersion6_0_1]>; def : ProcessorModel<"verde", SIQuarterSpeedModel, diff --git a/contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp index c55878f8bff0..215791f4f92d 100644 --- a/contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/R600ISelLowering.cpp @@ -584,23 +584,23 @@ SDValue R600TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const return LowerImplicitParameter(DAG, VT, DL, 8); case Intrinsic::r600_read_tgid_x: - return CreateLiveInRegister(DAG, &AMDGPU::R600_TReg32RegClass, - AMDGPU::T1_X, VT); + return CreateLiveInRegisterRaw(DAG, &AMDGPU::R600_TReg32RegClass, + AMDGPU::T1_X, VT); case Intrinsic::r600_read_tgid_y: - return CreateLiveInRegister(DAG, &AMDGPU::R600_TReg32RegClass, - AMDGPU::T1_Y, VT); + return CreateLiveInRegisterRaw(DAG, &AMDGPU::R600_TReg32RegClass, + AMDGPU::T1_Y, VT); case Intrinsic::r600_read_tgid_z: - return CreateLiveInRegister(DAG, &AMDGPU::R600_TReg32RegClass, - AMDGPU::T1_Z, VT); + return CreateLiveInRegisterRaw(DAG, &AMDGPU::R600_TReg32RegClass, + AMDGPU::T1_Z, VT); case Intrinsic::r600_read_tidig_x: - return CreateLiveInRegister(DAG, &AMDGPU::R600_TReg32RegClass, - AMDGPU::T0_X, VT); + return CreateLiveInRegisterRaw(DAG, &AMDGPU::R600_TReg32RegClass, + AMDGPU::T0_X, VT); case Intrinsic::r600_read_tidig_y: - return CreateLiveInRegister(DAG, &AMDGPU::R600_TReg32RegClass, - AMDGPU::T0_Y, VT); + return CreateLiveInRegisterRaw(DAG, &AMDGPU::R600_TReg32RegClass, + AMDGPU::T0_Y, VT); case Intrinsic::r600_read_tidig_z: - return CreateLiveInRegister(DAG, &AMDGPU::R600_TReg32RegClass, - AMDGPU::T0_Z, VT); + return CreateLiveInRegisterRaw(DAG, &AMDGPU::R600_TReg32RegClass, + AMDGPU::T0_Z, VT); case Intrinsic::r600_recipsqrt_ieee: return DAG.getNode(AMDGPUISD::RSQ, DL, VT, Op.getOperand(1)); diff --git a/contrib/llvm/lib/Target/AMDGPU/SIDefines.h b/contrib/llvm/lib/Target/AMDGPU/SIDefines.h index 5cd90323ff67..3915c0e5bdbe 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIDefines.h +++ b/contrib/llvm/lib/Target/AMDGPU/SIDefines.h @@ -118,9 +118,9 @@ namespace AMDGPU { // Operand for source modifiers for VOP instructions OPERAND_INPUT_MODS, - // Operand for GFX9 SDWA instructions - OPERAND_SDWA9_SRC, - OPERAND_SDWA9_VOPC_DST, + // Operand for SDWA instructions + OPERAND_SDWA_SRC, + OPERAND_SDWA_VOPC_DST, /// Operand with 32-bit immediate that uses the constant bus. OPERAND_KIMM32, diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp b/contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp index 5f5f25103c02..0a795c99f94e 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIFixSGPRCopies.cpp @@ -174,6 +174,31 @@ static bool isSGPRToVGPRCopy(const TargetRegisterClass *SrcRC, return TRI.isSGPRClass(SrcRC) && TRI.hasVGPRs(DstRC); } +static bool tryChangeVGPRtoSGPRinCopy(MachineInstr &MI, + const SIRegisterInfo *TRI, + const SIInstrInfo *TII) { + MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); + auto &Src = MI.getOperand(1); + unsigned DstReg = MI.getOperand(0).getReg(); + unsigned SrcReg = Src.getReg(); + if (!TargetRegisterInfo::isVirtualRegister(SrcReg) || + !TargetRegisterInfo::isVirtualRegister(DstReg)) + return false; + + for (const auto &MO : MRI.reg_nodbg_operands(DstReg)) { + const auto *UseMI = MO.getParent(); + if (UseMI == &MI) + continue; + if (MO.isDef() || UseMI->getParent() != MI.getParent() || + UseMI->getOpcode() <= TargetOpcode::GENERIC_OP_END || + !TII->isOperandLegal(*UseMI, UseMI->getOperandNo(&MO), &Src)) + return false; + } + // Change VGPR to SGPR destination. + MRI.setRegClass(DstReg, TRI->getEquivalentSGPRClass(MRI.getRegClass(DstReg))); + return true; +} + // Distribute an SGPR->VGPR copy of a REG_SEQUENCE into a VGPR REG_SEQUENCE. // // SGPRx = ... @@ -214,6 +239,9 @@ static bool foldVGPRCopyIntoRegSequence(MachineInstr &MI, if (!isSGPRToVGPRCopy(SrcRC, DstRC, *TRI)) return false; + if (tryChangeVGPRtoSGPRinCopy(CopyUse, TRI, TII)) + return true; + // TODO: Could have multiple extracts? unsigned SubReg = CopyUse.getOperand(1).getSubReg(); if (SubReg != AMDGPU::NoSubRegister) @@ -563,6 +591,8 @@ bool SIFixSGPRCopies::runOnMachineFunction(MachineFunction &MF) { break; } TII->moveToVALU(MI); + } else if (isSGPRToVGPRCopy(SrcRC, DstRC, *TRI)) { + tryChangeVGPRtoSGPRinCopy(MI, TRI, TII); } break; diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index e10f1ed3762e..f391f67a241f 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -13,6 +13,7 @@ #include "AMDGPUSubtarget.h" #include "SIInstrInfo.h" #include "SIMachineFunctionInfo.h" +#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -166,6 +167,8 @@ static bool updateOperand(FoldCandidate &Fold, if (TargetRegisterInfo::isVirtualRegister(Old.getReg()) && TargetRegisterInfo::isVirtualRegister(New->getReg())) { Old.substVirtReg(New->getReg(), New->getSubReg(), TRI); + + Old.setIsUndef(New->isUndef()); return true; } @@ -470,7 +473,7 @@ static MachineOperand *getImmOrMaterializedImm(MachineRegisterInfo &MRI, return &Op; MachineInstr *Def = MRI.getVRegDef(Op.getReg()); - if (Def->isMoveImmediate()) { + if (Def && Def->isMoveImmediate()) { MachineOperand &ImmSrc = Def->getOperand(1); if (ImmSrc.isImm()) return &ImmSrc; @@ -921,12 +924,9 @@ bool SIFoldOperands::runOnMachineFunction(MachineFunction &MF) { // level. bool IsIEEEMode = ST->enableIEEEBit(MF) || !MFI->hasNoSignedZerosFPMath(); - for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); - BI != BE; ++BI) { - - MachineBasicBlock &MBB = *BI; + for (MachineBasicBlock *MBB : depth_first(&MF)) { MachineBasicBlock::iterator I, Next; - for (I = MBB.begin(); I != MBB.end(); I = Next) { + for (I = MBB->begin(); I != MBB->end(); I = Next) { Next = std::next(I); MachineInstr &MI = *I; diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp index b1bd14e421f0..08a64de38501 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.cpp @@ -284,7 +284,7 @@ void SIFrameLowering::emitEntryFunctionPrologue(MachineFunction &MF, MF, SIRegisterInfo::PRIVATE_SEGMENT_WAVE_BYTE_OFFSET); unsigned PreloadedPrivateBufferReg = AMDGPU::NoRegister; - if (ST.isAmdCodeObjectV2(MF) || ST.isMesaGfxShader(MF)) { + if (ST.isAmdCodeObjectV2(MF)) { PreloadedPrivateBufferReg = TRI->getPreloadedValue( MF, SIRegisterInfo::PRIVATE_SEGMENT_BUFFER); } @@ -363,14 +363,14 @@ void SIFrameLowering::emitEntryFunctionPrologue(MachineFunction &MF, // Use relocations to get the pointer, and setup the other bits manually. uint64_t Rsrc23 = TII->getScratchRsrcWords23(); - if (MFI->hasPrivateMemoryInputPtr()) { + if (MFI->hasImplicitBufferPtr()) { unsigned Rsrc01 = TRI->getSubReg(ScratchRsrcReg, AMDGPU::sub0_sub1); if (AMDGPU::isCompute(MF.getFunction()->getCallingConv())) { const MCInstrDesc &Mov64 = TII->get(AMDGPU::S_MOV_B64); BuildMI(MBB, I, DL, Mov64, Rsrc01) - .addReg(PreloadedPrivateBufferReg) + .addReg(MFI->getImplicitBufferPtrUserSGPR()) .addReg(ScratchRsrcReg, RegState::ImplicitDefine); } else { const MCInstrDesc &LoadDwordX2 = TII->get(AMDGPU::S_LOAD_DWORDX2_IMM); @@ -385,7 +385,7 @@ void SIFrameLowering::emitEntryFunctionPrologue(MachineFunction &MF, MachineMemOperand::MODereferenceable, 0, 0); BuildMI(MBB, I, DL, LoadDwordX2, Rsrc01) - .addReg(PreloadedPrivateBufferReg) + .addReg(MFI->getImplicitBufferPtrUserSGPR()) .addImm(0) // offset .addImm(0) // glc .addMemOperand(MMO) @@ -417,14 +417,69 @@ void SIFrameLowering::emitEntryFunctionPrologue(MachineFunction &MF, void SIFrameLowering::emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const { - const SIMachineFunctionInfo *MFI = MF.getInfo(); - if (MFI->isEntryFunction()) + const SIMachineFunctionInfo *FuncInfo = MF.getInfo(); + if (FuncInfo->isEntryFunction()) { emitEntryFunctionPrologue(MF, MBB); + return; + } + + const MachineFrameInfo &MFI = MF.getFrameInfo(); + const SISubtarget &ST = MF.getSubtarget(); + const SIInstrInfo *TII = ST.getInstrInfo(); + + unsigned StackPtrReg = FuncInfo->getStackPtrOffsetReg(); + unsigned FramePtrReg = FuncInfo->getFrameOffsetReg(); + + MachineBasicBlock::iterator MBBI = MBB.begin(); + DebugLoc DL; + + bool NeedFP = hasFP(MF); + if (NeedFP) { + // If we need a base pointer, set it up here. It's whatever the value of + // the stack pointer is at this point. Any variable size objects will be + // allocated after this, so we can still use the base pointer to reference + // locals. + BuildMI(MBB, MBBI, DL, TII->get(AMDGPU::COPY), FramePtrReg) + .addReg(StackPtrReg) + .setMIFlag(MachineInstr::FrameSetup); + } + + uint32_t NumBytes = MFI.getStackSize(); + if (NumBytes != 0 && hasSP(MF)) { + BuildMI(MBB, MBBI, DL, TII->get(AMDGPU::S_ADD_U32), StackPtrReg) + .addReg(StackPtrReg) + .addImm(NumBytes * ST.getWavefrontSize()) + .setMIFlag(MachineInstr::FrameSetup); + } } void SIFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { + const SIMachineFunctionInfo *FuncInfo = MF.getInfo(); + if (FuncInfo->isEntryFunction()) + return; + unsigned StackPtrReg = FuncInfo->getStackPtrOffsetReg(); + if (StackPtrReg == AMDGPU::NoRegister) + return; + + const MachineFrameInfo &MFI = MF.getFrameInfo(); + uint32_t NumBytes = MFI.getStackSize(); + + const SISubtarget &ST = MF.getSubtarget(); + const SIInstrInfo *TII = ST.getInstrInfo(); + MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); + DebugLoc DL; + + // FIXME: Clarify distinction between no set SP and SP. For callee functions, + // it's really whether we need SP to be accurate or not. + + if (NumBytes != 0 && hasSP(MF)) { + BuildMI(MBB, MBBI, DL, TII->get(AMDGPU::S_SUB_U32), StackPtrReg) + .addReg(StackPtrReg) + .addImm(NumBytes * ST.getWavefrontSize()) + .setMIFlag(MachineInstr::FrameDestroy); + } } static bool allStackObjectsAreDead(const MachineFrameInfo &MFI) { @@ -557,3 +612,19 @@ void SIFrameLowering::emitDebuggerPrologue(MachineFunction &MF, WorkItemIDObjectIdx, &AMDGPU::VGPR_32RegClass, TRI); } } + +bool SIFrameLowering::hasFP(const MachineFunction &MF) const { + // All stack operations are relative to the frame offset SGPR. + // TODO: Still want to eliminate sometimes. + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + // XXX - Is this only called after frame is finalized? Should be able to check + // frame size. + return MFI.hasStackObjects() && !allStackObjectsAreDead(MFI); +} + +bool SIFrameLowering::hasSP(const MachineFunction &MF) const { + // All stack operations are relative to the frame offset SGPR. + const MachineFrameInfo &MFI = MF.getFrameInfo(); + return MFI.hasCalls() || MFI.hasVarSizedObjects(); +} diff --git a/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h b/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h index e17adbe27361..d4dfa1c7eaa8 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h +++ b/contrib/llvm/lib/Target/AMDGPU/SIFrameLowering.h @@ -60,6 +60,10 @@ class SIFrameLowering final : public AMDGPUFrameLowering { /// \brief Emits debugger prologue. void emitDebuggerPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const; + +public: + bool hasFP(const MachineFunction &MF) const override; + bool hasSP(const MachineFunction &MF) const; }; } // end namespace llvm diff --git a/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp index 441f1ef4bd04..d0f4e00994de 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.cpp @@ -211,6 +211,9 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction(ISD::UADDO, MVT::i32, Legal); setOperationAction(ISD::USUBO, MVT::i32, Legal); + setOperationAction(ISD::ADDCARRY, MVT::i32, Legal); + setOperationAction(ISD::SUBCARRY, MVT::i32, Legal); + // We only support LOAD/STORE and vector manipulation ops for vectors // with > 4 elements. for (MVT VT : {MVT::v8i32, MVT::v8f32, MVT::v16i32, MVT::v16f32, @@ -471,6 +474,10 @@ SITargetLowering::SITargetLowering(const TargetMachine &TM, setOperationAction(ISD::SELECT, VT, Custom); } + setTargetDAGCombine(ISD::ADD); + setTargetDAGCombine(ISD::ADDCARRY); + setTargetDAGCombine(ISD::SUB); + setTargetDAGCombine(ISD::SUBCARRY); setTargetDAGCombine(ISD::FADD); setTargetDAGCombine(ISD::FSUB); setTargetDAGCombine(ISD::FMINNUM); @@ -1061,10 +1068,10 @@ static void allocateHSAUserSGPRs(CCState &CCInfo, MachineFunction &MF, const SIRegisterInfo &TRI, SIMachineFunctionInfo &Info) { - if (Info.hasPrivateMemoryInputPtr()) { - unsigned PrivateMemoryPtrReg = Info.addPrivateMemoryPtr(TRI); - MF.addLiveIn(PrivateMemoryPtrReg, &AMDGPU::SGPR_64RegClass); - CCInfo.AllocateReg(PrivateMemoryPtrReg); + if (Info.hasImplicitBufferPtr()) { + unsigned ImplicitBufferPtrReg = Info.addImplicitBufferPtr(TRI); + MF.addLiveIn(ImplicitBufferPtrReg, &AMDGPU::SGPR_64RegClass); + CCInfo.AllocateReg(ImplicitBufferPtrReg); } // FIXME: How should these inputs interact with inreg / custom SGPR inputs? @@ -1227,7 +1234,7 @@ static void reservePrivateMemoryRegs(const TargetMachine &TM, } } - if (NeedSP){ + if (NeedSP) { unsigned ReservedStackPtrOffsetReg = TRI.reservedStackPtrOffsetReg(MF); Info.setStackPtrOffsetReg(ReservedStackPtrOffsetReg); @@ -2998,7 +3005,11 @@ SDValue SITargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, switch (IntrinsicID) { case Intrinsic::amdgcn_implicit_buffer_ptr: { - unsigned Reg = TRI->getPreloadedValue(MF, SIRegisterInfo::PRIVATE_SEGMENT_BUFFER); + if (getSubtarget()->isAmdCodeObjectV2(MF)) + return emitNonHSAIntrinsicError(DAG, DL, VT); + + unsigned Reg = TRI->getPreloadedValue(MF, + SIRegisterInfo::IMPLICIT_BUFFER_PTR); return CreateLiveInRegister(DAG, &AMDGPU::SReg_64RegClass, Reg, VT); } case Intrinsic::amdgcn_dispatch_ptr: @@ -3288,6 +3299,8 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const { unsigned IntrID = cast(Op.getOperand(1))->getZExtValue(); SDLoc DL(Op); + MachineFunction &MF = DAG.getMachineFunction(); + switch (IntrID) { case Intrinsic::amdgcn_atomic_inc: case Intrinsic::amdgcn_atomic_dec: { @@ -3313,7 +3326,6 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, Op.getOperand(5), // glc Op.getOperand(6) // slc }; - MachineFunction &MF = DAG.getMachineFunction(); SIMachineFunctionInfo *MFI = MF.getInfo(); unsigned Opc = (IntrID == Intrinsic::amdgcn_buffer_load) ? @@ -3328,6 +3340,29 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, return DAG.getMemIntrinsicNode(Opc, DL, Op->getVTList(), Ops, IntVT, MMO); } + case Intrinsic::amdgcn_tbuffer_load: { + SDValue Ops[] = { + Op.getOperand(0), // Chain + Op.getOperand(2), // rsrc + Op.getOperand(3), // vindex + Op.getOperand(4), // voffset + Op.getOperand(5), // soffset + Op.getOperand(6), // offset + Op.getOperand(7), // dfmt + Op.getOperand(8), // nfmt + Op.getOperand(9), // glc + Op.getOperand(10) // slc + }; + + EVT VT = Op.getOperand(2).getValueType(); + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo(), + MachineMemOperand::MOLoad, + VT.getStoreSize(), VT.getStoreSize()); + return DAG.getMemIntrinsicNode(AMDGPUISD::TBUFFER_LOAD_FORMAT, DL, + Op->getVTList(), Ops, VT, MMO); + } // Basic sample. case Intrinsic::amdgcn_image_sample: case Intrinsic::amdgcn_image_sample_cl: @@ -3393,10 +3428,10 @@ SDValue SITargetLowering::LowerINTRINSIC_W_CHAIN(SDValue Op, SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const { - MachineFunction &MF = DAG.getMachineFunction(); SDLoc DL(Op); SDValue Chain = Op.getOperand(0); unsigned IntrinsicID = cast(Op.getOperand(1))->getZExtValue(); + MachineFunction &MF = DAG.getMachineFunction(); switch (IntrinsicID) { case Intrinsic::amdgcn_exp: { @@ -3463,33 +3498,6 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, return DAG.getNode(AMDGPUISD::INIT_EXEC_FROM_INPUT, DL, MVT::Other, Chain, Op.getOperand(2), Op.getOperand(3)); } - case AMDGPUIntrinsic::SI_tbuffer_store: { - SDValue Ops[] = { - Chain, - Op.getOperand(2), - Op.getOperand(3), - Op.getOperand(4), - Op.getOperand(5), - Op.getOperand(6), - Op.getOperand(7), - Op.getOperand(8), - Op.getOperand(9), - Op.getOperand(10), - Op.getOperand(11), - Op.getOperand(12), - Op.getOperand(13), - Op.getOperand(14) - }; - - EVT VT = Op.getOperand(3).getValueType(); - - MachineMemOperand *MMO = MF.getMachineMemOperand( - MachinePointerInfo(), - MachineMemOperand::MOStore, - VT.getStoreSize(), 4); - return DAG.getMemIntrinsicNode(AMDGPUISD::TBUFFER_STORE_FORMAT, DL, - Op->getVTList(), Ops, VT, MMO); - } case AMDGPUIntrinsic::AMDGPU_kill: { SDValue Src = Op.getOperand(2); if (const ConstantFPSDNode *K = dyn_cast(Src)) { @@ -3505,7 +3513,6 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, } case Intrinsic::amdgcn_s_barrier: { if (getTargetMachine().getOptLevel() > CodeGenOpt::None) { - const MachineFunction &MF = DAG.getMachineFunction(); const SISubtarget &ST = MF.getSubtarget(); unsigned WGSize = ST.getFlatWorkGroupSizes(*MF.getFunction()).second; if (WGSize <= ST.getWavefrontSize()) @@ -3514,6 +3521,75 @@ SDValue SITargetLowering::LowerINTRINSIC_VOID(SDValue Op, } return SDValue(); }; + case AMDGPUIntrinsic::SI_tbuffer_store: { + + // Extract vindex and voffset from vaddr as appropriate + const ConstantSDNode *OffEn = cast(Op.getOperand(10)); + const ConstantSDNode *IdxEn = cast(Op.getOperand(11)); + SDValue VAddr = Op.getOperand(5); + + SDValue Zero = DAG.getTargetConstant(0, DL, MVT::i32); + + assert(!(OffEn->isOne() && IdxEn->isOne()) && + "Legacy intrinsic doesn't support both offset and index - use new version"); + + SDValue VIndex = IdxEn->isOne() ? VAddr : Zero; + SDValue VOffset = OffEn->isOne() ? VAddr : Zero; + + // Deal with the vec-3 case + const ConstantSDNode *NumChannels = cast(Op.getOperand(4)); + auto Opcode = NumChannels->getZExtValue() == 3 ? + AMDGPUISD::TBUFFER_STORE_FORMAT_X3 : AMDGPUISD::TBUFFER_STORE_FORMAT; + + SDValue Ops[] = { + Chain, + Op.getOperand(3), // vdata + Op.getOperand(2), // rsrc + VIndex, + VOffset, + Op.getOperand(6), // soffset + Op.getOperand(7), // inst_offset + Op.getOperand(8), // dfmt + Op.getOperand(9), // nfmt + Op.getOperand(12), // glc + Op.getOperand(13), // slc + }; + + assert((cast(Op.getOperand(14)))->getZExtValue() == 0 && + "Value of tfe other than zero is unsupported"); + + EVT VT = Op.getOperand(3).getValueType(); + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo(), + MachineMemOperand::MOStore, + VT.getStoreSize(), 4); + return DAG.getMemIntrinsicNode(Opcode, DL, + Op->getVTList(), Ops, VT, MMO); + } + + case Intrinsic::amdgcn_tbuffer_store: { + SDValue Ops[] = { + Chain, + Op.getOperand(2), // vdata + Op.getOperand(3), // rsrc + Op.getOperand(4), // vindex + Op.getOperand(5), // voffset + Op.getOperand(6), // soffset + Op.getOperand(7), // offset + Op.getOperand(8), // dfmt + Op.getOperand(9), // nfmt + Op.getOperand(10), // glc + Op.getOperand(11) // slc + }; + EVT VT = Op.getOperand(3).getValueType(); + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo(), + MachineMemOperand::MOStore, + VT.getStoreSize(), 4); + return DAG.getMemIntrinsicNode(AMDGPUISD::TBUFFER_STORE_FORMAT, DL, + Op->getVTList(), Ops, VT, MMO); + } + default: return Op; } @@ -4839,6 +4915,103 @@ unsigned SITargetLowering::getFusedOpcode(const SelectionDAG &DAG, return 0; } +SDValue SITargetLowering::performAddCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + EVT VT = N->getValueType(0); + + if (VT != MVT::i32) + return SDValue(); + + SDLoc SL(N); + SDValue LHS = N->getOperand(0); + SDValue RHS = N->getOperand(1); + + // add x, zext (setcc) => addcarry x, 0, setcc + // add x, sext (setcc) => subcarry x, 0, setcc + unsigned Opc = LHS.getOpcode(); + if (Opc == ISD::ZERO_EXTEND || Opc == ISD::SIGN_EXTEND || + Opc == ISD::ANY_EXTEND || Opc == ISD::ADDCARRY) + std::swap(RHS, LHS); + + Opc = RHS.getOpcode(); + switch (Opc) { + default: break; + case ISD::ZERO_EXTEND: + case ISD::SIGN_EXTEND: + case ISD::ANY_EXTEND: { + auto Cond = RHS.getOperand(0); + if (Cond.getOpcode() != ISD::SETCC && + Cond.getOpcode() != AMDGPUISD::FP_CLASS) + break; + SDVTList VTList = DAG.getVTList(MVT::i32, MVT::i1); + SDValue Args[] = { LHS, DAG.getConstant(0, SL, MVT::i32), Cond }; + Opc = (Opc == ISD::SIGN_EXTEND) ? ISD::SUBCARRY : ISD::ADDCARRY; + return DAG.getNode(Opc, SL, VTList, Args); + } + case ISD::ADDCARRY: { + // add x, (addcarry y, 0, cc) => addcarry x, y, cc + auto C = dyn_cast(RHS.getOperand(1)); + if (!C || C->getZExtValue() != 0) break; + SDValue Args[] = { LHS, RHS.getOperand(0), RHS.getOperand(2) }; + return DAG.getNode(ISD::ADDCARRY, SDLoc(N), RHS->getVTList(), Args); + } + } + return SDValue(); +} + +SDValue SITargetLowering::performSubCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + SelectionDAG &DAG = DCI.DAG; + EVT VT = N->getValueType(0); + + if (VT != MVT::i32) + return SDValue(); + + SDLoc SL(N); + SDValue LHS = N->getOperand(0); + SDValue RHS = N->getOperand(1); + + unsigned Opc = LHS.getOpcode(); + if (Opc != ISD::SUBCARRY) + std::swap(RHS, LHS); + + if (LHS.getOpcode() == ISD::SUBCARRY) { + // sub (subcarry x, 0, cc), y => subcarry x, y, cc + auto C = dyn_cast(LHS.getOperand(1)); + if (!C || C->getZExtValue() != 0) + return SDValue(); + SDValue Args[] = { LHS.getOperand(0), RHS, LHS.getOperand(2) }; + return DAG.getNode(ISD::SUBCARRY, SDLoc(N), LHS->getVTList(), Args); + } + return SDValue(); +} + +SDValue SITargetLowering::performAddCarrySubCarryCombine(SDNode *N, + DAGCombinerInfo &DCI) const { + + if (N->getValueType(0) != MVT::i32) + return SDValue(); + + auto C = dyn_cast(N->getOperand(1)); + if (!C || C->getZExtValue() != 0) + return SDValue(); + + SelectionDAG &DAG = DCI.DAG; + SDValue LHS = N->getOperand(0); + + // addcarry (add x, y), 0, cc => addcarry x, y, cc + // subcarry (sub x, y), 0, cc => subcarry x, y, cc + unsigned LHSOpc = LHS.getOpcode(); + unsigned Opc = N->getOpcode(); + if ((LHSOpc == ISD::ADD && Opc == ISD::ADDCARRY) || + (LHSOpc == ISD::SUB && Opc == ISD::SUBCARRY)) { + SDValue Args[] = { LHS.getOperand(0), LHS.getOperand(1), N->getOperand(2) }; + return DAG.getNode(Opc, SDLoc(N), N->getVTList(), Args); + } + return SDValue(); +} + SDValue SITargetLowering::performFAddCombine(SDNode *N, DAGCombinerInfo &DCI) const { if (DCI.getDAGCombineLevel() < AfterLegalizeDAG) @@ -5009,6 +5182,13 @@ SDValue SITargetLowering::PerformDAGCombine(SDNode *N, switch (N->getOpcode()) { default: return AMDGPUTargetLowering::PerformDAGCombine(N, DCI); + case ISD::ADD: + return performAddCombine(N, DCI); + case ISD::SUB: + return performSubCombine(N, DCI); + case ISD::ADDCARRY: + case ISD::SUBCARRY: + return performAddCarrySubCarryCombine(N, DCI); case ISD::FADD: return performFAddCombine(N, DCI); case ISD::FSUB: @@ -5425,15 +5605,6 @@ MachineSDNode *SITargetLowering::buildRSRC(SelectionDAG &DAG, const SDLoc &DL, return DAG.getMachineNode(AMDGPU::REG_SEQUENCE, DL, MVT::v4i32, Ops); } -SDValue SITargetLowering::CreateLiveInRegister(SelectionDAG &DAG, - const TargetRegisterClass *RC, - unsigned Reg, EVT VT) const { - SDValue VReg = AMDGPUTargetLowering::CreateLiveInRegister(DAG, RC, Reg, VT); - - return DAG.getCopyFromReg(DAG.getEntryNode(), SDLoc(DAG.getEntryNode()), - cast(VReg)->getReg(), VT); -} - //===----------------------------------------------------------------------===// // SI Inline Assembly Support //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h b/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h index 8e2ec40b224c..24f88e632d38 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h +++ b/contrib/llvm/lib/Target/AMDGPU/SIISelLowering.h @@ -108,6 +108,9 @@ class SITargetLowering final : public AMDGPUTargetLowering { unsigned getFusedOpcode(const SelectionDAG &DAG, const SDNode *N0, const SDNode *N1) const; + SDValue performAddCombine(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue performAddCarrySubCarryCombine(SDNode *N, DAGCombinerInfo &DCI) const; + SDValue performSubCombine(SDNode *N, DAGCombinerInfo &DCI) const; SDValue performFAddCombine(SDNode *N, DAGCombinerInfo &DCI) const; SDValue performFSubCombine(SDNode *N, DAGCombinerInfo &DCI) const; SDValue performSetCCCombine(SDNode *N, DAGCombinerInfo &DCI) const; @@ -216,8 +219,6 @@ class SITargetLowering final : public AMDGPUTargetLowering { void AdjustInstrPostInstrSelection(MachineInstr &MI, SDNode *Node) const override; - SDValue CreateLiveInRegister(SelectionDAG &DAG, const TargetRegisterClass *RC, - unsigned Reg, EVT VT) const override; SDNode *legalizeTargetIndependentNode(SDNode *Node, SelectionDAG &DAG) const; MachineSDNode *wrapAddr64Rsrc(SelectionDAG &DAG, const SDLoc &DL, diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp index 1097814e99ce..c9b48fea7225 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp @@ -2108,7 +2108,9 @@ bool SIInstrInfo::isInlineConstant(const APInt &Imm) const { bool SIInstrInfo::isInlineConstant(const MachineOperand &MO, uint8_t OperandType) const { - if (!MO.isImm() || OperandType < MCOI::OPERAND_FIRST_TARGET) + if (!MO.isImm() || + OperandType < AMDGPU::OPERAND_SRC_FIRST || + OperandType > AMDGPU::OPERAND_SRC_LAST) return false; // MachineOperand provides no way to tell the true operand size, since it only @@ -2433,8 +2435,73 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI, } } + // Verify SDWA + if (isSDWA(MI)) { + + if (!ST.hasSDWA()) { + ErrInfo = "SDWA is not supported on this target"; + return false; + } + + int DstIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::vdst); + if ( DstIdx == -1) + DstIdx = AMDGPU::getNamedOperandIdx(Opcode, AMDGPU::OpName::sdst); + + const int OpIndicies[] = { DstIdx, Src0Idx, Src1Idx, Src2Idx }; + + for (int OpIdx: OpIndicies) { + if (OpIdx == -1) + continue; + const MachineOperand &MO = MI.getOperand(OpIdx); + + if (!ST.hasSDWAScalar()) { + // Only VGPRS on VI + if (!MO.isReg() || !RI.hasVGPRs(RI.getRegClassForReg(MRI, MO.getReg()))) { + ErrInfo = "Only VGPRs allowed as operands in SDWA instructions on VI"; + return false; + } + } else { + // No immediates on GFX9 + if (!MO.isReg()) { + ErrInfo = "Only reg allowed as operands in SDWA instructions on GFX9"; + return false; + } + } + } + + if (!ST.hasSDWAOmod()) { + // No omod allowed on VI + const MachineOperand *OMod = getNamedOperand(MI, AMDGPU::OpName::omod); + if (OMod != nullptr && + (!OMod->isImm() || OMod->getImm() != 0)) { + ErrInfo = "OMod not allowed in SDWA instructions on VI"; + return false; + } + } + + uint16_t BasicOpcode = AMDGPU::getBasicFromSDWAOp(Opcode); + if (isVOPC(BasicOpcode)) { + if (!ST.hasSDWASdst() && DstIdx != -1) { + // Only vcc allowed as dst on VI for VOPC + const MachineOperand &Dst = MI.getOperand(DstIdx); + if (!Dst.isReg() || Dst.getReg() != AMDGPU::VCC) { + ErrInfo = "Only VCC allowed as dst in SDWA instructions on VI"; + return false; + } + } else if (!ST.hasSDWAClampVOPC()) { + // No clamp allowed on GFX9 for VOPC + const MachineOperand *Clamp = getNamedOperand(MI, AMDGPU::OpName::clamp); + if (Clamp != nullptr && + (!Clamp->isImm() || Clamp->getImm() != 0)) { + ErrInfo = "Clamp not allowed in VOPC SDWA instructions on VI"; + return false; + } + } + } + } + // Verify VOP* - if (isVOP1(MI) || isVOP2(MI) || isVOP3(MI) || isVOPC(MI)) { + if (isVOP1(MI) || isVOP2(MI) || isVOP3(MI) || isVOPC(MI) || isSDWA(MI)) { // Only look at the true operands. Only a real operand can use the constant // bus, and we don't want to check pseudo-operands like the source modifier // flags. diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h index f6e5e8883f63..74b48c761808 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h +++ b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.h @@ -813,6 +813,9 @@ namespace AMDGPU { LLVM_READONLY int getSDWAOp(uint16_t Opcode); + LLVM_READONLY + int getBasicFromSDWAOp(uint16_t Opcode); + LLVM_READONLY int getCommuteRev(uint16_t Opcode); diff --git a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td index 470a47b02443..3b4a8b5d1e81 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td +++ b/contrib/llvm/lib/Target/AMDGPU/SIInstrInfo.td @@ -20,6 +20,8 @@ def SIEncodingFamily { int NONE = -1; int SI = 0; int VI = 1; + int SDWA = 2; + int SDWA9 = 3; } //===----------------------------------------------------------------------===// @@ -39,25 +41,41 @@ def SIatomic_dec : SDNode<"AMDGPUISD::ATOMIC_DEC", SDTAtomic2, [SDNPMayLoad, SDNPMayStore, SDNPMemOperand, SDNPHasChain] >; -def SItbuffer_store : SDNode<"AMDGPUISD::TBUFFER_STORE_FORMAT", - SDTypeProfile<0, 13, - [SDTCisVT<0, v4i32>, // rsrc(SGPR) - SDTCisVT<1, iAny>, // vdata(VGPR) - SDTCisVT<2, i32>, // num_channels(imm) - SDTCisVT<3, i32>, // vaddr(VGPR) +def SItbuffer_load : SDNode<"AMDGPUISD::TBUFFER_LOAD_FORMAT", + SDTypeProfile<1, 9, + [ // vdata + SDTCisVT<1, v4i32>, // rsrc + SDTCisVT<2, i32>, // vindex(VGPR) + SDTCisVT<3, i32>, // voffset(VGPR) SDTCisVT<4, i32>, // soffset(SGPR) - SDTCisVT<5, i32>, // inst_offset(imm) + SDTCisVT<5, i32>, // offset(imm) SDTCisVT<6, i32>, // dfmt(imm) SDTCisVT<7, i32>, // nfmt(imm) - SDTCisVT<8, i32>, // offen(imm) - SDTCisVT<9, i32>, // idxen(imm) - SDTCisVT<10, i32>, // glc(imm) - SDTCisVT<11, i32>, // slc(imm) - SDTCisVT<12, i32> // tfe(imm) + SDTCisVT<8, i32>, // glc(imm) + SDTCisVT<9, i32> // slc(imm) ]>, - [SDNPMayStore, SDNPMemOperand, SDNPHasChain] + [SDNPMayLoad, SDNPMemOperand, SDNPHasChain] >; +def SDTtbuffer_store : SDTypeProfile<0, 10, + [ // vdata + SDTCisVT<1, v4i32>, // rsrc + SDTCisVT<2, i32>, // vindex(VGPR) + SDTCisVT<3, i32>, // voffset(VGPR) + SDTCisVT<4, i32>, // soffset(SGPR) + SDTCisVT<5, i32>, // offset(imm) + SDTCisVT<6, i32>, // dfmt(imm) + SDTCisVT<7, i32>, // nfmt(imm) + SDTCisVT<8, i32>, // glc(imm) + SDTCisVT<9, i32> // slc(imm) + ]>; + +def SItbuffer_store : SDNode<"AMDGPUISD::TBUFFER_STORE_FORMAT", SDTtbuffer_store, + [SDNPMayStore, SDNPMemOperand, SDNPHasChain]>; +def SItbuffer_store_x3 : SDNode<"AMDGPUISD::TBUFFER_STORE_FORMAT_X3", + SDTtbuffer_store, + [SDNPMayStore, SDNPMemOperand, SDNPHasChain]>; + def SDTBufferLoad : SDTypeProfile<1, 5, [ // vdata SDTCisVT<1, v4i32>, // rsrc @@ -452,25 +470,25 @@ def ExpSrc3 : RegisterOperand { let ParserMatchClass = VReg32OrOffClass; } -class SDWA9Src : RegisterOperand { +class SDWASrc : RegisterOperand { let OperandNamespace = "AMDGPU"; - let OperandType = "OPERAND_SDWA9_SRC"; - let EncoderMethod = "getSDWA9SrcEncoding"; + let OperandType = "OPERAND_SDWA_SRC"; + let EncoderMethod = "getSDWASrcEncoding"; } -def SDWA9Src32 : SDWA9Src { - let DecoderMethod = "decodeSDWA9Src32"; +def SDWASrc32 : SDWASrc { + let DecoderMethod = "decodeSDWASrc32"; } -def SDWA9Src16 : SDWA9Src { - let DecoderMethod = "decodeSDWA9Src16"; +def SDWASrc16 : SDWASrc { + let DecoderMethod = "decodeSDWASrc16"; } -def SDWA9VopcDst : VOPDstOperand { +def SDWAVopcDst : VOPDstOperand { let OperandNamespace = "AMDGPU"; - let OperandType = "OPERAND_SDWA9_VOPC_DST"; - let EncoderMethod = "getSDWA9VopcDstEncoding"; - let DecoderMethod = "decodeSDWA9VopcDst"; + let OperandType = "OPERAND_SDWA_VOPC_DST"; + let EncoderMethod = "getSDWAVopcDstEncoding"; + let DecoderMethod = "decodeSDWAVopcDst"; } class NamedMatchClass : AsmOperandClass { @@ -525,7 +543,7 @@ def idxen : NamedOperandBit<"Idxen", NamedMatchClass<"Idxen">>; def addr64 : NamedOperandBit<"Addr64", NamedMatchClass<"Addr64">>; def offset_u12 : NamedOperandU12<"Offset", NamedMatchClass<"OffsetU12">>; -def offset_s13 : NamedOperandS13<"Offset", NamedMatchClass<"OffsetS13">>; +def offset_s13 : NamedOperandS13<"OffsetS13", NamedMatchClass<"OffsetS13">>; def offset : NamedOperandU16<"Offset", NamedMatchClass<"Offset">>; def offset0 : NamedOperandU8<"Offset0", NamedMatchClass<"Offset0">>; def offset1 : NamedOperandU8<"Offset1", NamedMatchClass<"Offset1">>; @@ -545,6 +563,9 @@ def lwe : NamedOperandBit<"LWE", NamedMatchClass<"LWE">>; def exp_compr : NamedOperandBit<"ExpCompr", NamedMatchClass<"ExpCompr">>; def exp_vm : NamedOperandBit<"ExpVM", NamedMatchClass<"ExpVM">>; +def DFMT : NamedOperandU8<"DFMT", NamedMatchClass<"DFMT">>; +def NFMT : NamedOperandU8<"NFMT", NamedMatchClass<"NFMT">>; + def dmask : NamedOperandU16<"DMask", NamedMatchClass<"DMask">>; def dpp_ctrl : NamedOperandU32<"DPPCtrl", NamedMatchClass<"DPPCtrl", 0>>; @@ -634,13 +655,13 @@ class IntInputMods : InputMods def Int32InputMods : IntInputMods; def Int64InputMods : IntInputMods; -def FPRegInputModsMatchClass : AsmOperandClass { - let Name = "RegWithFPInputMods"; +def FPRegSDWAInputModsMatchClass : AsmOperandClass { + let Name = "SDWARegWithFPInputMods"; let ParserMethod = "parseRegWithFPInputMods"; - let PredicateMethod = "isRegKind"; + let PredicateMethod = "isSDWARegKind"; } -def FPRegInputMods : InputMods { +def FPRegSDWAInputMods : InputMods { let PrintMethod = "printOperandAndFPInputMods"; } @@ -655,13 +676,13 @@ def FPVRegInputMods : InputMods { } -def IntRegInputModsMatchClass : AsmOperandClass { - let Name = "RegWithIntInputMods"; +def IntRegSDWAInputModsMatchClass : AsmOperandClass { + let Name = "SDWARegWithIntInputMods"; let ParserMethod = "parseRegWithIntInputMods"; - let PredicateMethod = "isRegKind"; + let PredicateMethod = "isSDWARegKind"; } -def IntRegInputMods : InputMods { +def IntRegSDWAInputMods : InputMods { let PrintMethod = "printOperandAndIntInputMods"; } @@ -851,10 +872,10 @@ class getVALUDstForVT { } // Returns the register class to use for the destination of VOP[12C] -// instructions with GFX9 SDWA extension -class getSDWA9DstForVT { +// instructions with SDWA extension +class getSDWADstForVT { RegisterOperand ret = !if(!eq(VT.Size, 1), - SDWA9VopcDst, // VOPC + SDWAVopcDst, // VOPC VOPDstOperand); // VOP1/2 32-bit dst } @@ -898,8 +919,8 @@ class getVregSrcForVT { !if(!eq(VT.Size, 64), VReg_64, VGPR_32)); } -class getSDWA9SrcForVT { - RegisterOperand ret = !if(!eq(VT.Size, 16), SDWA9Src16, SDWA9Src32); +class getSDWASrcForVT { + RegisterOperand ret = !if(!eq(VT.Size, 16), SDWASrc16, SDWASrc32); } // Returns the register class to use for sources of VOP3 instructions for the @@ -995,7 +1016,7 @@ class getSrcMod { ); } -// Return type of input modifiers operand specified input operand for SDWA/DPP +// Return type of input modifiers operand specified input operand for DPP class getSrcModExt { bit isFP = !if(!eq(VT.Value, f16.Value), 1, !if(!eq(VT.Value, f32.Value), 1, @@ -1004,13 +1025,13 @@ class getSrcModExt { Operand ret = !if(isFP, FPVRegInputMods, IntVRegInputMods); } -// Return type of input modifiers operand specified input operand for SDWA 9 -class getSrcModSDWA9 { +// Return type of input modifiers operand specified input operand for SDWA +class getSrcModSDWA { bit isFP = !if(!eq(VT.Value, f16.Value), 1, !if(!eq(VT.Value, f32.Value), 1, !if(!eq(VT.Value, f64.Value), 1, 0))); - Operand ret = !if(isFP, FPRegInputMods, IntRegInputMods); + Operand ret = !if(isFP, FPRegSDWAInputMods, IntRegSDWAInputMods); } // Returns the input arguments for VOP[12C] instructions for the given SrcVT. @@ -1141,68 +1162,44 @@ class getInsDPP { - dag ret = !if(!eq(NumSrcArgs, 0), - // VOP1 without input operands (V_NOP) - (ins), - !if(!eq(NumSrcArgs, 1), - // VOP1_SDWA - (ins Src0Mod:$src0_modifiers, Src0RC:$src0, - clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused, - src0_sel:$src0_sel), - !if(!eq(NumSrcArgs, 2), - !if(!eq(DstVT.Size, 1), - // VOPC_SDWA with modifiers - (ins Src0Mod:$src0_modifiers, Src0RC:$src0, - Src1Mod:$src1_modifiers, Src1RC:$src1, - clampmod:$clamp, src0_sel:$src0_sel, src1_sel:$src1_sel), - // VOP2_SDWA with modifiers - (ins Src0Mod:$src0_modifiers, Src0RC:$src0, - Src1Mod:$src1_modifiers, Src1RC:$src1, - clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused, - src0_sel:$src0_sel, src1_sel:$src1_sel)), - (ins)/* endif */))); -} - -// Ins for GFX9 SDWA -class getInsSDWA9 { - dag ret = !if(!eq(NumSrcArgs, 0), // VOP1 without input operands (V_NOP) (ins), !if(!eq(NumSrcArgs, 1), // VOP1 !if(!eq(HasSDWAOMod, 0), - // VOP1_SDWA9 without omod + // VOP1_SDWA without omod (ins Src0Mod:$src0_modifiers, Src0RC:$src0, clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused, src0_sel:$src0_sel), - // VOP1_SDWA9 with omod + // VOP1_SDWA with omod (ins Src0Mod:$src0_modifiers, Src0RC:$src0, clampmod:$clamp, omod:$omod, dst_sel:$dst_sel, dst_unused:$dst_unused, src0_sel:$src0_sel)), !if(!eq(NumSrcArgs, 2), !if(!eq(DstVT.Size, 1), - // VOPC_SDWA9 + // VOPC_SDWA (ins Src0Mod:$src0_modifiers, Src0RC:$src0, Src1Mod:$src1_modifiers, Src1RC:$src1, - src0_sel:$src0_sel, src1_sel:$src1_sel), - // VOP2_SDWA9 + clampmod:$clamp, src0_sel:$src0_sel, src1_sel:$src1_sel), + // VOP2_SDWA !if(!eq(HasSDWAOMod, 0), - // VOP2_SDWA9 without omod + // VOP2_SDWA without omod (ins Src0Mod:$src0_modifiers, Src0RC:$src0, Src1Mod:$src1_modifiers, Src1RC:$src1, clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused, src0_sel:$src0_sel, src1_sel:$src1_sel), - // VOP1_SDWA9 with omod + // VOP2_SDWA with omod (ins Src0Mod:$src0_modifiers, Src0RC:$src0, Src1Mod:$src1_modifiers, Src1RC:$src1, clampmod:$clamp, omod:$omod, @@ -1220,12 +1217,12 @@ class getOutsExt { (outs)); // V_NOP } -// Outs for GFX9 SDWA -class getOutsSDWA9 { +// Outs for SDWA +class getOutsSDWA { dag ret = !if(HasDst, !if(!eq(DstVT.Size, 1), - (outs DstRCSDWA9:$sdst), - (outs DstRCSDWA9:$vdst)), + (outs DstRCSDWA:$sdst), + (outs DstRCSDWA:$vdst)), (outs)); // V_NOP } @@ -1387,8 +1384,7 @@ class VOPProfile _ArgVT> { field ValueType Src2VT = ArgVT[3]; field RegisterOperand DstRC = getVALUDstForVT.ret; field RegisterOperand DstRCDPP = getVALUDstForVT.ret; - field RegisterOperand DstRCSDWA = getVALUDstForVT.ret; - field RegisterOperand DstRCSDWA9 = getSDWA9DstForVT.ret; + field RegisterOperand DstRCSDWA = getSDWADstForVT.ret; field RegisterOperand Src0RC32 = getVOPSrc0ForVT.ret; field RegisterClass Src1RC32 = getVregSrcForVT.ret; field RegisterOperand Src0RC64 = getVOP3SrcForVT.ret; @@ -1396,19 +1392,15 @@ class VOPProfile _ArgVT> { field RegisterOperand Src2RC64 = getVOP3SrcForVT.ret; field RegisterClass Src0DPP = getVregSrcForVT.ret; field RegisterClass Src1DPP = getVregSrcForVT.ret; - field RegisterClass Src0SDWA = getVregSrcForVT.ret; - field RegisterClass Src1SDWA = getVregSrcForVT.ret; - field RegisterOperand Src0SDWA9 = getSDWA9SrcForVT.ret; - field RegisterOperand Src1SDWA9 = getSDWA9SrcForVT.ret; + field RegisterOperand Src0SDWA = getSDWASrcForVT.ret; + field RegisterOperand Src1SDWA = getSDWASrcForVT.ret; field Operand Src0Mod = getSrcMod.ret; field Operand Src1Mod = getSrcMod.ret; field Operand Src2Mod = getSrcMod.ret; field Operand Src0ModDPP = getSrcModExt.ret; field Operand Src1ModDPP = getSrcModExt.ret; - field Operand Src0ModSDWA = getSrcModExt.ret; - field Operand Src1ModSDWA = getSrcModExt.ret; - field Operand Src0ModSDWA9 = getSrcModSDWA9.ret; - field Operand Src1ModSDWA9 = getSrcModSDWA9.ret; + field Operand Src0ModSDWA = getSrcModSDWA.ret; + field Operand Src1ModSDWA = getSrcModSDWA.ret; field bit HasDst = !if(!eq(DstVT.Value, untyped.Value), 0, 1); @@ -1457,8 +1449,7 @@ class VOPProfile _ArgVT> { field dag Outs32 = Outs; field dag Outs64 = Outs; field dag OutsDPP = getOutsExt.ret; - field dag OutsSDWA = getOutsExt.ret; - field dag OutsSDWA9 = getOutsSDWA9.ret; + field dag OutsSDWA = getOutsSDWA.ret; field dag Ins32 = getIns32.ret; field dag Ins64 = getIns64 _ArgVT> { field dag InsDPP = getInsDPP.ret; field dag InsSDWA = getInsSDWA.ret; - field dag InsSDWA9 = getInsSDWA9.ret; + field string Asm32 = getAsm32.ret; field string Asm64 = getAsm64.ret; @@ -1628,13 +1617,13 @@ def getSDWAOp : InstrMapping { let ValueCols = [["SDWA"]]; } -// Maps ordinary instructions to their SDWA GFX9 counterparts -def getSDWA9Op : InstrMapping { +// Maps SDWA instructions to their ordinary counterparts +def getBasicFromSDWAOp : InstrMapping { let FilterClass = "VOP"; let RowFields = ["OpName"]; let ColFields = ["AsmVariantName"]; - let KeyCol = ["Default"]; - let ValueCols = [["SDWA9"]]; + let KeyCol = ["SDWA"]; + let ValueCols = [["Default"]]; } def getMaskedMIMGOp : InstrMapping { @@ -1669,7 +1658,9 @@ def getMCOpcodeGen : InstrMapping { let ColFields = ["Subtarget"]; let KeyCol = [!cast(SIEncodingFamily.NONE)]; let ValueCols = [[!cast(SIEncodingFamily.SI)], - [!cast(SIEncodingFamily.VI)]]; + [!cast(SIEncodingFamily.VI)], + [!cast(SIEncodingFamily.SDWA)], + [!cast(SIEncodingFamily.SDWA9)]]; } // Get equivalent SOPK instruction. diff --git a/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp index 18b197ddb7ae..3203c38dae34 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.cpp @@ -74,7 +74,7 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF) WorkItemIDX(false), WorkItemIDY(false), WorkItemIDZ(false), - PrivateMemoryInputPtr(false) { + ImplicitBufferPtr(false) { const SISubtarget &ST = MF.getSubtarget(); const Function *F = MF.getFunction(); FlatWorkGroupSizes = ST.getFlatWorkGroupSizes(*F); @@ -86,6 +86,7 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF) ScratchRSrcReg = AMDGPU::SGPR0_SGPR1_SGPR2_SGPR3; ScratchWaveOffsetReg = AMDGPU::SGPR4; FrameOffsetReg = AMDGPU::SGPR5; + StackPtrOffsetReg = AMDGPU::SGPR32; return; } @@ -150,7 +151,7 @@ SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF) DispatchID = true; } else if (ST.isMesaGfxShader(MF)) { if (HasStackObjects || MaySpill) - PrivateMemoryInputPtr = true; + ImplicitBufferPtr = true; } // We don't need to worry about accessing spills with flat instructions. @@ -203,11 +204,11 @@ unsigned SIMachineFunctionInfo::addFlatScratchInit(const SIRegisterInfo &TRI) { return FlatScratchInitUserSGPR; } -unsigned SIMachineFunctionInfo::addPrivateMemoryPtr(const SIRegisterInfo &TRI) { - PrivateMemoryPtrUserSGPR = TRI.getMatchingSuperReg( +unsigned SIMachineFunctionInfo::addImplicitBufferPtr(const SIRegisterInfo &TRI) { + ImplicitBufferPtrUserSGPR = TRI.getMatchingSuperReg( getNextUserSGPR(), AMDGPU::sub0, &AMDGPU::SReg_64RegClass); NumUserSGPRs += 2; - return PrivateMemoryPtrUserSGPR; + return ImplicitBufferPtrUserSGPR; } /// Reserve a slice of a VGPR to support spilling for FrameIndex \p FI. diff --git a/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h b/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h index 9fdb8caac6f2..05aa249584bf 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h +++ b/contrib/llvm/lib/Target/AMDGPU/SIMachineFunctionInfo.h @@ -97,7 +97,7 @@ class SIMachineFunctionInfo final : public AMDGPUMachineFunction { unsigned StackPtrOffsetReg; // Input registers for non-HSA ABI - unsigned PrivateMemoryPtrUserSGPR; + unsigned ImplicitBufferPtrUserSGPR; // Input registers setup for the HSA ABI. // User SGPRs in allocation order. @@ -179,7 +179,7 @@ class SIMachineFunctionInfo final : public AMDGPUMachineFunction { // Private memory buffer // Compute directly in sgpr[0:1] // Other shaders indirect 64-bits at sgpr[0:1] - bool PrivateMemoryInputPtr : 1; + bool ImplicitBufferPtr : 1; MCPhysReg getNextUserSGPR() const { assert(NumSystemSGPRs == 0 && "System SGPRs must be added after user SGPRs"); @@ -236,7 +236,7 @@ class SIMachineFunctionInfo final : public AMDGPUMachineFunction { unsigned addKernargSegmentPtr(const SIRegisterInfo &TRI); unsigned addDispatchID(const SIRegisterInfo &TRI); unsigned addFlatScratchInit(const SIRegisterInfo &TRI); - unsigned addPrivateMemoryPtr(const SIRegisterInfo &TRI); + unsigned addImplicitBufferPtr(const SIRegisterInfo &TRI); // Add system SGPRs. unsigned addWorkGroupIDX() { @@ -341,8 +341,8 @@ class SIMachineFunctionInfo final : public AMDGPUMachineFunction { return WorkItemIDZ; } - bool hasPrivateMemoryInputPtr() const { - return PrivateMemoryInputPtr; + bool hasImplicitBufferPtr() const { + return ImplicitBufferPtr; } unsigned getNumUserSGPRs() const { @@ -396,8 +396,8 @@ class SIMachineFunctionInfo final : public AMDGPUMachineFunction { return QueuePtrUserSGPR; } - unsigned getPrivateMemoryPtrUserSGPR() const { - return PrivateMemoryPtrUserSGPR; + unsigned getImplicitBufferPtrUserSGPR() const { + return ImplicitBufferPtrUserSGPR; } bool hasSpilledSGPRs() const { diff --git a/contrib/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp b/contrib/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp index f4ddf1891683..4ac23ef03cb3 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIPeepholeSDWA.cpp @@ -67,9 +67,9 @@ class SIPeepholeSDWA : public MachineFunctionPass { bool runOnMachineFunction(MachineFunction &MF) override; void matchSDWAOperands(MachineFunction &MF); - bool isConvertibleToSDWA(const MachineInstr &MI) const; + bool isConvertibleToSDWA(const MachineInstr &MI, const SISubtarget &ST) const; bool convertToSDWA(MachineInstr &MI, const SDWAOperandsVector &SDWAOperands); - void legalizeScalarOperands(MachineInstr &MI) const; + void legalizeScalarOperands(MachineInstr &MI, const SISubtarget &ST) const; StringRef getPassName() const override { return "SI Peephole SDWA"; } @@ -224,7 +224,7 @@ static bool isSameReg(const MachineOperand &LHS, const MachineOperand &RHS) { static bool isSubregOf(const MachineOperand &SubReg, const MachineOperand &SuperReg, const TargetRegisterInfo *TRI) { - + if (!SuperReg.isReg() || !SubReg.isReg()) return false; @@ -557,7 +557,7 @@ void SIPeepholeSDWA::matchSDWAOperands(MachineFunction &MF) { MachineOperand *Src0 = TII->getNamedOperand(MI, AMDGPU::OpName::src0); MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst); - + if (TRI->isPhysicalRegister(Src0->getReg()) || TRI->isPhysicalRegister(Dst->getReg())) break; @@ -590,7 +590,7 @@ void SIPeepholeSDWA::matchSDWAOperands(MachineFunction &MF) { break; MachineOperand *Dst = TII->getNamedOperand(MI, AMDGPU::OpName::vdst); - + if (TRI->isPhysicalRegister(Src1->getReg()) || TRI->isPhysicalRegister(Dst->getReg())) break; @@ -607,16 +607,38 @@ void SIPeepholeSDWA::matchSDWAOperands(MachineFunction &MF) { } } -bool SIPeepholeSDWA::isConvertibleToSDWA(const MachineInstr &MI) const { +bool SIPeepholeSDWA::isConvertibleToSDWA(const MachineInstr &MI, + const SISubtarget &ST) const { // Check if this instruction has opcode that supports SDWA - unsigned Opc = MI.getOpcode(); - if (AMDGPU::getSDWAOp(Opc) != -1) - return true; - int Opc32 = AMDGPU::getVOPe32(Opc); - if (Opc32 != -1 && AMDGPU::getSDWAOp(Opc32) != -1) - return !TII->hasModifiersSet(MI, AMDGPU::OpName::omod) && - !TII->getNamedOperand(MI, AMDGPU::OpName::sdst); - return false; + int Opc = MI.getOpcode(); + if (AMDGPU::getSDWAOp(Opc) == -1) + Opc = AMDGPU::getVOPe32(Opc); + + if (Opc == -1 || AMDGPU::getSDWAOp(Opc) == -1) + return false; + + if (!ST.hasSDWAOmod() && TII->hasModifiersSet(MI, AMDGPU::OpName::omod)) + return false; + + if (TII->isVOPC(Opc)) { + if (!ST.hasSDWASdst()) { + const MachineOperand *SDst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst); + if (SDst && SDst->getReg() != AMDGPU::VCC) + return false; + } + + if (!ST.hasSDWAClampVOPC() && TII->hasModifiersSet(MI, AMDGPU::OpName::clamp)) + return false; + + } else if (TII->getNamedOperand(MI, AMDGPU::OpName::sdst)) { + return false; + } + + if (!ST.hasSDWAMac() && (Opc == AMDGPU::V_MAC_F16_e32 || + Opc == AMDGPU::V_MAC_F32_e32)) + return false; + + return true; } bool SIPeepholeSDWA::convertToSDWA(MachineInstr &MI, @@ -641,6 +663,11 @@ bool SIPeepholeSDWA::convertToSDWA(MachineInstr &MI, if (Dst) { assert(AMDGPU::getNamedOperandIdx(SDWAOpcode, AMDGPU::OpName::vdst) != -1); SDWAInst.add(*Dst); + } else { + Dst = TII->getNamedOperand(MI, AMDGPU::OpName::sdst); + assert(Dst && + AMDGPU::getNamedOperandIdx(SDWAOpcode, AMDGPU::OpName::sdst) != -1); + SDWAInst.add(*Dst); } // Copy src0, initialize src0_modifiers. All sdwa instructions has src0 and @@ -677,9 +704,23 @@ bool SIPeepholeSDWA::convertToSDWA(MachineInstr &MI, SDWAInst.add(*Src2); } - // Initialize clamp. + // Copy clamp if present, initialize otherwise assert(AMDGPU::getNamedOperandIdx(SDWAOpcode, AMDGPU::OpName::clamp) != -1); - SDWAInst.addImm(0); + MachineOperand *Clamp = TII->getNamedOperand(MI, AMDGPU::OpName::clamp); + if (Clamp) { + SDWAInst.add(*Clamp); + } else { + SDWAInst.addImm(0); + } + + // Copy omod if present, initialize otherwise if needed + MachineOperand *OMod = TII->getNamedOperand(MI, AMDGPU::OpName::omod); + if (OMod) { + assert(AMDGPU::getNamedOperandIdx(SDWAOpcode, AMDGPU::OpName::omod) != -1); + SDWAInst.add(*OMod); + } else if (AMDGPU::getNamedOperandIdx(SDWAOpcode, AMDGPU::OpName::omod) != -1) { + SDWAInst.addImm(0); + } // Initialize dst_sel and dst_unused if present if (Dst) { @@ -733,16 +774,25 @@ bool SIPeepholeSDWA::convertToSDWA(MachineInstr &MI, } // If an instruction was converted to SDWA it should not have immediates or SGPR -// operands. Copy its scalar operands into VGPRs. -void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &MI) const { +// operands (allowed one SGPR on GFX9). Copy its scalar operands into VGPRs. +void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &MI, const SISubtarget &ST) const { const MCInstrDesc &Desc = TII->get(MI.getOpcode()); - for (unsigned I = 0, E = MI.getNumExplicitOperands(); I != E; ++I) { - MachineOperand &Op = MI.getOperand(I); + unsigned ConstantBusCount = 0; + for (MachineOperand &Op: MI.explicit_uses()) { if (!Op.isImm() && !(Op.isReg() && !TRI->isVGPR(*MRI, Op.getReg()))) continue; + + unsigned I = MI.getOperandNo(&Op); if (Desc.OpInfo[I].RegClass == -1 || !TRI->hasVGPRs(TRI->getRegClass(Desc.OpInfo[I].RegClass))) continue; + + if (ST.hasSDWAScalar() && ConstantBusCount == 0 && Op.isReg() && + TRI->isSGPRReg(*MRI, Op.getReg())) { + ++ConstantBusCount; + continue; + } + unsigned VGPR = MRI->createVirtualRegister(&AMDGPU::VGPR_32RegClass); auto Copy = BuildMI(*MI.getParent(), MI.getIterator(), MI.getDebugLoc(), TII->get(AMDGPU::V_MOV_B32_e32), VGPR); @@ -758,22 +808,20 @@ void SIPeepholeSDWA::legalizeScalarOperands(MachineInstr &MI) const { bool SIPeepholeSDWA::runOnMachineFunction(MachineFunction &MF) { const SISubtarget &ST = MF.getSubtarget(); - if (!ST.hasSDWA() || - !AMDGPU::isVI(ST)) { // TODO: Add support for SDWA on gfx9 + if (!ST.hasSDWA()) return false; - } MRI = &MF.getRegInfo(); TRI = ST.getRegisterInfo(); TII = ST.getInstrInfo(); - + // Find all SDWA operands in MF. matchSDWAOperands(MF); for (const auto &OperandPair : SDWAOperands) { const auto &Operand = OperandPair.second; MachineInstr *PotentialMI = Operand->potentialToConvert(TII); - if (PotentialMI && isConvertibleToSDWA(*PotentialMI)) { + if (PotentialMI && isConvertibleToSDWA(*PotentialMI, ST)) { PotentialMatches[PotentialMI].push_back(Operand.get()); } } @@ -788,7 +836,7 @@ bool SIPeepholeSDWA::runOnMachineFunction(MachineFunction &MF) { bool Ret = !ConvertedInstructions.empty(); while (!ConvertedInstructions.empty()) - legalizeScalarOperands(*ConvertedInstructions.pop_back_val()); + legalizeScalarOperands(*ConvertedInstructions.pop_back_val(), ST); return Ret; } diff --git a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp index b611f28fcabd..ef6ad4ad0c8f 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.cpp @@ -1044,18 +1044,29 @@ void SIRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI, unsigned CarryOut = MRI.createVirtualRegister(&AMDGPU::SReg_64_XEXECRegClass); unsigned ScaledReg - = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass); + = MRI.createVirtualRegister(&AMDGPU::VGPR_32RegClass); - // XXX - Should this use a vector shift? - BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_LSHR_B32), ScaledReg) - .addReg(DiffReg, RegState::Kill) - .addImm(Log2_32(ST.getWavefrontSize())); + BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_LSHRREV_B32_e64), ScaledReg) + .addImm(Log2_32(ST.getWavefrontSize())) + .addReg(DiffReg, RegState::Kill); // TODO: Fold if use instruction is another add of a constant. - BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_ADD_I32_e64), ResultReg) - .addReg(CarryOut, RegState::Define | RegState::Dead) - .addImm(Offset) - .addReg(ScaledReg, RegState::Kill); + if (AMDGPU::isInlinableLiteral32(Offset, ST.hasInv2PiInlineImm())) { + BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_ADD_I32_e64), ResultReg) + .addReg(CarryOut, RegState::Define | RegState::Dead) + .addImm(Offset) + .addReg(ScaledReg, RegState::Kill); + } else { + unsigned ConstOffsetReg + = MRI.createVirtualRegister(&AMDGPU::SReg_32_XM0RegClass); + + BuildMI(*MBB, MI, DL, TII->get(AMDGPU::S_MOV_B32), ConstOffsetReg) + .addImm(Offset); + BuildMI(*MBB, MI, DL, TII->get(AMDGPU::V_ADD_I32_e64), ResultReg) + .addReg(CarryOut, RegState::Define | RegState::Dead) + .addReg(ConstOffsetReg, RegState::Kill) + .addReg(ScaledReg, RegState::Kill); + } MRI.setRegAllocationHint(CarryOut, 0, AMDGPU::VCC); } @@ -1341,12 +1352,11 @@ unsigned SIRegisterInfo::getPreloadedValue(const MachineFunction &MF, case SIRegisterInfo::PRIVATE_SEGMENT_WAVE_BYTE_OFFSET: return MFI->PrivateSegmentWaveByteOffsetSystemSGPR; case SIRegisterInfo::PRIVATE_SEGMENT_BUFFER: - if (ST.isAmdCodeObjectV2(MF)) { - assert(MFI->hasPrivateSegmentBuffer()); - return MFI->PrivateSegmentBufferUserSGPR; - } - assert(MFI->hasPrivateMemoryInputPtr()); - return MFI->PrivateMemoryPtrUserSGPR; + assert(MFI->hasPrivateSegmentBuffer()); + return MFI->PrivateSegmentBufferUserSGPR; + case SIRegisterInfo::IMPLICIT_BUFFER_PTR: + assert(MFI->hasImplicitBufferPtr()); + return MFI->ImplicitBufferPtrUserSGPR; case SIRegisterInfo::KERNARG_SEGMENT_PTR: assert(MFI->hasKernargSegmentPtr()); return MFI->KernargSegmentPtrUserSGPR; diff --git a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h index 8fed6d5f9710..600cc886cb59 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h +++ b/contrib/llvm/lib/Target/AMDGPU/SIRegisterInfo.h @@ -197,12 +197,13 @@ class SIRegisterInfo final : public AMDGPURegisterInfo { WORKGROUP_ID_Y = 11, WORKGROUP_ID_Z = 12, PRIVATE_SEGMENT_WAVE_BYTE_OFFSET = 14, + IMPLICIT_BUFFER_PTR = 15, // VGPRS: - FIRST_VGPR_VALUE = 15, + FIRST_VGPR_VALUE = 16, WORKITEM_ID_X = FIRST_VGPR_VALUE, - WORKITEM_ID_Y = 16, - WORKITEM_ID_Z = 17 + WORKITEM_ID_Y = 17, + WORKITEM_ID_Z = 18 }; /// \brief Returns the physical register that \p Value is stored in. diff --git a/contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp b/contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp index c5f121757e62..96a18544f02a 100644 --- a/contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/SIShrinkInstructions.cpp @@ -92,6 +92,8 @@ static bool canShrink(MachineInstr &MI, const SIInstrInfo *TII, case AMDGPU::V_ADDC_U32_e64: case AMDGPU::V_SUBB_U32_e64: + if (TII->getNamedOperand(MI, AMDGPU::OpName::src1)->isImm()) + return false; // Additional verification is needed for sdst/src2. return true; diff --git a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp index f581e69980c7..26515b27bb77 100644 --- a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp +++ b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp @@ -538,6 +538,27 @@ bool isSGPR(unsigned Reg, const MCRegisterInfo* TRI) { Reg == AMDGPU::SCC; } +bool isRegIntersect(unsigned Reg0, unsigned Reg1, const MCRegisterInfo* TRI) { + + if (Reg0 == Reg1) { + return true; + } + + unsigned SubReg0 = TRI->getSubReg(Reg0, 1); + if (SubReg0 == 0) { + return TRI->getSubRegIndex(Reg1, Reg0) > 0; + } + + for (unsigned Idx = 2; SubReg0 > 0; ++Idx) { + if (isRegIntersect(Reg1, SubReg0, TRI)) { + return true; + } + SubReg0 = TRI->getSubReg(Reg0, Idx); + } + + return false; +} + unsigned getMCReg(unsigned Reg, const MCSubtargetInfo &STI) { switch(Reg) { diff --git a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h index eff0230d21f5..936e4921a709 100644 --- a/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h +++ b/contrib/llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h @@ -271,6 +271,9 @@ bool isGFX9(const MCSubtargetInfo &STI); /// \brief Is Reg - scalar register bool isSGPR(unsigned Reg, const MCRegisterInfo* TRI); +/// \brief Is there any intersection between registers +bool isRegIntersect(unsigned Reg0, unsigned Reg1, const MCRegisterInfo* TRI); + /// If \p Reg is a pseudo reg, return the correct hardware register given /// \p STI otherwise return \p Reg. unsigned getMCReg(unsigned Reg, const MCSubtargetInfo &STI); diff --git a/contrib/llvm/lib/Target/AMDGPU/VOP1Instructions.td b/contrib/llvm/lib/Target/AMDGPU/VOP1Instructions.td index 95b5ef0a49db..96b33c373f05 100644 --- a/contrib/llvm/lib/Target/AMDGPU/VOP1Instructions.td +++ b/contrib/llvm/lib/Target/AMDGPU/VOP1Instructions.td @@ -93,11 +93,6 @@ class VOP1_SDWA_Pseudo pattern=[]> : let AsmMatchConverter = "cvtSdwaVOP1"; } -class VOP1_SDWA9_Pseudo pattern=[]> : - VOP_SDWA9_Pseudo { - let AsmMatchConverter = "cvtSdwaVOP1"; -} - class getVOP1Pat64 : LetDummies { list ret = !if(P.HasModifiers, @@ -117,7 +112,6 @@ multiclass VOP1Inst ; def _e64 : VOP3_Pseudo .ret>; def _sdwa : VOP1_SDWA_Pseudo ; - def _sdwa9 : VOP1_SDWA9_Pseudo ; } // Special profile for instructions which have clamp @@ -274,12 +268,10 @@ def VOP_MOVRELD : VOPProfile<[untyped, i32, untyped, untyped]> { let Ins64 = (ins Src0RC64:$vdst, VSrc_b32:$src0); let InsDPP = (ins Src0RC32:$vdst, Src0RC32:$src0, dpp_ctrl:$dpp_ctrl, row_mask:$row_mask, bank_mask:$bank_mask, bound_ctrl:$bound_ctrl); + let InsSDWA = (ins Src0RC32:$vdst, Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0, - clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused, + clampmod:$clamp, omod:$omod, dst_sel:$dst_sel, dst_unused:$dst_unused, src0_sel:$src0_sel); - let InsSDWA9 = (ins Src0RC32:$vdst, Src0ModSDWA9:$src0_modifiers, Src0SDWA9:$src0, - clampmod:$clamp, omod:$omod, dst_sel:$dst_sel, dst_unused:$dst_unused, - src0_sel:$src0_sel); let Asm32 = getAsm32<1, 1>.ret; let Asm64 = getAsm64<1, 1, 0, 1>.ret; @@ -545,8 +537,8 @@ multiclass VOP1_Real_vi op> { VOP1_SDWAe (NAME#"_sdwa").Pfl>; def _sdwa_gfx9 : - VOP_SDWA9_Real (NAME#"_sdwa9")>, - VOP1_SDWA9Ae (NAME#"_sdwa9").Pfl>; + VOP_SDWA9_Real (NAME#"_sdwa")>, + VOP1_SDWA9Ae (NAME#"_sdwa").Pfl>; // For now left dpp only for asm/dasm // TODO: add corresponding pseudo diff --git a/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td b/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td index 657cacaa792c..7b9bc71ad4c7 100644 --- a/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td +++ b/contrib/llvm/lib/Target/AMDGPU/VOP2Instructions.td @@ -114,11 +114,6 @@ class VOP2_SDWA_Pseudo pattern=[]> : let AsmMatchConverter = "cvtSdwaVOP2"; } -class VOP2_SDWA9_Pseudo pattern=[]> : - VOP_SDWA9_Pseudo { - let AsmMatchConverter = "cvtSdwaVOP2"; -} - class getVOP2Pat64 : LetDummies { list ret = !if(P.HasModifiers, [(set P.DstVT:$vdst, @@ -139,7 +134,6 @@ multiclass VOP2Inst ; def _sdwa : VOP2_SDWA_Pseudo ; - def _sdwa9 : VOP2_SDWA9_Pseudo ; } multiclass VOP2bInst { let AsmMatchConverter = "cvtSdwaVOP2b"; } - - def _sdwa9 : VOP2_SDWA9_Pseudo { - let AsmMatchConverter = "cvtSdwaVOP2b"; - } } def _e64 : VOP3_Pseudo .ret>, @@ -221,17 +211,13 @@ class VOP_MAC : VOPProfile <[vt, vt, vt, vt]> { VGPR_32:$src2, // stub argument dpp_ctrl:$dpp_ctrl, row_mask:$row_mask, bank_mask:$bank_mask, bound_ctrl:$bound_ctrl); + let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0, Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1, VGPR_32:$src2, // stub argument - clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused, + clampmod:$clamp, omod:$omod, + dst_sel:$dst_sel, dst_unused:$dst_unused, src0_sel:$src0_sel, src1_sel:$src1_sel); - let InsSDWA9 = (ins Src0ModSDWA9:$src0_modifiers, Src0SDWA9:$src0, - Src1ModSDWA9:$src1_modifiers, Src1SDWA9:$src1, - VGPR_32:$src2, // stub argument - clampmod:$clamp, omod:$omod, - dst_sel:$dst_sel, dst_unused:$dst_unused, - src0_sel:$src0_sel, src1_sel:$src1_sel); let Asm32 = getAsm32<1, 2, vt>.ret; let Asm64 = getAsm64<1, 2, HasModifiers, HasOMod, vt>.ret; let AsmDPP = getAsmDPP<1, 2, HasModifiers, vt>.ret; @@ -289,15 +275,10 @@ def VOP2b_I32_I1_I32_I32_I1 : VOPProfile<[i32, i32, i32, i1]> { let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0, Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1, - clampmod:$clamp, dst_sel:$dst_sel, dst_unused:$dst_unused, + clampmod:$clamp, omod:$omod, + dst_sel:$dst_sel, dst_unused:$dst_unused, src0_sel:$src0_sel, src1_sel:$src1_sel); - let InsSDWA9 = (ins Src0ModSDWA9:$src0_modifiers, Src0SDWA9:$src0, - Src1ModSDWA9:$src1_modifiers, Src1SDWA9:$src1, - clampmod:$clamp, omod:$omod, - dst_sel:$dst_sel, dst_unused:$dst_unused, - src0_sel:$src0_sel, src1_sel:$src1_sel); - let InsDPP = (ins Src0Mod:$src0_modifiers, Src0DPP:$src0, Src1Mod:$src1_modifiers, Src1DPP:$src1, dpp_ctrl:$dpp_ctrl, row_mask:$row_mask, @@ -326,6 +307,8 @@ def VOP_READLANE : VOPProfile<[i32, i32, i32]> { let Ins64 = Ins32; let Asm32 = " $vdst, $src0, $src1"; let Asm64 = Asm32; + let HasExt = 0; + let HasSDWA9 = 0; } def VOP_WRITELANE : VOPProfile<[i32, i32, i32]> { @@ -335,6 +318,8 @@ def VOP_WRITELANE : VOPProfile<[i32, i32, i32]> { let Ins64 = Ins32; let Asm32 = " $vdst, $src0, $src1"; let Asm64 = Asm32; + let HasExt = 0; + let HasSDWA9 = 0; } //===----------------------------------------------------------------------===// @@ -397,20 +382,29 @@ def V_READLANE_B32 : VOP2_Pseudo<"v_readlane_b32", VOP_READLANE, def V_WRITELANE_B32 : VOP2_Pseudo<"v_writelane_b32", VOP_WRITELANE, [], "">; } // End isConvergent = 1 -defm V_BFM_B32 : VOP2Inst <"v_bfm_b32", VOP_I32_I32_I32>; -defm V_BCNT_U32_B32 : VOP2Inst <"v_bcnt_u32_b32", VOP_I32_I32_I32>; -defm V_MBCNT_LO_U32_B32 : VOP2Inst <"v_mbcnt_lo_u32_b32", VOP_I32_I32_I32, int_amdgcn_mbcnt_lo>; -defm V_MBCNT_HI_U32_B32 : VOP2Inst <"v_mbcnt_hi_u32_b32", VOP_I32_I32_I32, int_amdgcn_mbcnt_hi>; -defm V_LDEXP_F32 : VOP2Inst <"v_ldexp_f32", VOP_F32_F32_I32, AMDGPUldexp>; -defm V_CVT_PKACCUM_U8_F32 : VOP2Inst <"v_cvt_pkaccum_u8_f32", VOP_I32_F32_I32>; // TODO: set "Uses = dst" -defm V_CVT_PKNORM_I16_F32 : VOP2Inst <"v_cvt_pknorm_i16_f32", VOP_I32_F32_F32>; -defm V_CVT_PKNORM_U16_F32 : VOP2Inst <"v_cvt_pknorm_u16_f32", VOP_I32_F32_F32>; -defm V_CVT_PKRTZ_F16_F32 : VOP2Inst <"v_cvt_pkrtz_f16_f32", VOP_I32_F32_F32, AMDGPUpkrtz_f16_f32>; -defm V_CVT_PK_U16_U32 : VOP2Inst <"v_cvt_pk_u16_u32", VOP_I32_I32_I32>; -defm V_CVT_PK_I16_I32 : VOP2Inst <"v_cvt_pk_i16_i32", VOP_I32_I32_I32>; +defm V_BFM_B32 : VOP2Inst <"v_bfm_b32", VOP_NO_EXT>; +defm V_BCNT_U32_B32 : VOP2Inst <"v_bcnt_u32_b32", VOP_NO_EXT>; +defm V_MBCNT_LO_U32_B32 : VOP2Inst <"v_mbcnt_lo_u32_b32", VOP_NO_EXT, int_amdgcn_mbcnt_lo>; +defm V_MBCNT_HI_U32_B32 : VOP2Inst <"v_mbcnt_hi_u32_b32", VOP_NO_EXT, int_amdgcn_mbcnt_hi>; +defm V_LDEXP_F32 : VOP2Inst <"v_ldexp_f32", VOP_NO_EXT, AMDGPUldexp>; +defm V_CVT_PKACCUM_U8_F32 : VOP2Inst <"v_cvt_pkaccum_u8_f32", VOP_NO_EXT>; // TODO: set "Uses = dst" +defm V_CVT_PKNORM_I16_F32 : VOP2Inst <"v_cvt_pknorm_i16_f32", VOP_NO_EXT>; +defm V_CVT_PKNORM_U16_F32 : VOP2Inst <"v_cvt_pknorm_u16_f32", VOP_NO_EXT>; +defm V_CVT_PKRTZ_F16_F32 : VOP2Inst <"v_cvt_pkrtz_f16_f32", VOP_NO_EXT, AMDGPUpkrtz_f16_f32>; +defm V_CVT_PK_U16_U32 : VOP2Inst <"v_cvt_pk_u16_u32", VOP_NO_EXT>; +defm V_CVT_PK_I16_I32 : VOP2Inst <"v_cvt_pk_i16_i32", VOP_NO_EXT>; } // End SubtargetPredicate = isGCN +def : Pat< + (AMDGPUadde i32:$src0, i32:$src1, i1:$src2), + (V_ADDC_U32_e64 $src0, $src1, $src2) +>; + +def : Pat< + (AMDGPUsube i32:$src0, i32:$src1, i1:$src2), + (V_SUBB_U32_e64 $src0, $src1, $src2) +>; // These instructions only exist on SI and CI let SubtargetPredicate = isSICI in { @@ -728,8 +722,8 @@ multiclass VOP2_SDWA_Real op> { multiclass VOP2_SDWA9_Real op> { def _sdwa_gfx9 : - VOP_SDWA9_Real (NAME#"_sdwa9")>, - VOP2_SDWA9Ae (NAME#"_sdwa9").Pfl>; + VOP_SDWA9_Real (NAME#"_sdwa")>, + VOP2_SDWA9Ae (NAME#"_sdwa").Pfl>; } multiclass VOP2be_Real_e32e64_vi op> : diff --git a/contrib/llvm/lib/Target/AMDGPU/VOPCInstructions.td b/contrib/llvm/lib/Target/AMDGPU/VOPCInstructions.td index cd347b86d305..f3482a22d5dc 100644 --- a/contrib/llvm/lib/Target/AMDGPU/VOPCInstructions.td +++ b/contrib/llvm/lib/Target/AMDGPU/VOPCInstructions.td @@ -113,11 +113,6 @@ class VOPC_SDWA_Pseudo pattern=[]> : let AsmMatchConverter = "cvtSdwaVOPC"; } -class VOPC_SDWA9_Pseudo pattern=[]> : - VOP_SDWA9_Pseudo { - let AsmMatchConverter = "cvtSdwaVOPC"; -} - // This class is used only with VOPC instructions. Use $sdst for out operand class VOPCInstAlias : InstAlias , PredicateControl { @@ -189,13 +184,6 @@ multiclass VOPC_Pseudos { - let Defs = !if(DefExec, [VCC, EXEC], [VCC]); - let SchedRW = P.Schedule; - let isConvergent = DefExec; - let isCompare = 1; - } } def VOPC_I1_F16_F16 : VOPC_Profile<[Write32Bit], f16>; @@ -540,14 +528,12 @@ class VOPC_Class_Profile sched, ValueType vt> : VOPC_Profile { let Ins64 = (ins Src0Mod:$src0_modifiers, Src0RC64:$src0, Src1RC64:$src1); let Asm64 = "$sdst, $src0_modifiers, $src1"; + let InsSDWA = (ins Src0ModSDWA:$src0_modifiers, Src0SDWA:$src0, Src1ModSDWA:$src1_modifiers, Src1SDWA:$src1, clampmod:$clamp, src0_sel:$src0_sel, src1_sel:$src1_sel); - let InsSDWA9 = (ins Src0ModSDWA9:$src0_modifiers, Src0SDWA9:$src0, - Src1ModSDWA9:$src1_modifiers, Src1SDWA9:$src1, - src0_sel:$src0_sel, src1_sel:$src1_sel); + let AsmSDWA = " vcc, $src0_modifiers, $src1_modifiers$clamp $src0_sel $src1_sel"; - //let AsmSDWA9 = " $sdst, $src0_modifiers, $src1_modifiers $src0_sel $src1_sel"; let HasSrc1Mods = 0; let HasClamp = 0; let HasOMod = 0; @@ -580,12 +566,6 @@ multiclass VOPC_Class_Pseudos { let SchedRW = p.Schedule; let isConvergent = DefExec; } - - def _sdwa9 : VOPC_SDWA9_Pseudo { - let Defs = !if(DefExec, [VCC, EXEC], [VCC]); - let SchedRW = p.Schedule; - let isConvergent = DefExec; - } } def VOPC_I1_F16_I32 : VOPC_Class_Profile<[Write32Bit], f16>; @@ -954,8 +934,8 @@ multiclass VOPC_Real_vi op> { VOPC_SDWAe (NAME#"_sdwa").Pfl>; def _sdwa_gfx9 : - VOP_SDWA9_Real (NAME#"_sdwa9")>, - VOPC_SDWA9e (NAME#"_sdwa9").Pfl>; + VOP_SDWA9_Real (NAME#"_sdwa")>, + VOPC_SDWA9e (NAME#"_sdwa").Pfl>; def : VOPCInstAlias (NAME#"_e64"), !cast(NAME#"_e32_vi")> { diff --git a/contrib/llvm/lib/Target/AMDGPU/VOPInstructions.td b/contrib/llvm/lib/Target/AMDGPU/VOPInstructions.td index 4da654f84f9d..e386f21c2ba4 100644 --- a/contrib/llvm/lib/Target/AMDGPU/VOPInstructions.td +++ b/contrib/llvm/lib/Target/AMDGPU/VOPInstructions.td @@ -232,11 +232,11 @@ class VOP3Pe op, VOPProfile P> : Enc64 { let Inst{9} = !if(P.HasSrc1Mods, src1_modifiers{1}, 0); // neg_hi src1 let Inst{10} = !if(P.HasSrc2Mods, src2_modifiers{1}, 0); // neg_hi src2 - let Inst{11} = !if(P.HasOpSel, src0_modifiers{2}, 0); // op_sel(0) - let Inst{12} = !if(P.HasOpSel, src1_modifiers{2}, 0); // op_sel(1) - let Inst{13} = !if(P.HasOpSel, src2_modifiers{2}, 0); // op_sel(2) + let Inst{11} = !if(!and(P.HasSrc0, P.HasOpSel), src0_modifiers{2}, 0); // op_sel(0) + let Inst{12} = !if(!and(P.HasSrc1, P.HasOpSel), src1_modifiers{2}, 0); // op_sel(1) + let Inst{13} = !if(!and(P.HasSrc2, P.HasOpSel), src2_modifiers{2}, 0); // op_sel(2) - let Inst{14} = !if(P.HasOpSel, src2_modifiers{3}, 0); // op_sel_hi(2) + let Inst{14} = !if(!and(P.HasSrc2, P.HasOpSel), src2_modifiers{3}, 0); // op_sel_hi(2) let Inst{15} = !if(P.HasClamp, clamp{0}, 0); @@ -245,8 +245,8 @@ class VOP3Pe op, VOPProfile P> : Enc64 { let Inst{40-32} = !if(P.HasSrc0, src0, 0); let Inst{49-41} = !if(P.HasSrc1, src1, 0); let Inst{58-50} = !if(P.HasSrc2, src2, 0); - let Inst{59} = !if(P.HasOpSel, src0_modifiers{3}, 0); // op_sel_hi(0) - let Inst{60} = !if(P.HasOpSel, src1_modifiers{3}, 0); // op_sel_hi(1) + let Inst{59} = !if(!and(P.HasSrc0, P.HasOpSel), src0_modifiers{3}, 0); // op_sel_hi(0) + let Inst{60} = !if(!and(P.HasSrc1, P.HasOpSel), src1_modifiers{3}, 0); // op_sel_hi(1) let Inst{61} = !if(P.HasSrc0Mods, src0_modifiers{0}, 0); // neg (lo) let Inst{62} = !if(P.HasSrc1Mods, src1_modifiers{0}, 0); // neg (lo) let Inst{63} = !if(P.HasSrc2Mods, src2_modifiers{0}, 0); // neg (lo) @@ -300,6 +300,19 @@ class VOP_SDWAe : Enc64 { let Inst{61-60} = !if(P.HasSrc1FloatMods, src1_modifiers{1-0}, 0); } +// GFX9 adds two features to SDWA: +// 1. Add 3 fields to the SDWA microcode word: S0, S1 and OMOD. +// a. S0 and S1 indicate that source 0 and 1 respectively are SGPRs rather +// than VGPRs (at most 1 can be an SGPR); +// b. OMOD is the standard output modifier (result *2, *4, /2) +// 2. Add a new version of the SDWA microcode word for VOPC: SDWAB. This +// replaces OMOD and the dest fields with SD and SDST (SGPR destination) +// field. +// a. When SD=1, the SDST is used as the destination for the compare result; +// b. When SD=0, VCC is used. +// +// In GFX9, V_MAC_F16, V_MAC_F32 opcodes cannot be used with SDWA + // gfx9 SDWA basic encoding class VOP_SDWA9e : Enc64 { bits<9> src0; // {src0_sgpr{0}, src0{7-0}} @@ -353,6 +366,7 @@ class VOP_SDWA_Pseudo pattern=[]> : string Mnemonic = opName; string AsmOperands = P.AsmSDWA; + string AsmOperands9 = P.AsmSDWA9; let Size = 8; let mayLoad = 0; @@ -372,53 +386,9 @@ class VOP_SDWA_Pseudo pattern=[]> : VOPProfile Pfl = P; } -// GFX9 adds two features to SDWA: -// 1. Add 3 fields to the SDWA microcode word: S0, S1 and OMOD. -// a. S0 and S1 indicate that source 0 and 1 respectively are SGPRs rather -// than VGPRs (at most 1 can be an SGPR); -// b. OMOD is the standard output modifier (result *2, *4, /2) -// 2. Add a new version of the SDWA microcode word for VOPC: SDWAB. This -// replaces OMOD and the dest fields with SD and SDST (SGPR destination) -// field. -// a. When SD=1, the SDST is used as the destination for the compare result; -// b.when SD=0, VCC is used. -// -// In GFX9, V_MAC_F16, V_MAC_F32 opcodes cannot be used with SDWA - -class VOP_SDWA9_Pseudo pattern=[]> : - InstSI , - VOP , - SIMCInstr , - MnemonicAlias { - - let isPseudo = 1; - let isCodeGenOnly = 1; - let UseNamedOperandTable = 1; - - string Mnemonic = opName; - string AsmOperands = P.AsmSDWA9; - - let Size = 8; - let mayLoad = 0; - let mayStore = 0; - let hasSideEffects = 0; - - let VALU = 1; - let SDWA = 1; - let Uses = [EXEC]; - - let SubtargetPredicate = !if(P.HasSDWA9, HasSDWA9, DisableInst); - let AssemblerPredicate = !if(P.HasSDWA9, HasSDWA9, DisableInst); - let AsmVariantName = !if(P.HasSDWA9, AMDGPUAsmVariants.SDWA9, - AMDGPUAsmVariants.Disable); - let DecoderNamespace = "SDWA9"; - - VOPProfile Pfl = P; -} - class VOP_SDWA_Real : InstSI , - SIMCInstr { + SIMCInstr { let isPseudo = 0; let isCodeGenOnly = 0; @@ -443,9 +413,9 @@ class VOP_SDWA_Real : let TSFlags = ps.TSFlags; } -class VOP_SDWA9_Real : - InstSI , - SIMCInstr { +class VOP_SDWA9_Real : + InstSI , + SIMCInstr { let isPseudo = 0; let isCodeGenOnly = 0; @@ -458,13 +428,15 @@ class VOP_SDWA9_Real : let Constraints = ps.Constraints; let DisableEncoding = ps.DisableEncoding; + let SubtargetPredicate = !if(ps.Pfl.HasSDWA9, HasSDWA9, DisableInst); + let AssemblerPredicate = !if(ps.Pfl.HasSDWA9, HasSDWA9, DisableInst); + let AsmVariantName = !if(ps.Pfl.HasSDWA9, AMDGPUAsmVariants.SDWA9, + AMDGPUAsmVariants.Disable); + let DecoderNamespace = "SDWA9"; + // Copy relevant pseudo op flags - let SubtargetPredicate = ps.SubtargetPredicate; - let AssemblerPredicate = ps.AssemblerPredicate; let AsmMatchConverter = ps.AsmMatchConverter; - let AsmVariantName = ps.AsmVariantName; let UseNamedOperandTable = ps.UseNamedOperandTable; - let DecoderNamespace = ps.DecoderNamespace; let Constraints = ps.Constraints; let DisableEncoding = ps.DisableEncoding; let TSFlags = ps.TSFlags; diff --git a/contrib/llvm/lib/Target/ARM/ARM.td b/contrib/llvm/lib/Target/ARM/ARM.td index ca68f5d42c32..6f67183df6a1 100644 --- a/contrib/llvm/lib/Target/ARM/ARM.td +++ b/contrib/llvm/lib/Target/ARM/ARM.td @@ -100,7 +100,8 @@ def FeatureRAS : SubtargetFeature<"ras", "HasRAS", "true", "Enable Reliability, Availability and Serviceability extensions">; def FeatureFPAO : SubtargetFeature<"fpao", "HasFPAO", "true", "Enable fast computation of positive address offsets">; - +def FeatureFuseAES : SubtargetFeature<"fuse-aes", "HasFuseAES", "true", + "CPU fuses AES crypto operations">; // Cyclone has preferred instructions for zeroing VFP registers, which can // execute in 0 cycles. diff --git a/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp index f9da036c7e46..90f635c81254 100644 --- a/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/contrib/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -1504,6 +1504,9 @@ void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) { return; } case ARM::CONSTPOOL_ENTRY: { + if (Subtarget->genExecuteOnly()) + llvm_unreachable("execute-only should not generate constant pools"); + /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool /// in the function. The first operand is the ID# for this instruction, the /// second is the index into the MachineConstantPool that this is, the third diff --git a/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp index 8715657ad5e2..e0810c358f2d 100644 --- a/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/contrib/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -665,12 +665,14 @@ bool ARMBaseInstrInfo::isPredicable(const MachineInstr &MI) const { const ARMFunctionInfo *AFI = MI.getParent()->getParent()->getInfo(); + // Neon instructions in Thumb2 IT blocks are deprecated, see ARMARM. + // In their ARM encoding, they can't be encoded in a conditional form. + if ((MI.getDesc().TSFlags & ARMII::DomainMask) == ARMII::DomainNEON) + return false; + if (AFI->isThumb2Function()) { if (getSubtarget().restrictIT()) return isV8EligibleForIT(&MI); - } else { // non-Thumb - if ((MI.getDesc().TSFlags & ARMII::DomainMask) == ARMII::DomainNEON) - return false; } return true; diff --git a/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp b/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp index 5b2d093e8f0d..2bcc707e9fc3 100644 --- a/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/contrib/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2669,12 +2669,35 @@ static SDValue LowerWRITE_REGISTER(SDValue Op, SelectionDAG &DAG) { // Select(N) returns N. So the raw TargetGlobalAddress nodes, etc. can only // be used to form addressing mode. These wrapped nodes will be selected // into MOVi. -static SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) { +SDValue ARMTargetLowering::LowerConstantPool(SDValue Op, + SelectionDAG &DAG) const { EVT PtrVT = Op.getValueType(); // FIXME there is no actual debug info here SDLoc dl(Op); ConstantPoolSDNode *CP = cast(Op); SDValue Res; + + // When generating execute-only code Constant Pools must be promoted to the + // global data section. It's a bit ugly that we can't share them across basic + // blocks, but this way we guarantee that execute-only behaves correct with + // position-independent addressing modes. + if (Subtarget->genExecuteOnly()) { + auto AFI = DAG.getMachineFunction().getInfo(); + auto T = const_cast(CP->getType()); + auto C = const_cast(CP->getConstVal()); + auto M = const_cast(DAG.getMachineFunction(). + getFunction()->getParent()); + auto GV = new GlobalVariable( + *M, T, /*isConst=*/true, GlobalVariable::InternalLinkage, C, + Twine(DAG.getDataLayout().getPrivateGlobalPrefix()) + "CP" + + Twine(DAG.getMachineFunction().getFunctionNumber()) + "_" + + Twine(AFI->createPICLabelUId()) + ); + SDValue GA = DAG.getTargetGlobalAddress(dyn_cast(GV), + dl, PtrVT); + return LowerGlobalAddress(GA, DAG); + } + if (CP->isMachineConstantPoolEntry()) Res = DAG.getTargetConstantPool(CP->getMachineCPVal(), PtrVT, CP->getAlignment()); @@ -3118,6 +3141,19 @@ static bool isReadOnly(const GlobalValue *GV) { isa(GV); } +SDValue ARMTargetLowering::LowerGlobalAddress(SDValue Op, + SelectionDAG &DAG) const { + switch (Subtarget->getTargetTriple().getObjectFormat()) { + default: llvm_unreachable("unknown object format"); + case Triple::COFF: + return LowerGlobalAddressWindows(Op, DAG); + case Triple::ELF: + return LowerGlobalAddressELF(Op, DAG); + case Triple::MachO: + return LowerGlobalAddressDarwin(Op, DAG); + } +} + SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op, SelectionDAG &DAG) const { EVT PtrVT = getPointerTy(DAG.getDataLayout()); @@ -7634,21 +7670,9 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { default: llvm_unreachable("Don't know how to custom lower this!"); case ISD::WRITE_REGISTER: return LowerWRITE_REGISTER(Op, DAG); - case ISD::ConstantPool: - if (Subtarget->genExecuteOnly()) - llvm_unreachable("execute-only should not generate constant pools"); - return LowerConstantPool(Op, DAG); + case ISD::ConstantPool: return LowerConstantPool(Op, DAG); case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); - case ISD::GlobalAddress: - switch (Subtarget->getTargetTriple().getObjectFormat()) { - default: llvm_unreachable("unknown object format"); - case Triple::COFF: - return LowerGlobalAddressWindows(Op, DAG); - case Triple::ELF: - return LowerGlobalAddressELF(Op, DAG); - case Triple::MachO: - return LowerGlobalAddressDarwin(Op, DAG); - } + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); case ISD::SELECT: return LowerSELECT(Op, DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); diff --git a/contrib/llvm/lib/Target/ARM/ARMISelLowering.h b/contrib/llvm/lib/Target/ARM/ARMISelLowering.h index 26da528c19e6..5044134f5b1e 100644 --- a/contrib/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/contrib/llvm/lib/Target/ARM/ARMISelLowering.h @@ -601,6 +601,8 @@ class InstrItineraryData; SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *Subtarget) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddressDarwin(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddressELF(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalAddressWindows(SDValue Op, SelectionDAG &DAG) const; diff --git a/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td b/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td index 45471a4e95b3..53db5acbe805 100644 --- a/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td +++ b/contrib/llvm/lib/Target/ARM/ARMInstrThumb2.td @@ -4756,6 +4756,16 @@ def t2MOVsr: t2AsmPseudo<"mov${p} $Rd, $shift", def t2MOVSsr: t2AsmPseudo<"movs${p} $Rd, $shift", (ins rGPR:$Rd, so_reg_reg:$shift, pred:$p)>; +// Aliases for the above with the .w qualifier +def : t2InstAlias<"mov${p}.w $Rd, $shift", + (t2MOVsi rGPR:$Rd, t2_so_reg:$shift, pred:$p)>; +def : t2InstAlias<"movs${p}.w $Rd, $shift", + (t2MOVSsi rGPR:$Rd, t2_so_reg:$shift, pred:$p)>; +def : t2InstAlias<"mov${p}.w $Rd, $shift", + (t2MOVsr rGPR:$Rd, so_reg_reg:$shift, pred:$p)>; +def : t2InstAlias<"movs${p}.w $Rd, $shift", + (t2MOVSsr rGPR:$Rd, so_reg_reg:$shift, pred:$p)>; + // ADR w/o the .w suffix def : t2InstAlias<"adr${p} $Rd, $addr", (t2ADR rGPR:$Rd, t2adrlabel:$addr, pred:$p)>; diff --git a/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.cpp b/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.cpp index 2ae3bad4076b..4cb0eca5ee5f 100644 --- a/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.cpp +++ b/contrib/llvm/lib/Target/ARM/ARMInstructionSelector.cpp @@ -42,6 +42,10 @@ class ARMInstructionSelector : public InstructionSelector { private: bool selectImpl(MachineInstr &I) const; + bool selectICmp(MachineInstrBuilder &MIB, const ARMBaseInstrInfo &TII, + MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) const; + const ARMBaseInstrInfo &TII; const ARMBaseRegisterInfo &TRI; const ARMBaseTargetMachine &TM; @@ -243,6 +247,105 @@ static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned RegBank, return Opc; } +static ARMCC::CondCodes getComparePred(CmpInst::Predicate Pred) { + switch (Pred) { + // Needs two compares... + case CmpInst::FCMP_ONE: + case CmpInst::FCMP_UEQ: + default: + // AL is our "false" for now. The other two need more compares. + return ARMCC::AL; + case CmpInst::ICMP_EQ: + case CmpInst::FCMP_OEQ: + return ARMCC::EQ; + case CmpInst::ICMP_SGT: + case CmpInst::FCMP_OGT: + return ARMCC::GT; + case CmpInst::ICMP_SGE: + case CmpInst::FCMP_OGE: + return ARMCC::GE; + case CmpInst::ICMP_UGT: + case CmpInst::FCMP_UGT: + return ARMCC::HI; + case CmpInst::FCMP_OLT: + return ARMCC::MI; + case CmpInst::ICMP_ULE: + case CmpInst::FCMP_OLE: + return ARMCC::LS; + case CmpInst::FCMP_ORD: + return ARMCC::VC; + case CmpInst::FCMP_UNO: + return ARMCC::VS; + case CmpInst::FCMP_UGE: + return ARMCC::PL; + case CmpInst::ICMP_SLT: + case CmpInst::FCMP_ULT: + return ARMCC::LT; + case CmpInst::ICMP_SLE: + case CmpInst::FCMP_ULE: + return ARMCC::LE; + case CmpInst::FCMP_UNE: + case CmpInst::ICMP_NE: + return ARMCC::NE; + case CmpInst::ICMP_UGE: + return ARMCC::HS; + case CmpInst::ICMP_ULT: + return ARMCC::LO; + } +} + +bool ARMInstructionSelector::selectICmp(MachineInstrBuilder &MIB, + const ARMBaseInstrInfo &TII, + MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI, + const RegisterBankInfo &RBI) const { + auto &MBB = *MIB->getParent(); + auto InsertBefore = std::next(MIB->getIterator()); + auto &DebugLoc = MIB->getDebugLoc(); + + // Move 0 into the result register. + auto Mov0I = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::MOVi)) + .addDef(MRI.createVirtualRegister(&ARM::GPRRegClass)) + .addImm(0) + .add(predOps(ARMCC::AL)) + .add(condCodeOp()); + if (!constrainSelectedInstRegOperands(*Mov0I, TII, TRI, RBI)) + return false; + + // Perform the comparison. + auto LHSReg = MIB->getOperand(2).getReg(); + auto RHSReg = MIB->getOperand(3).getReg(); + assert(MRI.getType(LHSReg) == MRI.getType(RHSReg) && + MRI.getType(LHSReg).getSizeInBits() == 32 && + MRI.getType(RHSReg).getSizeInBits() == 32 && + "Unsupported types for comparison operation"); + auto CmpI = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::CMPrr)) + .addUse(LHSReg) + .addUse(RHSReg) + .add(predOps(ARMCC::AL)); + if (!constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI)) + return false; + + // Move 1 into the result register if the flags say so. + auto ResReg = MIB->getOperand(0).getReg(); + auto Cond = + static_cast(MIB->getOperand(1).getPredicate()); + auto ARMCond = getComparePred(Cond); + if (ARMCond == ARMCC::AL) + return false; + + auto Mov1I = BuildMI(MBB, InsertBefore, DebugLoc, TII.get(ARM::MOVCCi)) + .addDef(ResReg) + .addUse(Mov0I->getOperand(0).getReg()) + .addImm(1) + .add(predOps(ARMCond, ARM::CPSR)); + if (!constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI)) + return false; + + MIB->eraseFromParent(); + return true; +} + bool ARMInstructionSelector::select(MachineInstr &I) const { assert(I.getParent() && "Instruction should be in a basic block!"); assert(I.getParent()->getParent() && "Instruction should be in a function!"); @@ -343,6 +446,8 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { I.setDesc(TII.get(COPY)); return selectCopy(I, TII, MRI, TRI, RBI); } + case G_ICMP: + return selectICmp(MIB, TII, MRI, TRI, RBI); case G_GEP: I.setDesc(TII.get(ARM::ADDrr)); MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); diff --git a/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp index a706079d9866..5873c7fb3872 100644 --- a/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp +++ b/contrib/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp @@ -86,6 +86,12 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) { setAction({G_CONSTANT, s32}, Legal); + setAction({G_ICMP, s1}, Legal); + for (auto Ty : {s8, s16}) + setAction({G_ICMP, 1, Ty}, WidenScalar); + for (auto Ty : {s32, p0}) + setAction({G_ICMP, 1, Ty}, Legal); + if (!ST.useSoftFloat() && ST.hasVFP2()) { setAction({G_FADD, s32}, Legal); setAction({G_FADD, s64}, Legal); diff --git a/contrib/llvm/lib/Target/ARM/ARMMacroFusion.cpp b/contrib/llvm/lib/Target/ARM/ARMMacroFusion.cpp new file mode 100644 index 000000000000..1b6e97c28d45 --- /dev/null +++ b/contrib/llvm/lib/Target/ARM/ARMMacroFusion.cpp @@ -0,0 +1,57 @@ +//===- ARMMacroFusion.cpp - ARM Macro Fusion ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file contains the ARM implementation of the DAG scheduling +/// mutation to pair instructions back to back. +// +//===----------------------------------------------------------------------===// + +#include "ARMMacroFusion.h" +#include "ARMSubtarget.h" +#include "llvm/CodeGen/MacroFusion.h" +#include "llvm/Target/TargetInstrInfo.h" + +namespace llvm { + +/// \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. +static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, + const TargetSubtargetInfo &TSI, + const MachineInstr *FirstMI, + const MachineInstr &SecondMI) { + const ARMSubtarget &ST = static_cast(TSI); + + // Assume wildcards for unspecified instrs. + unsigned FirstOpcode = + FirstMI ? FirstMI->getOpcode() + : static_cast(ARM::INSTRUCTION_LIST_END); + unsigned SecondOpcode = SecondMI.getOpcode(); + + if (ST.hasFuseAES()) + // Fuse AES crypto operations. + switch(SecondOpcode) { + // AES encode. + case ARM::AESMC : + return FirstOpcode == ARM::AESE || + FirstOpcode == ARM::INSTRUCTION_LIST_END; + // AES decode. + case ARM::AESIMC: + return FirstOpcode == ARM::AESD || + FirstOpcode == ARM::INSTRUCTION_LIST_END; + } + + return false; +} + +std::unique_ptr createARMMacroFusionDAGMutation () { + return createMacroFusionDAGMutation(shouldScheduleAdjacent); +} + +} // end namespace llvm diff --git a/contrib/llvm/lib/Target/ARM/ARMMacroFusion.h b/contrib/llvm/lib/Target/ARM/ARMMacroFusion.h new file mode 100644 index 000000000000..1e4fc6687eae --- /dev/null +++ b/contrib/llvm/lib/Target/ARM/ARMMacroFusion.h @@ -0,0 +1,24 @@ +//===- ARMMacroFusion.h - ARM Macro Fusion ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file contains the ARM definition of the DAG scheduling mutation +/// to pair instructions back to back. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineScheduler.h" + +namespace llvm { + +/// Note that you have to add: +/// DAG.addMutation(createARMMacroFusionDAGMutation()); +/// to ARMPassConfig::createMachineScheduler() to have an effect. +std::unique_ptr createARMMacroFusionDAGMutation(); + +} // llvm diff --git a/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp b/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp index f59b075e6dd9..2350d0c6ef69 100644 --- a/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp +++ b/contrib/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp @@ -255,6 +255,16 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { OperandsMapping = getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr}); break; + case G_ICMP: { + LLT Ty2 = MRI.getType(MI.getOperand(2).getReg()); + (void)Ty2; + assert(Ty2.getSizeInBits() == 32 && "Unsupported size for G_ICMP"); + OperandsMapping = + getOperandsMapping({&ARM::ValueMappings[ARM::GPR3OpsIdx], nullptr, + &ARM::ValueMappings[ARM::GPR3OpsIdx], + &ARM::ValueMappings[ARM::GPR3OpsIdx]}); + break; + } case G_MERGE_VALUES: { // We only support G_MERGE_VALUES for creating a double precision floating // point value out of two GPRs. diff --git a/contrib/llvm/lib/Target/ARM/ARMSubtarget.h b/contrib/llvm/lib/Target/ARM/ARMSubtarget.h index af682dd8321c..d890d0fa777e 100644 --- a/contrib/llvm/lib/Target/ARM/ARMSubtarget.h +++ b/contrib/llvm/lib/Target/ARM/ARMSubtarget.h @@ -285,6 +285,10 @@ class ARMSubtarget : public ARMGenSubtargetInfo { /// HasFPAO - if true, processor does positive address offset computation faster bool HasFPAO = false; + /// HasFuseAES - if true, processor executes back to back AES instruction + /// pairs faster. + bool HasFuseAES = false; + /// If true, if conversion may decide to leave some instructions unpredicated. bool IsProfitableToUnpredicate = false; @@ -561,6 +565,10 @@ class ARMSubtarget : public ARMGenSubtargetInfo { bool hasD16() const { return HasD16; } bool hasFullFP16() const { return HasFullFP16; } + bool hasFuseAES() const { return HasFuseAES; } + /// \brief Return true if the CPU supports any kind of instruction fusion. + bool hasFusion() const { return hasFuseAES(); } + const Triple &getTargetTriple() const { return TargetTriple; } bool isTargetDarwin() const { return TargetTriple.isOSDarwin(); } diff --git a/contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp index c0506cfda612..eb71e557ec91 100644 --- a/contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp +++ b/contrib/llvm/lib/Target/ARM/ARMTargetMachine.cpp @@ -17,6 +17,7 @@ #include "ARMRegisterBankInfo.h" #endif #include "ARMSubtarget.h" +#include "ARMMacroFusion.h" #include "ARMTargetMachine.h" #include "ARMTargetObjectFile.h" #include "ARMTargetTransformInfo.h" @@ -394,6 +395,9 @@ class ARMPassConfig : public TargetPassConfig { createMachineScheduler(MachineSchedContext *C) const override { ScheduleDAGMILive *DAG = createGenericSchedLive(C); // add DAG Mutations here. + const ARMSubtarget &ST = C->MF->getSubtarget(); + if (ST.hasFusion()) + DAG->addMutation(createARMMacroFusionDAGMutation()); return DAG; } @@ -401,6 +405,9 @@ class ARMPassConfig : public TargetPassConfig { createPostMachineScheduler(MachineSchedContext *C) const override { ScheduleDAGMI *DAG = createGenericSchedPostRA(C); // add DAG Mutations here. + const ARMSubtarget &ST = C->MF->getSubtarget(); + if (ST.hasFusion()) + DAG->addMutation(createARMMacroFusionDAGMutation()); return DAG; } diff --git a/contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 19fba3033bb2..891b5c60e1fd 100644 --- a/contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/contrib/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -6860,6 +6860,17 @@ static unsigned getRealVLDOpcode(unsigned Opc, unsigned &Spacing) { bool ARMAsmParser::processInstruction(MCInst &Inst, const OperandVector &Operands, MCStreamer &Out) { + // Check if we have the wide qualifier, because if it's present we + // must avoid selecting a 16-bit thumb instruction. + bool HasWideQualifier = false; + for (auto &Op : Operands) { + ARMOperand &ARMOp = static_cast(*Op); + if (ARMOp.isToken() && ARMOp.getToken() == ".w") { + HasWideQualifier = true; + break; + } + } + switch (Inst.getOpcode()) { // Alias for alternate form of 'ldr{,b}t Rt, [Rn], #imm' instruction. case ARM::LDRT_POST: @@ -6939,8 +6950,7 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, // Select the narrow version if the immediate will fit. if (Inst.getOperand(1).getImm() > 0 && Inst.getOperand(1).getImm() <= 0xff && - !(static_cast(*Operands[2]).isToken() && - static_cast(*Operands[2]).getToken() == ".w")) + !HasWideQualifier) Inst.setOpcode(ARM::tLDRpci); else Inst.setOpcode(ARM::t2LDRpci); @@ -6971,10 +6981,9 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, else if (Inst.getOpcode() == ARM::t2LDRConstPool) TmpInst.setOpcode(ARM::t2LDRpci); const ARMOperand &PoolOperand = - (static_cast(*Operands[2]).isToken() && - static_cast(*Operands[2]).getToken() == ".w") ? - static_cast(*Operands[4]) : - static_cast(*Operands[3]); + (HasWideQualifier ? + static_cast(*Operands[4]) : + static_cast(*Operands[3])); const MCExpr *SubExprVal = PoolOperand.getConstantPoolImm(); // If SubExprVal is a constant we may be able to use a MOV if (isa(SubExprVal) && @@ -8117,8 +8126,7 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, if (isARMLowRegister(Inst.getOperand(0).getReg()) && isARMLowRegister(Inst.getOperand(1).getReg()) && Inst.getOperand(5).getReg() == (inITBlock() ? 0 : ARM::CPSR) && - !(static_cast(*Operands[3]).isToken() && - static_cast(*Operands[3]).getToken() == ".w")) { + !HasWideQualifier) { unsigned NewOpc; switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected opcode"); @@ -8152,7 +8160,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, isARMLowRegister(Inst.getOperand(1).getReg()) && isARMLowRegister(Inst.getOperand(2).getReg()) && Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg() && - inITBlock() == (Inst.getOpcode() == ARM::t2MOVsr)) + inITBlock() == (Inst.getOpcode() == ARM::t2MOVsr) && + !HasWideQualifier) isNarrow = true; MCInst TmpInst; unsigned newOpc; @@ -8186,7 +8195,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, bool isNarrow = false; if (isARMLowRegister(Inst.getOperand(0).getReg()) && isARMLowRegister(Inst.getOperand(1).getReg()) && - inITBlock() == (Inst.getOpcode() == ARM::t2MOVsi)) + inITBlock() == (Inst.getOpcode() == ARM::t2MOVsi) && + !HasWideQualifier) isNarrow = true; MCInst TmpInst; unsigned newOpc; @@ -8415,10 +8425,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, !isARMLowRegister(Inst.getOperand(0).getReg()) || (Inst.getOperand(2).isImm() && (unsigned)Inst.getOperand(2).getImm() > 255) || - ((!inITBlock() && Inst.getOperand(5).getReg() != ARM::CPSR) || - (inITBlock() && Inst.getOperand(5).getReg() != 0)) || - (static_cast(*Operands[3]).isToken() && - static_cast(*Operands[3]).getToken() == ".w")) + Inst.getOperand(5).getReg() != (inITBlock() ? 0 : ARM::CPSR) || + HasWideQualifier) break; MCInst TmpInst; TmpInst.setOpcode(Inst.getOpcode() == ARM::t2ADDri ? @@ -8447,8 +8455,7 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, } if (!Transform || Inst.getOperand(5).getReg() != 0 || - (static_cast(*Operands[3]).isToken() && - static_cast(*Operands[3]).getToken() == ".w")) + HasWideQualifier) break; MCInst TmpInst; TmpInst.setOpcode(ARM::tADDhirr); @@ -8568,11 +8575,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, if (isARMLowRegister(Inst.getOperand(0).getReg()) && (Inst.getOperand(1).isImm() && (unsigned)Inst.getOperand(1).getImm() <= 255) && - ((!inITBlock() && Inst.getOperand(2).getImm() == ARMCC::AL && - Inst.getOperand(4).getReg() == ARM::CPSR) || - (inITBlock() && Inst.getOperand(4).getReg() == 0)) && - (!static_cast(*Operands[2]).isToken() || - static_cast(*Operands[2]).getToken() != ".w")) { + Inst.getOperand(4).getReg() == (inITBlock() ? 0 : ARM::CPSR) && + !HasWideQualifier) { // The operands aren't in the same order for tMOVi8... MCInst TmpInst; TmpInst.setOpcode(ARM::tMOVi8); @@ -8593,8 +8597,7 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, isARMLowRegister(Inst.getOperand(1).getReg()) && Inst.getOperand(2).getImm() == ARMCC::AL && Inst.getOperand(4).getReg() == ARM::CPSR && - (!static_cast(*Operands[2]).isToken() || - static_cast(*Operands[2]).getToken() != ".w")) { + !HasWideQualifier) { // The operands aren't the same for tMOV[S]r... (no cc_out) MCInst TmpInst; TmpInst.setOpcode(Inst.getOperand(4).getReg() ? ARM::tMOVSr : ARM::tMOVr); @@ -8616,8 +8619,7 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, if (isARMLowRegister(Inst.getOperand(0).getReg()) && isARMLowRegister(Inst.getOperand(1).getReg()) && Inst.getOperand(2).getImm() == 0 && - (!static_cast(*Operands[2]).isToken() || - static_cast(*Operands[2]).getToken() != ".w")) { + !HasWideQualifier) { unsigned NewOpc; switch (Inst.getOpcode()) { default: llvm_unreachable("Illegal opcode!"); @@ -8716,11 +8718,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, if ((isARMLowRegister(Inst.getOperand(1).getReg()) && isARMLowRegister(Inst.getOperand(2).getReg())) && Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg() && - ((!inITBlock() && Inst.getOperand(5).getReg() == ARM::CPSR) || - (inITBlock() && Inst.getOperand(5).getReg() != ARM::CPSR)) && - (!static_cast(*Operands[3]).isToken() || - !static_cast(*Operands[3]).getToken().equals_lower( - ".w"))) { + Inst.getOperand(5).getReg() == (inITBlock() ? 0 : ARM::CPSR) && + !HasWideQualifier) { unsigned NewOpc; switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected opcode"); @@ -8756,11 +8755,8 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, isARMLowRegister(Inst.getOperand(2).getReg())) && (Inst.getOperand(0).getReg() == Inst.getOperand(1).getReg() || Inst.getOperand(0).getReg() == Inst.getOperand(2).getReg()) && - ((!inITBlock() && Inst.getOperand(5).getReg() == ARM::CPSR) || - (inITBlock() && Inst.getOperand(5).getReg() != ARM::CPSR)) && - (!static_cast(*Operands[3]).isToken() || - !static_cast(*Operands[3]).getToken().equals_lower( - ".w"))) { + Inst.getOperand(5).getReg() == (inITBlock() ? 0 : ARM::CPSR) && + !HasWideQualifier) { unsigned NewOpc; switch (Inst.getOpcode()) { default: llvm_unreachable("unexpected opcode"); diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp index 716492ea2566..81760f03940a 100644 --- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -358,11 +358,27 @@ static uint32_t joinHalfWords(uint32_t FirstHalf, uint32_t SecondHalf, return Value; } -unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value, +unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm, + const MCFixup &Fixup, + const MCValue &Target, uint64_t Value, bool IsPCRel, MCContext &Ctx, bool IsLittleEndian, bool IsResolved) const { unsigned Kind = Fixup.getKind(); + + // MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT + // and .word relocations they put the Thumb bit into the addend if possible. + // Other relocation types don't want this bit though (branches couldn't encode + // it if it *was* present, and no other relocations exist) and it can + // interfere with checking valid expressions. + if (const MCSymbolRefExpr *A = Target.getSymA()) { + if (A->hasSubsectionsViaSymbols() && Asm.isThumbFunc(&A->getSymbol()) && + (Kind == FK_Data_4 || Kind == ARM::fixup_arm_movw_lo16 || + Kind == ARM::fixup_arm_movt_hi16 || Kind == ARM::fixup_t2_movw_lo16 || + Kind == ARM::fixup_t2_movt_hi16)) + Value |= 1; + } + switch (Kind) { default: Ctx.reportError(Fixup.getLoc(), "bad relocation fixup type"); @@ -505,6 +521,13 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value, return swapHalfWords(out, IsLittleEndian); } case ARM::fixup_arm_thumb_bl: { + // FIXME: We get both thumb1 and thumb2 in here, so we can only check for + // the less strict thumb2 value. + if (!isInt<26>(Value - 4)) { + Ctx.reportError(Fixup.getLoc(), "Relocation out of range"); + return 0; + } + // The value doesn't encode the low bit (always zero) and is offset by // four. The 32-bit immediate value is encoded as // imm32 = SignExtend(S:I1:I2:imm10:imm11:0) @@ -716,29 +739,11 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCFixup &Fixup, uint64_t Value, } void ARMAsmBackend::processFixupValue(const MCAssembler &Asm, - const MCAsmLayout &Layout, const MCFixup &Fixup, - const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) { + const MCValue &Target, bool &IsResolved) { const MCSymbolRefExpr *A = Target.getSymA(); const MCSymbol *Sym = A ? &A->getSymbol() : nullptr; const unsigned FixupKind = Fixup.getKind() ; - // MachO (the only user of "Value") tries to make .o files that look vaguely - // pre-linked, so for MOVW/MOVT and .word relocations they put the Thumb bit - // into the addend if possible. Other relocation types don't want this bit - // though (branches couldn't encode it if it *was* present, and no other - // relocations exist) and it can interfere with checking valid expressions. - if (FixupKind == FK_Data_4 || - FixupKind == ARM::fixup_arm_movw_lo16 || - FixupKind == ARM::fixup_arm_movt_hi16 || - FixupKind == ARM::fixup_t2_movw_lo16 || - FixupKind == ARM::fixup_t2_movt_hi16) { - if (Sym) { - if (Asm.isThumbFunc(Sym)) - Value |= 1; - } - } if (IsResolved && (unsigned)Fixup.getKind() == ARM::fixup_arm_thumb_bl) { assert(Sym && "How did we resolve this?"); @@ -747,7 +752,7 @@ void ARMAsmBackend::processFixupValue(const MCAssembler &Asm, // If the symbol is out of range, produce a relocation and hope the // linker can handle it. GNU AS produces an error in this case. - if (Sym->isExternal() || Value >= 0x400004) + if (Sym->isExternal()) IsResolved = false; } // Create relocations for unconditional branches to function symbols with @@ -759,6 +764,7 @@ void ARMAsmBackend::processFixupValue(const MCAssembler &Asm, IsResolved = false; if (!Asm.isThumbFunc(Sym) && (FixupKind == ARM::fixup_arm_thumb_br || FixupKind == ARM::fixup_arm_thumb_bl || + FixupKind == ARM::fixup_t2_condbranch || FixupKind == ARM::fixup_t2_uncondbranch)) IsResolved = false; } @@ -875,22 +881,25 @@ static unsigned getFixupKindContainerSizeBytes(unsigned Kind) { } } -void ARMAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, bool IsPCRel, - MCContext &Ctx) const { +void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsPCRel) const { unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); - Value = adjustFixupValue(Fixup, Value, IsPCRel, Ctx, IsLittleEndian, true); + MCContext &Ctx = Asm.getContext(); + Value = adjustFixupValue(Asm, Fixup, Target, Value, IsPCRel, Ctx, + IsLittleEndian, true); if (!Value) return; // Doesn't change encoding. unsigned Offset = Fixup.getOffset(); - assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); // Used to point to big endian bytes. unsigned FullSizeBytes; if (!IsLittleEndian) { FullSizeBytes = getFixupKindContainerSizeBytes(Fixup.getKind()); - assert((Offset + FullSizeBytes) <= DataSize && "Invalid fixup size!"); + assert((Offset + FullSizeBytes) <= Data.size() && "Invalid fixup size!"); assert(NumBytes <= FullSizeBytes && "Invalid fixup size!"); } diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h index 2ddedb5d6105..6a0ba2ed41c1 100644 --- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h +++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h @@ -40,17 +40,17 @@ class ARMAsmBackend : public MCAsmBackend { /// processFixupValue - Target hook to process the literal value of a fixup /// if necessary. - void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFixup &Fixup, const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) override; + void processFixupValue(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, bool &IsResolved) override; - unsigned adjustFixupValue(const MCFixup &Fixup, uint64_t Value, bool IsPCRel, + unsigned adjustFixupValue(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, uint64_t Value, bool IsPCRel, MCContext &Ctx, bool IsLittleEndian, bool IsResolved) const; - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; unsigned getRelaxedOpcode(unsigned Op) const; diff --git a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp index 00505a103e00..f74fb2e20b5a 100644 --- a/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp +++ b/contrib/llvm/lib/Target/ARM/MCTargetDesc/ARMWinCOFFObjectWriter.cpp @@ -33,8 +33,8 @@ class ARMWinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter { ~ARMWinCOFFObjectWriter() override = default; - unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, - bool IsCrossSection, + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsCrossSection, const MCAsmBackend &MAB) const override; bool recordRelocation(const MCFixup &) const override; @@ -42,7 +42,8 @@ class ARMWinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter { } // end anonymous namespace -unsigned ARMWinCOFFObjectWriter::getRelocType(const MCValue &Target, +unsigned ARMWinCOFFObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, const MCFixup &Fixup, bool IsCrossSection, const MCAsmBackend &MAB) const { diff --git a/contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp b/contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp index 7d5fb6ca17b9..c6ddd6bdad5e 100644 --- a/contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp +++ b/contrib/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp @@ -214,7 +214,12 @@ void BPFDAGToDAGISel::PreprocessISelDAG() { if (Opcode != ISD::LOAD) continue; - unsigned char new_val[8]; // hold up the constant values replacing loads. + union { + uint8_t c[8]; + uint16_t s; + uint32_t i; + uint64_t d; + } new_val; // hold up the constant values replacing loads. bool to_replace = false; SDLoc DL(Node); const LoadSDNode *LD = cast(Node); @@ -242,7 +247,7 @@ void BPFDAGToDAGISel::PreprocessISelDAG() { const ConstantSDNode *CDN = dyn_cast(OP2.getNode()); if (GADN && CDN) to_replace = - getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val); + getConstantFieldValue(GADN, CDN->getZExtValue(), size, new_val.c); } else if (LDAddrNode->getOpcode() > ISD::BUILTIN_OP_END && LDAddrNode->getNumOperands() > 0) { DEBUG(dbgs() << "Check candidate load: "; LD->dump(); dbgs() << '\n'); @@ -250,7 +255,7 @@ void BPFDAGToDAGISel::PreprocessISelDAG() { SDValue OP1 = LDAddrNode->getOperand(0); if (const GlobalAddressSDNode *GADN = dyn_cast(OP1.getNode())) - to_replace = getConstantFieldValue(GADN, 0, size, new_val); + to_replace = getConstantFieldValue(GADN, 0, size, new_val.c); } if (!to_replace) @@ -259,13 +264,13 @@ void BPFDAGToDAGISel::PreprocessISelDAG() { // replacing the old with a new value uint64_t val; if (size == 1) - val = *(uint8_t *)new_val; + val = new_val.c[0]; else if (size == 2) - val = *(uint16_t *)new_val; + val = new_val.s; else if (size == 4) - val = *(uint32_t *)new_val; + val = new_val.i; else { - val = *(uint64_t *)new_val; + val = new_val.d; } DEBUG(dbgs() << "Replacing load of size " << size << " with constant " @@ -318,14 +323,17 @@ bool BPFDAGToDAGISel::getConstantFieldValue(const GlobalAddressSDNode *Node, } // test whether host endianness matches target - uint8_t test_buf[2]; + union { + uint8_t c[2]; + uint16_t s; + } test_buf; uint16_t test_val = 0x2345; if (DL.isLittleEndian()) - support::endian::write16le(test_buf, test_val); + support::endian::write16le(test_buf.c, test_val); else - support::endian::write16be(test_buf, test_val); + support::endian::write16be(test_buf.c, test_val); - bool endian_match = *(uint16_t *)test_buf == test_val; + bool endian_match = test_buf.s == test_val; for (uint64_t i = Offset, j = 0; i < Offset + Size; i++, j++) ByteSeq[j] = endian_match ? TmpVal[i] : TmpVal[Offset + Size - 1 - j]; diff --git a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp index 80357a63a4e1..15e89fb2a261 100644 --- a/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp +++ b/contrib/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp @@ -27,8 +27,9 @@ class BPFAsmBackend : public MCAsmBackend { : MCAsmBackend(), IsLittleEndian(IsLittleEndian) {} ~BPFAsmBackend() override = default; - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; @@ -61,9 +62,10 @@ bool BPFAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { return true; } -void BPFAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, bool IsPCRel, - MCContext &Ctx) const { +void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsPCRel) const { if (Fixup.getKind() == FK_SecRel_4 || Fixup.getKind() == FK_SecRel_8) { assert(Value == 0); } else if (Fixup.getKind() == FK_Data_4 || Fixup.getKind() == FK_Data_8) { diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp index 9f8c9ded8127..734f3c6658d9 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp +++ b/contrib/llvm/lib/Target/Hexagon/HexagonExpandCondsets.cpp @@ -567,8 +567,19 @@ unsigned HexagonExpandCondsets::getCondTfrOpcode(const MachineOperand &SO, } llvm_unreachable("Invalid register operand"); } - if (SO.isImm() || SO.isFPImm()) - return IfTrue ? C2_cmoveit : C2_cmoveif; + switch (SO.getType()) { + case MachineOperand::MO_Immediate: + case MachineOperand::MO_FPImmediate: + case MachineOperand::MO_ConstantPoolIndex: + case MachineOperand::MO_TargetIndex: + case MachineOperand::MO_JumpTableIndex: + case MachineOperand::MO_ExternalSymbol: + case MachineOperand::MO_GlobalAddress: + case MachineOperand::MO_BlockAddress: + return IfTrue ? C2_cmoveit : C2_cmoveif; + default: + break; + } llvm_unreachable("Unexpected source operand"); } diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp index 18e49c69b8e3..2b0ceaa66258 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp +++ b/contrib/llvm/lib/Target/Hexagon/HexagonFrameLowering.cpp @@ -1051,10 +1051,26 @@ int HexagonFrameLowering::getFrameIndexReference(const MachineFunction &MF, bool HasExtraAlign = HRI.needsStackRealignment(MF); bool NoOpt = MF.getTarget().getOptLevel() == CodeGenOpt::None; + unsigned FrameSize = MFI.getStackSize(); unsigned SP = HRI.getStackRegister(), FP = HRI.getFrameRegister(); auto &HMFI = *MF.getInfo(); unsigned AP = HMFI.getStackAlignBasePhysReg(); - unsigned FrameSize = MFI.getStackSize(); + // It may happen that AP will be absent even HasAlloca && HasExtraAlign + // is true. HasExtraAlign may be set because of vector spills, without + // aligned locals or aligned outgoing function arguments. Since vector + // spills will ultimately be "unaligned", it is safe to use FP as the + // base register. + // In fact, in such a scenario the stack is actually not required to be + // aligned, although it may end up being aligned anyway, since this + // particular case is not easily detectable. The alignment will be + // unnecessary, but not incorrect. + // Unfortunately there is no quick way to verify that the above is + // indeed the case (and that it's not a result of an error), so just + // assume that missing AP will be replaced by FP. + // (A better fix would be to rematerialize AP from FP and always align + // vector spills.) + if (AP == 0) + AP = FP; bool UseFP = false, UseAP = false; // Default: use SP (except at -O0). // Use FP at -O0, except when there are objects with extra alignment. @@ -2454,9 +2470,44 @@ bool HexagonFrameLowering::mayOverflowFrameOffset(MachineFunction &MF) const { unsigned StackSize = MF.getFrameInfo().estimateStackSize(MF); auto &HST = MF.getSubtarget(); // A fairly simplistic guess as to whether a potential load/store to a - // stack location could require an extra register. It does not account - // for store-immediate instructions. - if (HST.useHVXOps()) - return StackSize > 256; + // stack location could require an extra register. + if (HST.useHVXOps() && StackSize > 256) + return true; + + // Check if the function has store-immediate instructions that access + // the stack. Since the offset field is not extendable, if the stack + // size exceeds the offset limit (6 bits, shifted), the stores will + // require a new base register. + bool HasImmStack = false; + unsigned MinLS = ~0u; // Log_2 of the memory access size. + + for (const MachineBasicBlock &B : MF) { + for (const MachineInstr &MI : B) { + unsigned LS = 0; + switch (MI.getOpcode()) { + case Hexagon::S4_storeirit_io: + case Hexagon::S4_storeirif_io: + case Hexagon::S4_storeiri_io: + ++LS; + LLVM_FALLTHROUGH; + case Hexagon::S4_storeirht_io: + case Hexagon::S4_storeirhf_io: + case Hexagon::S4_storeirh_io: + ++LS; + LLVM_FALLTHROUGH; + case Hexagon::S4_storeirbt_io: + case Hexagon::S4_storeirbf_io: + case Hexagon::S4_storeirb_io: + if (MI.getOperand(0).isFI()) + HasImmStack = true; + MinLS = std::min(MinLS, LS); + break; + } + } + } + + if (HasImmStack) + return !isUInt<6>(StackSize >> MinLS); + return false; } diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp index 11ac5454f604..5abbcbba72dd 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp +++ b/contrib/llvm/lib/Target/Hexagon/HexagonGenMux.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/LivePhysRegs.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -295,15 +296,12 @@ bool HexagonGenMux::genMuxInBlock(MachineBasicBlock &B) { unsigned SR1 = Src1->isReg() ? Src1->getReg() : 0; unsigned SR2 = Src2->isReg() ? Src2->getReg() : 0; bool Failure = false, CanUp = true, CanDown = true; - bool Used1 = false, Used2 = false; for (unsigned X = MinX+1; X < MaxX; X++) { const DefUseInfo &DU = DUM.lookup(X); if (DU.Defs[PR] || DU.Defs[DR] || DU.Uses[DR]) { Failure = true; break; } - Used1 |= DU.Uses[SR1]; - Used2 |= DU.Uses[SR2]; if (CanDown && DU.Defs[SR1]) CanDown = false; if (CanUp && DU.Defs[SR2]) @@ -317,64 +315,52 @@ bool HexagonGenMux::genMuxInBlock(MachineBasicBlock &B) { // Prefer "down", since this will move the MUX farther away from the // predicate definition. MachineBasicBlock::iterator At = CanDown ? Def2 : Def1; - if (CanDown) { - // If the MUX is placed "down", we need to make sure that there aren't - // any kills of the source registers between the two defs. - if (Used1 || Used2) { - auto ResetKill = [this] (unsigned Reg, MachineInstr &MI) -> bool { - if (MachineOperand *Op = MI.findRegisterUseOperand(Reg, true, HRI)) { - Op->setIsKill(false); - return true; - } - return false; - }; - bool KilledSR1 = false, KilledSR2 = false; - for (MachineInstr &MJ : make_range(std::next(It1), It2)) { - if (SR1) - KilledSR1 |= ResetKill(SR1, MJ); - if (SR2) - KilledSR2 |= ResetKill(SR1, MJ); - } - // If any of the source registers were killed in this range, transfer - // the kills to the source operands: they will me "moved" to the - // resulting MUX and their parent instructions will be deleted. - if (KilledSR1) { - assert(Src1->isReg()); - Src1->setIsKill(true); - } - if (KilledSR2) { - assert(Src2->isReg()); - Src2->setIsKill(true); - } - } - } else { - // If the MUX is placed "up", it shouldn't kill any source registers - // that are still used afterwards. We can reset the kill flags directly - // on the operands, because the source instructions will be erased. - if (Used1 && Src1->isReg()) - Src1->setIsKill(false); - if (Used2 && Src2->isReg()) - Src2->setIsKill(false); - } ML.push_back(MuxInfo(At, DR, PR, SrcT, SrcF, Def1, Def2)); } - for (unsigned I = 0, N = ML.size(); I < N; ++I) { - MuxInfo &MX = ML[I]; - MachineBasicBlock &B = *MX.At->getParent(); - DebugLoc DL = MX.At->getDebugLoc(); + for (MuxInfo &MX : ML) { unsigned MxOpc = getMuxOpcode(*MX.SrcT, *MX.SrcF); if (!MxOpc) continue; - BuildMI(B, MX.At, DL, HII->get(MxOpc), MX.DefR) - .addReg(MX.PredR) - .add(*MX.SrcT) - .add(*MX.SrcF); + MachineBasicBlock &B = *MX.At->getParent(); + const DebugLoc &DL = B.findDebugLoc(MX.At); + auto NewMux = BuildMI(B, MX.At, DL, HII->get(MxOpc), MX.DefR) + .addReg(MX.PredR) + .add(*MX.SrcT) + .add(*MX.SrcF); + NewMux->clearKillInfo(); B.erase(MX.Def1); B.erase(MX.Def2); Changed = true; } + // Fix up kill flags. + + LivePhysRegs LPR(*HRI); + LPR.addLiveOuts(B); + auto IsLive = [&LPR,this] (unsigned Reg) -> bool { + for (MCSubRegIterator S(Reg, HRI, true); S.isValid(); ++S) + if (LPR.contains(*S)) + return true; + return false; + }; + for (auto I = B.rbegin(), E = B.rend(); I != E; ++I) { + if (I->isDebugValue()) + continue; + // This isn't 100% accurate, but it's safe. + // It won't detect (as a kill) a case like this + // r0 = add r0, 1 <-- r0 should be "killed" + // ... = r0 + for (MachineOperand &Op : I->operands()) { + if (!Op.isReg() || !Op.isUse()) + continue; + assert(Op.getSubReg() == 0 && "Should have physical registers only"); + bool Live = IsLive(Op.getReg()); + Op.setIsKill(!Live); + } + LPR.stepBackward(*I); + } + return Changed; } diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp index f43101fa456d..fec2dc5ce306 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp +++ b/contrib/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp @@ -94,10 +94,6 @@ static cl::opt UseDFAHazardRec("dfa-hazard-rec", /// /// Constants for Hexagon instructions. /// -const int Hexagon_MEMV_OFFSET_MAX_128B = 896; // #s4: -8*128...7*128 -const int Hexagon_MEMV_OFFSET_MIN_128B = -1024; // #s4 -const int Hexagon_MEMV_OFFSET_MAX = 448; // #s4: -8*64...7*64 -const int Hexagon_MEMV_OFFSET_MIN = -512; // #s4 const int Hexagon_MEMW_OFFSET_MAX = 4095; const int Hexagon_MEMW_OFFSET_MIN = -4096; const int Hexagon_MEMD_OFFSET_MAX = 8191; @@ -2443,8 +2439,7 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset, case Hexagon::V6_vS32b_ai: case Hexagon::V6_vL32Ub_ai: case Hexagon::V6_vS32Ub_ai: - return (Offset >= Hexagon_MEMV_OFFSET_MIN) && - (Offset <= Hexagon_MEMV_OFFSET_MAX); + return isShiftedInt<4,6>(Offset); case Hexagon::PS_vstorerq_ai_128B: case Hexagon::PS_vstorerw_ai_128B: @@ -2454,8 +2449,7 @@ bool HexagonInstrInfo::isValidOffset(unsigned Opcode, int Offset, case Hexagon::V6_vS32b_ai_128B: case Hexagon::V6_vL32Ub_ai_128B: case Hexagon::V6_vS32Ub_ai_128B: - return (Offset >= Hexagon_MEMV_OFFSET_MIN_128B) && - (Offset <= Hexagon_MEMV_OFFSET_MAX_128B); + return isShiftedInt<4,7>(Offset); case Hexagon::J2_loop0i: case Hexagon::J2_loop1i: diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp index d73fc7c73185..de6b203015d8 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp +++ b/contrib/llvm/lib/Target/Hexagon/HexagonNewValueJump.cpp @@ -629,7 +629,7 @@ bool HexagonNewValueJump::runOnMachineFunction(MachineFunction &MF) { if (MO.isReg() && MO.isUse()) { unsigned feederReg = MO.getReg(); for (MachineBasicBlock::iterator localII = feederPos, - end = jmpPos; localII != end; localII++) { + end = cmpInstr->getIterator(); localII != end; localII++) { MachineInstr &localMI = *localII; for (unsigned j = 0; j < localMI.getNumOperands(); j++) { MachineOperand &localMO = localMI.getOperand(j); diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp index ee3209354688..7d961a238ae2 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp +++ b/contrib/llvm/lib/Target/Hexagon/HexagonPeephole.cpp @@ -100,9 +100,6 @@ namespace { void getAnalysisUsage(AnalysisUsage &AU) const override { MachineFunctionPass::getAnalysisUsage(AU); } - - private: - void ChangeOpInto(MachineOperand &Dst, MachineOperand &Src); }; } @@ -132,7 +129,9 @@ bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) { PeepholeDoubleRegsMap.clear(); // Traverse the basic block. - for (MachineInstr &MI : *MBB) { + for (auto I = MBB->begin(), E = MBB->end(), NextI = I; I != E; I = NextI) { + NextI = std::next(I); + MachineInstr &MI = *I; // Look for sign extends: // %vreg170 = SXTW %vreg166 if (!DisableOptSZExt && MI.getOpcode() == Hexagon::A2_sxtw) { @@ -280,14 +279,13 @@ bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) { if (NewOp) { unsigned PSrc = MI.getOperand(PR).getReg(); if (unsigned POrig = PeepholeMap.lookup(PSrc)) { - MI.getOperand(PR).setReg(POrig); + BuildMI(*MBB, MI.getIterator(), MI.getDebugLoc(), + QII->get(NewOp), MI.getOperand(0).getReg()) + .addReg(POrig) + .add(MI.getOperand(S2)) + .add(MI.getOperand(S1)); MRI->clearKillFlags(POrig); - MI.setDesc(QII->get(NewOp)); - // Swap operands S1 and S2. - MachineOperand Op1 = MI.getOperand(S1); - MachineOperand Op2 = MI.getOperand(S2); - ChangeOpInto(MI.getOperand(S1), Op2); - ChangeOpInto(MI.getOperand(S2), Op1); + MI.eraseFromParent(); } } // if (NewOp) } // if (!Done) @@ -299,40 +297,6 @@ bool HexagonPeephole::runOnMachineFunction(MachineFunction &MF) { return true; } -void HexagonPeephole::ChangeOpInto(MachineOperand &Dst, MachineOperand &Src) { - assert (&Dst != &Src && "Cannot duplicate into itself"); - switch (Dst.getType()) { - case MachineOperand::MO_Register: - if (Src.isReg()) { - Dst.setReg(Src.getReg()); - Dst.setSubReg(Src.getSubReg()); - MRI->clearKillFlags(Src.getReg()); - } else if (Src.isImm()) { - Dst.ChangeToImmediate(Src.getImm()); - } else { - llvm_unreachable("Unexpected src operand type"); - } - break; - - case MachineOperand::MO_Immediate: - if (Src.isImm()) { - Dst.setImm(Src.getImm()); - } else if (Src.isReg()) { - Dst.ChangeToRegister(Src.getReg(), Src.isDef(), Src.isImplicit(), - false, Src.isDead(), Src.isUndef(), - Src.isDebug()); - Dst.setSubReg(Src.getSubReg()); - } else { - llvm_unreachable("Unexpected src operand type"); - } - break; - - default: - llvm_unreachable("Unexpected dst operand type"); - break; - } -} - FunctionPass *llvm::createHexagonPeephole() { return new HexagonPeephole(); } diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp index 8851a23ae8ac..0aada8a53c97 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp +++ b/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.cpp @@ -1,4 +1,4 @@ -//===-- HexagonSubtarget.cpp - Hexagon Subtarget Information --------------===// +//===- HexagonSubtarget.cpp - Hexagon Subtarget Information ---------------===// // // The LLVM Compiler Infrastructure // @@ -11,13 +11,23 @@ // //===----------------------------------------------------------------------===// -#include "HexagonSubtarget.h" #include "Hexagon.h" +#include "HexagonInstrInfo.h" #include "HexagonRegisterInfo.h" +#include "HexagonSubtarget.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "MCTargetDesc/HexagonMCTargetDesc.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/ScheduleDAG.h" #include "llvm/CodeGen/ScheduleDAGInstrs.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" +#include +#include #include using namespace llvm; @@ -119,9 +129,7 @@ HexagonSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { HexagonSubtarget::HexagonSubtarget(const Triple &TT, StringRef CPU, StringRef FS, const TargetMachine &TM) : HexagonGenSubtargetInfo(TT, CPU, FS), CPUString(CPU), - InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), - FrameLowering() { - + InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this) { initializeEnvironment(); // Initialize scheduling itinerary for the specified CPU. @@ -196,7 +204,6 @@ void HexagonSubtarget::adjustSchedDependency(SUnit *Src, SUnit *Dst, updateLatency(*SrcInst, *DstInst, Dep); } - void HexagonSubtarget::HexagonDAGMutation::apply(ScheduleDAGInstrs *DAG) { for (auto &SU : DAG->SUnits) { if (!SU.isInstr()) @@ -240,18 +247,18 @@ void HexagonSubtarget::HexagonDAGMutation::apply(ScheduleDAGInstrs *DAG) { } } - void HexagonSubtarget::getPostRAMutations( - std::vector> &Mutations) const { - Mutations.push_back(make_unique()); + std::vector> &Mutations) const { + Mutations.push_back( + llvm::make_unique()); } void HexagonSubtarget::getSMSMutations( - std::vector> &Mutations) const { - Mutations.push_back(make_unique()); + std::vector> &Mutations) const { + Mutations.push_back( + llvm::make_unique()); } - // Pin the vtable to this file. void HexagonSubtarget::anchor() {} @@ -447,4 +454,3 @@ unsigned HexagonSubtarget::getL1PrefetchDistance() const { bool HexagonSubtarget::enableSubRegLiveness() const { return EnableSubregLiveness; } - diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h b/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h index 4379efa79c9c..753dca000065 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h +++ b/contrib/llvm/lib/Target/Hexagon/HexagonSubtarget.h @@ -1,4 +1,4 @@ -//===-- HexagonSubtarget.h - Define Subtarget for the Hexagon ---*- C++ -*-===// +//===- HexagonSubtarget.h - Define Subtarget for the Hexagon ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,12 +15,17 @@ #define LLVM_LIB_TARGET_HEXAGON_HEXAGONSUBTARGET_H #include "HexagonFrameLowering.h" -#include "HexagonISelLowering.h" #include "HexagonInstrInfo.h" +#include "HexagonISelLowering.h" #include "HexagonSelectionDAGInfo.h" -#include "llvm/Target/TargetMachine.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/ScheduleDAGMutation.h" +#include "llvm/MC/MCInstrItineraries.h" #include "llvm/Target/TargetSubtargetInfo.h" +#include #include +#include #define GET_SUBTARGETINFO_HEADER #include "HexagonGenSubtargetInfo.inc" @@ -30,6 +35,12 @@ namespace llvm { +class MachineInstr; +class SDep; +class SUnit; +class TargetMachine; +class Triple; + class HexagonSubtarget : public HexagonGenSubtargetInfo { virtual void anchor(); @@ -57,6 +68,7 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { HexagonSelectionDAGInfo TSInfo; HexagonFrameLowering FrameLowering; InstrItineraryData InstrItins; + void initializeEnvironment(); public: @@ -108,6 +120,7 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { bool useBSBScheduling() const { return UseBSBScheduling; } bool enableMachineScheduler() const override; + // Always use the TargetLowering default scheduler. // FIXME: This will use the vliw scheduler which is probably just hurting // compiler time and will be removed eventually anyway. @@ -124,6 +137,7 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { unsigned getSmallDataThreshold() const { return Hexagon_SMALL_DATA_THRESHOLD; } + const HexagonArchEnum &getHexagonArchVersion() const { return HexagonArchVersion; } @@ -155,4 +169,4 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { } // end namespace llvm -#endif +#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONSUBTARGET_H diff --git a/contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp b/contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp index e507a797871f..031a1bdefafb 100644 --- a/contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp +++ b/contrib/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp @@ -291,7 +291,6 @@ bool HexagonPassConfig::addInstSelector() { if (EnableBitSimplify) addPass(createHexagonBitSimplify()); addPass(createHexagonPeephole()); - printAndVerify("After hexagon peephole pass"); // Constant propagation. if (!DisableHCP) { addPass(createHexagonConstPropagationPass()); diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp index 545c8b6b2acd..093ce80bc2e3 100644 --- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp +++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp @@ -202,10 +202,8 @@ class HexagonAsmBackend : public MCAsmBackend { /// processFixupValue - Target hook to adjust the literal value of a fixup /// if necessary. IsResolved signals whether the caller believes a relocation /// is needed; the target can modify the value. The default does nothing. - void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFixup &Fixup, const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) override { + void processFixupValue(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, bool &IsResolved) override { MCFixupKind Kind = Fixup.getKind(); switch((unsigned)Kind) { @@ -415,9 +413,9 @@ class HexagonAsmBackend : public MCAsmBackend { /// ApplyFixup - Apply the \arg Value for given \arg Fixup into the provided /// data fragment, at the offset specified by the fixup and following the /// fixup kind as appropriate. - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t FixupValue, bool IsPCRel, - MCContext &Ctx) const override { + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t FixupValue, bool IsPCRel) const override { // When FixupValue is 0 the relocation is external and there // is nothing for us to do. @@ -432,8 +430,8 @@ class HexagonAsmBackend : public MCAsmBackend { // to a real offset before we can use it. uint32_t Offset = Fixup.getOffset(); unsigned NumBytes = getFixupKindNumBytes(Kind); - assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); - char *InstAddr = Data + Offset; + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); + char *InstAddr = Data.data() + Offset; Value = adjustFixupValue(Kind, FixupValue); if(!Value) @@ -517,7 +515,7 @@ class HexagonAsmBackend : public MCAsmBackend { dbgs() << "\tBValue=0x"; dbgs().write_hex(Value) << ": AValue=0x"; dbgs().write_hex(FixupValue) << ": Offset=" << Offset << - ": Size=" << DataSize << + ": Size=" << Data.size() << ": OInst=0x"; dbgs().write_hex(OldData) << ": Reloc=0x"; dbgs().write_hex(Reloc);); diff --git a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp index e8f154a1fa53..c7114c7f18a0 100644 --- a/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp +++ b/contrib/llvm/lib/Target/Hexagon/MCTargetDesc/HexagonMCDuplexInfo.cpp @@ -701,33 +701,32 @@ MCInst HexagonMCInstrInfo::deriveSubInst(MCInst const &Inst) { break; case Hexagon::A2_addi: Absolute = Inst.getOperand(2).getExpr()->evaluateAsAbsolute(Value); - assert(Absolute);(void)Absolute; - if (Value == 1) { - Result.setOpcode(Hexagon::SA1_inc); - addOps(Result, Inst, 0); - addOps(Result, Inst, 1); - break; - } // 1,2 SUBInst $Rd = add($Rs, #1) - else if (Value == -1) { - Result.setOpcode(Hexagon::SA1_dec); - addOps(Result, Inst, 0); - addOps(Result, Inst, 1); - addOps(Result, Inst, 2); - break; - } // 1,2 SUBInst $Rd = add($Rs,#-1) - else if (Inst.getOperand(1).getReg() == Hexagon::R29) { - Result.setOpcode(Hexagon::SA1_addsp); - addOps(Result, Inst, 0); - addOps(Result, Inst, 2); - break; - } // 1,3 SUBInst $Rd = add(r29, #$u6_2) - else { - Result.setOpcode(Hexagon::SA1_addi); - addOps(Result, Inst, 0); - addOps(Result, Inst, 1); - addOps(Result, Inst, 2); - break; - } // 1,2,3 SUBInst $Rx = add($Rx, #$s7) + if (Absolute) { + if (Value == 1) { + Result.setOpcode(Hexagon::SA1_inc); + addOps(Result, Inst, 0); + addOps(Result, Inst, 1); + break; + } // 1,2 SUBInst $Rd = add($Rs, #1) + if (Value == -1) { + Result.setOpcode(Hexagon::SA1_dec); + addOps(Result, Inst, 0); + addOps(Result, Inst, 1); + addOps(Result, Inst, 2); + break; + } // 1,2 SUBInst $Rd = add($Rs,#-1) + if (Inst.getOperand(1).getReg() == Hexagon::R29) { + Result.setOpcode(Hexagon::SA1_addsp); + addOps(Result, Inst, 0); + addOps(Result, Inst, 2); + break; + } // 1,3 SUBInst $Rd = add(r29, #$u6_2) + } + Result.setOpcode(Hexagon::SA1_addi); + addOps(Result, Inst, 0); + addOps(Result, Inst, 1); + addOps(Result, Inst, 2); + break; // 1,2,3 SUBInst $Rx = add($Rx, #$s7) case Hexagon::A2_add: Result.setOpcode(Hexagon::SA1_addrx); addOps(Result, Inst, 0); diff --git a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp index 0ef1401ef531..c212726113ab 100644 --- a/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp +++ b/contrib/llvm/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp @@ -49,8 +49,9 @@ class LanaiAsmBackend : public MCAsmBackend { LanaiAsmBackend(const Target &T, Triple::OSType OST) : MCAsmBackend(), OSType(OST) {} - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; @@ -88,9 +89,10 @@ bool LanaiAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { return true; } -void LanaiAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned /*DataSize*/, uint64_t Value, - bool /*IsPCRel*/, MCContext & /*Ctx*/) const { +void LanaiAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool /*IsPCRel*/) const { MCFixupKind Kind = Fixup.getKind(); Value = adjustFixupValue(static_cast(Kind), Value); diff --git a/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp b/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp index d8fdc8ba674e..982c6fea62d4 100644 --- a/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp +++ b/contrib/llvm/lib/Target/MSP430/MSP430TargetMachine.cpp @@ -32,16 +32,20 @@ static Reloc::Model getEffectiveRelocModel(Optional RM) { return *RM; } +static std::string computeDataLayout(const Triple &TT, StringRef CPU, + const TargetOptions &Options) { + return "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"; +} + MSP430TargetMachine::MSP430TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, Optional RM, CodeModel::Model CM, CodeGenOpt::Level OL) - : LLVMTargetMachine(T, "e-m:e-p:16:16-i32:16:32-a:16-n8:16", TT, CPU, FS, + : LLVMTargetMachine(T, computeDataLayout(TT, CPU, Options), TT, CPU, FS, Options, getEffectiveRelocModel(RM), CM, OL), TLOF(make_unique()), - // FIXME: Check DataLayout string. Subtarget(TT, CPU, FS, *this) { initAsmInfo(); } diff --git a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 694c201cbe8d..9d5c179a0fd9 100644 --- a/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/contrib/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -322,6 +322,7 @@ class MipsAsmParser : public MCTargetAsmParser { bool parseDirectiveSet(); bool parseDirectiveOption(); bool parseInsnDirective(); + bool parseRSectionDirective(StringRef Section); bool parseSSectionDirective(StringRef Section, unsigned Type); bool parseSetAtDirective(); @@ -5106,7 +5107,7 @@ int MipsAsmParser::matchCPURegisterName(StringRef Name) { CC = StringSwitch(Name) .Case("zero", 0) - .Case("at", 1) + .Cases("at", "AT", 1) .Case("a0", 4) .Case("a1", 5) .Case("a2", 6) @@ -6952,6 +6953,23 @@ bool MipsAsmParser::parseInsnDirective() { return false; } +/// parseRSectionDirective +/// ::= .rdata +bool MipsAsmParser::parseRSectionDirective(StringRef Section) { + // If this is not the end of the statement, report an error. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + reportParseError("unexpected token, expected end of statement"); + return false; + } + + MCSection *ELFSection = getContext().getELFSection( + Section, ELF::SHT_PROGBITS, ELF::SHF_ALLOC); + getParser().getStreamer().SwitchSection(ELFSection); + + getParser().Lex(); // Eat EndOfStatement token. + return false; +} + /// parseSSectionDirective /// ::= .sbss /// ::= .sdata @@ -7499,6 +7517,10 @@ bool MipsAsmParser::ParseDirective(AsmToken DirectiveID) { parseInsnDirective(); return false; } + if (IDVal == ".rdata") { + parseRSectionDirective(".rodata"); + return false; + } if (IDVal == ".sbss") { parseSSectionDirective(IDVal, ELF::SHT_NOBITS); return false; diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp index 6d3d4db03603..ae48d6e38fa0 100644 --- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -235,10 +235,12 @@ static unsigned calculateMMLEIndex(unsigned i) { /// ApplyFixup - Apply the \p Value for given \p Fixup into the provided /// data fragment, at the offset specified by the fixup and following the /// fixup kind as appropriate. -void MipsAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, bool IsPCRel, - MCContext &Ctx) const { +void MipsAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsPCRel) const { MCFixupKind Kind = Fixup.getKind(); + MCContext &Ctx = Asm.getContext(); Value = adjustFixupValue(Fixup, Value, Ctx); if (!Value) diff --git a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h index 4b3cc6e21f4c..bf3b290b7ed5 100644 --- a/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ b/contrib/llvm/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -38,8 +38,9 @@ class MipsAsmBackend : public MCAsmBackend { MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; Optional getFixupKind(StringRef Name) const override; const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; diff --git a/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td index 3272319ad50f..7daea163b8a6 100644 --- a/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td +++ b/contrib/llvm/lib/Target/Mips/Mips32r6InstrInfo.td @@ -326,9 +326,9 @@ class AUIPC_DESC : ALUIPC_DESC_BASE<"auipc", GPR32Opnd, II_AUIPC>; class AUI_DESC_BASE : MipsR6Arch { - dag OutOperandList = (outs GPROpnd:$rs); - dag InOperandList = (ins GPROpnd:$rt, uimm16:$imm); - string AsmString = !strconcat(instr_asm, "\t$rs, $rt, $imm"); + dag OutOperandList = (outs GPROpnd:$rt); + dag InOperandList = (ins GPROpnd:$rs, uimm16:$imm); + string AsmString = !strconcat(instr_asm, "\t$rt, $rs, $imm"); list Pattern = []; InstrItinClass Itinerary = itin; } diff --git a/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp index 68708dc4f50f..02102d6b22f4 100644 --- a/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp +++ b/contrib/llvm/lib/Target/Mips/MipsISelLowering.cpp @@ -907,6 +907,11 @@ static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, if (!(CN1 = dyn_cast(N->getOperand(1)))) return SDValue(); } + // Don't generate INS if constant OR operand doesn't fit into bits + // cleared by constant AND operand. + if (CN->getSExtValue() & CN1->getSExtValue()) + return SDValue(); + SDLoc DL(N); EVT ValTy = N->getOperand(0)->getValueType(0); SDValue Const1; diff --git a/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp b/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp index 272595af5f6f..b95f1158fa56 100644 --- a/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp +++ b/contrib/llvm/lib/Target/Mips/MipsLongBranch.cpp @@ -274,8 +274,8 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { if (IsPIC) { MachineBasicBlock *BalTgtMBB = MF->CreateMachineBasicBlock(BB); MF->insert(FallThroughMBB, BalTgtMBB); - LongBrMBB->addSuccessor(BalTgtMBB, BranchProbability::getOne()); - BalTgtMBB->addSuccessor(&*FallThroughMBB, BranchProbability::getOne()); + LongBrMBB->addSuccessor(BalTgtMBB); + BalTgtMBB->addSuccessor(TgtMBB); // We must select between the MIPS32r6/MIPS64r6 BAL (which is a normal // instruction) and the pre-MIPS32r6/MIPS64r6 definition (which is an @@ -342,8 +342,8 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { .addReg(Mips::SP).addImm(8); if (Subtarget.hasMips32r6()) - BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JALR), Mips::ZERO) - .addReg(Mips::AT); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JALR)) + .addReg(Mips::ZERO).addReg(Mips::AT); else BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JR)).addReg(Mips::AT); @@ -415,8 +415,8 @@ void MipsLongBranch::expandToLongBranch(MBBInfo &I) { .addReg(Mips::SP_64).addImm(0); if (Subtarget.hasMips64r6()) - BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JALR64), Mips::ZERO_64) - .addReg(Mips::AT_64); + BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JALR64)) + .addReg(Mips::ZERO_64).addReg(Mips::AT_64); else BuildMI(*BalTgtMBB, Pos, DL, TII->get(Mips::JR64)).addReg(Mips::AT_64); diff --git a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp index 2382ea271661..b57bceb3c837 100644 --- a/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp +++ b/contrib/llvm/lib/Target/Mips/MipsSEISelLowering.cpp @@ -1257,19 +1257,22 @@ static SDValue lowerMSACopyIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { static SDValue lowerMSASplatZExt(SDValue Op, unsigned OpNr, SelectionDAG &DAG) { EVT ResVecTy = Op->getValueType(0); EVT ViaVecTy = ResVecTy; + bool BigEndian = !DAG.getSubtarget().getTargetTriple().isLittleEndian(); SDLoc DL(Op); // When ResVecTy == MVT::v2i64, LaneA is the upper 32 bits of the lane and // LaneB is the lower 32-bits. Otherwise LaneA and LaneB are alternating // lanes. - SDValue LaneA; - SDValue LaneB = Op->getOperand(2); + SDValue LaneA = Op->getOperand(OpNr); + SDValue LaneB; if (ResVecTy == MVT::v2i64) { - LaneA = DAG.getConstant(0, DL, MVT::i32); + LaneB = DAG.getConstant(0, DL, MVT::i32); ViaVecTy = MVT::v4i32; + if(BigEndian) + std::swap(LaneA, LaneB); } else - LaneA = LaneB; + LaneB = LaneA; SDValue Ops[16] = { LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB, LaneA, LaneB }; @@ -1277,8 +1280,11 @@ static SDValue lowerMSASplatZExt(SDValue Op, unsigned OpNr, SelectionDAG &DAG) { SDValue Result = DAG.getBuildVector( ViaVecTy, DL, makeArrayRef(Ops, ViaVecTy.getVectorNumElements())); - if (ViaVecTy != ResVecTy) - Result = DAG.getNode(ISD::BITCAST, DL, ResVecTy, Result); + if (ViaVecTy != ResVecTy) { + SDValue One = DAG.getConstant(1, DL, ViaVecTy); + Result = DAG.getNode(ISD::BITCAST, DL, ResVecTy, + DAG.getNode(ISD::AND, DL, ViaVecTy, Result, One)); + } return Result; } diff --git a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp index 028c2cb562f8..6d7eb786a683 100644 --- a/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ b/contrib/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -113,8 +113,9 @@ class PPCAsmBackend : public MCAsmBackend { return (IsLittleEndian? InfosLE : InfosBE)[Kind - FirstTargetFixupKind]; } - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override { + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override { Value = adjustFixupValue(Fixup.getKind(), Value); if (!Value) return; // Doesn't change encoding. @@ -130,10 +131,8 @@ class PPCAsmBackend : public MCAsmBackend { } } - void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFixup &Fixup, const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) override { + void processFixupValue(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, bool &IsResolved) override { switch ((PPC::Fixups)Fixup.getKind()) { default: break; case PPC::fixup_ppc_br24: diff --git a/contrib/llvm/lib/Target/PowerPC/PPC.h b/contrib/llvm/lib/Target/PowerPC/PPC.h index 38ae62b26757..07c9c1f9f84c 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPC.h +++ b/contrib/llvm/lib/Target/PowerPC/PPC.h @@ -24,7 +24,6 @@ namespace llvm { class PPCTargetMachine; class PassRegistry; class FunctionPass; - class ImmutablePass; class MachineInstr; class AsmPrinter; class MCInst; diff --git a/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp b/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp index 57a1d373c88c..c2c115cb6daf 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp +++ b/contrib/llvm/lib/Target/PowerPC/PPCFrameLowering.cpp @@ -521,7 +521,7 @@ void PPCFrameLowering::replaceFPWithRealFP(MachineFunction &MF) const { const PPCRegisterInfo *RegInfo = Subtarget.getRegisterInfo(); bool HasBP = RegInfo->hasBasePointer(MF); unsigned BPReg = HasBP ? (unsigned) RegInfo->getBaseRegister(MF) : FPReg; - unsigned BP8Reg = HasBP ? (unsigned) PPC::X30 : FPReg; + unsigned BP8Reg = HasBP ? (unsigned) PPC::X30 : FP8Reg; for (MachineFunction::iterator BI = MF.begin(), BE = MF.end(); BI != BE; ++BI) diff --git a/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 662550f7a396..72f14e969138 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/contrib/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -2560,8 +2560,9 @@ SDValue PPCTargetLowering::LowerGlobalTLSAddress(SDValue Op, PPCII::MO_TPREL_HA); SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, PPCII::MO_TPREL_LO); - SDValue TLSReg = DAG.getRegister(is64bit ? PPC::X13 : PPC::R2, - is64bit ? MVT::i64 : MVT::i32); + SDValue TLSReg = is64bit ? DAG.getRegister(PPC::X13, MVT::i64) + : DAG.getRegister(PPC::R2, MVT::i32); + SDValue Hi = DAG.getNode(PPCISD::Hi, dl, PtrVT, TGAHi, TLSReg); return DAG.getNode(PPCISD::Lo, dl, PtrVT, TGALo, Hi); } @@ -8377,9 +8378,9 @@ SDValue PPCTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, if (IntrinsicID == Intrinsic::thread_pointer) { // Reads the thread pointer register, used for __builtin_thread_pointer. - bool is64bit = Subtarget.isPPC64(); - return DAG.getRegister(is64bit ? PPC::X13 : PPC::R2, - is64bit ? MVT::i64 : MVT::i32); + if (Subtarget.isPPC64()) + return DAG.getRegister(PPC::X13, MVT::i64); + return DAG.getRegister(PPC::R2, MVT::i32); } // If this is a lowered altivec predicate compare, CompareOpc is set to the diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td b/contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td index 70536a6039b8..e2af5e529544 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td +++ b/contrib/llvm/lib/Target/PowerPC/PPCInstr64Bit.td @@ -972,13 +972,15 @@ def LDMX : XForm_1<31, 309, (outs g8rc:$rD), (ins memrr:$src), // Support for medium and large code model. let hasSideEffects = 0 in { +let isReMaterializable = 1 in { def ADDIStocHA: Pseudo<(outs g8rc:$rD), (ins g8rc_nox0:$reg, tocentry:$disp), "#ADDIStocHA", []>, isPPC64; +def ADDItocL: Pseudo<(outs g8rc:$rD), (ins g8rc_nox0:$reg, tocentry:$disp), + "#ADDItocL", []>, isPPC64; +} let mayLoad = 1 in def LDtocL: Pseudo<(outs g8rc:$rD), (ins tocentry:$disp, g8rc_nox0:$reg), "#LDtocL", []>, isPPC64; -def ADDItocL: Pseudo<(outs g8rc:$rD), (ins g8rc_nox0:$reg, tocentry:$disp), - "#ADDItocL", []>, isPPC64; } // Support for thread-local storage. @@ -994,7 +996,7 @@ def LDgotTprelL: Pseudo<(outs g8rc:$rD), (ins s16imm64:$disp, g8rc_nox0:$reg), (PPCldGotTprelL tglobaltlsaddr:$disp, i64:$reg))]>, isPPC64; -let isBarrier = 1, isPseudo = 1, Defs = [CR7], Itinerary = IIC_LdStSync in +let isPseudo = 1, Defs = [CR7], Itinerary = IIC_LdStSync in def CFENCE8 : Pseudo<(outs), (ins g8rc:$cr), "#CFENCE8", []>; def : Pat<(PPCaddTls i64:$in, tglobaltlsaddr:$g), diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp index 236e513bec23..13b4f9ab962d 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp +++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.cpp @@ -292,6 +292,29 @@ unsigned PPCInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, return 0; } +// For opcodes with the ReMaterializable flag set, this function is called to +// verify the instruction is really rematable. +bool PPCInstrInfo::isReallyTriviallyReMaterializable(const MachineInstr &MI, + AliasAnalysis *AA) const { + switch (MI.getOpcode()) { + default: + // This function should only be called for opcodes with the ReMaterializable + // flag set. + llvm_unreachable("Unknown rematerializable operation!"); + break; + case PPC::LI: + case PPC::LI8: + case PPC::LIS: + case PPC::LIS8: + case PPC::QVGPCI: + case PPC::ADDIStocHA: + case PPC::ADDItocL: + case PPC::LOAD_STACK_GUARD: + return true; + } + return false; +} + unsigned PPCInstrInfo::isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex) const { // Note: This list must be kept consistent with StoreRegToStackSlot. diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h index 8dd4dbb60879..b0629c88cf57 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h +++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.h @@ -162,6 +162,8 @@ class PPCInstrInfo : public PPCGenInstrInfo { unsigned &SubIdx) const override; unsigned isLoadFromStackSlot(const MachineInstr &MI, int &FrameIndex) const override; + bool isReallyTriviallyReMaterializable(const MachineInstr &MI, + AliasAnalysis *AA) const override; unsigned isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex) const override; diff --git a/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp b/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp index 637e52bbdbee..8af7f7e98117 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp +++ b/contrib/llvm/lib/Target/PowerPC/PPCRegisterInfo.cpp @@ -389,9 +389,14 @@ void PPCRegisterInfo::lowerDynamicAlloc(MachineBasicBlock::iterator II) const { unsigned Reg = MF.getRegInfo().createVirtualRegister(LP64 ? G8RC : GPRC); if (MaxAlign < TargetAlign && isInt<16>(FrameSize)) { - BuildMI(MBB, II, dl, TII.get(PPC::ADDI), Reg) - .addReg(PPC::R31) - .addImm(FrameSize); + if (LP64) + BuildMI(MBB, II, dl, TII.get(PPC::ADDI8), Reg) + .addReg(PPC::X31) + .addImm(FrameSize); + else + BuildMI(MBB, II, dl, TII.get(PPC::ADDI), Reg) + .addReg(PPC::R31) + .addImm(FrameSize); } else if (LP64) { BuildMI(MBB, II, dl, TII.get(PPC::LD), Reg) .addImm(0) @@ -478,8 +483,10 @@ void PPCRegisterInfo::lowerDynamicAreaOffset( const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); unsigned maxCallFrameSize = MFI.getMaxCallFrameSize(); + bool is64Bit = TM.isPPC64(); DebugLoc dl = MI.getDebugLoc(); - BuildMI(MBB, II, dl, TII.get(PPC::LI), MI.getOperand(0).getReg()) + BuildMI(MBB, II, dl, TII.get(is64Bit ? PPC::LI8 : PPC::LI), + MI.getOperand(0).getReg()) .addImm(maxCallFrameSize); MBB.erase(II); } diff --git a/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp b/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp index 5a226b23ff96..a88a6541e8d0 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp +++ b/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.cpp @@ -86,9 +86,9 @@ EnableMachineCombinerPass("ppc-machine-combiner", extern "C" void LLVMInitializePowerPCTarget() { // Register the targets - RegisterTargetMachine A(getThePPC32Target()); - RegisterTargetMachine B(getThePPC64Target()); - RegisterTargetMachine C(getThePPC64LETarget()); + RegisterTargetMachine A(getThePPC32Target()); + RegisterTargetMachine B(getThePPC64Target()); + RegisterTargetMachine C(getThePPC64LETarget()); PassRegistry &PR = *PassRegistry::getPassRegistry(); initializePPCBoolRetToIntPass(PR); @@ -177,32 +177,34 @@ static PPCTargetMachine::PPCABI computeTargetABI(const Triple &TT, assert(Options.MCOptions.getABIName().empty() && "Unknown target-abi option!"); - if (!TT.isMacOSX()) { - switch (TT.getArch()) { - case Triple::ppc64le: - return PPCTargetMachine::PPC_ABI_ELFv2; - case Triple::ppc64: - return PPCTargetMachine::PPC_ABI_ELFv1; - default: - // Fallthrough. - ; - } + if (TT.isMacOSX()) + return PPCTargetMachine::PPC_ABI_UNKNOWN; + + switch (TT.getArch()) { + case Triple::ppc64le: + return PPCTargetMachine::PPC_ABI_ELFv2; + case Triple::ppc64: + return PPCTargetMachine::PPC_ABI_ELFv1; + default: + return PPCTargetMachine::PPC_ABI_UNKNOWN; } - return PPCTargetMachine::PPC_ABI_UNKNOWN; } static Reloc::Model getEffectiveRelocModel(const Triple &TT, Optional RM) { - if (!RM.hasValue()) { - if (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le) { - if (!TT.isOSBinFormatMachO() && !TT.isMacOSX()) - return Reloc::PIC_; - } - if (TT.isOSDarwin()) - return Reloc::DynamicNoPIC; - return Reloc::Static; - } - return *RM; + if (RM.hasValue()) + return *RM; + + // Darwin defaults to dynamic-no-pic. + if (TT.isOSDarwin()) + return Reloc::DynamicNoPIC; + + // Non-darwin 64-bit platforms are PIC by default. + if (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le) + return Reloc::PIC_; + + // 32-bit is static by default. + return Reloc::Static; } // The FeatureString here is a little subtle. We are modifying the feature @@ -224,26 +226,6 @@ PPCTargetMachine::PPCTargetMachine(const Target &T, const Triple &TT, PPCTargetMachine::~PPCTargetMachine() = default; -void PPC32TargetMachine::anchor() {} - -PPC32TargetMachine::PPC32TargetMachine(const Target &T, const Triple &TT, - StringRef CPU, StringRef FS, - const TargetOptions &Options, - Optional RM, - CodeModel::Model CM, - CodeGenOpt::Level OL) - : PPCTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL) {} - -void PPC64TargetMachine::anchor() {} - -PPC64TargetMachine::PPC64TargetMachine(const Target &T, const Triple &TT, - StringRef CPU, StringRef FS, - const TargetOptions &Options, - Optional RM, - CodeModel::Model CM, - CodeGenOpt::Level OL) - : PPCTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL) {} - const PPCSubtarget * PPCTargetMachine::getSubtargetImpl(const Function &F) const { Attribute CPUAttr = F.getFnAttribute("target-cpu"); @@ -406,7 +388,7 @@ void PPCPassConfig::addPreRegAlloc() { // FIXME: We probably don't need to run these for -fPIE. if (getPPCTargetMachine().isPositionIndependent()) { // FIXME: LiveVariables should not be necessary here! - // PPCTLSDYnamicCallPass uses LiveIntervals which previously dependet on + // PPCTLSDynamicCallPass uses LiveIntervals which previously dependent on // LiveVariables. This (unnecessary) dependency has been removed now, // however a stage-2 clang build fails without LiveVariables computed here. addPass(&LiveVariablesID, false); diff --git a/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.h b/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.h index b8f5a2083d80..5eb6ba785d1b 100644 --- a/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.h +++ b/contrib/llvm/lib/Target/PowerPC/PPCTargetMachine.h @@ -23,7 +23,7 @@ namespace llvm { /// Common code between 32-bit and 64-bit PowerPC targets. /// -class PPCTargetMachine : public LLVMTargetMachine { +class PPCTargetMachine final : public LLVMTargetMachine { public: enum PPCABI { PPC_ABI_UNKNOWN, PPC_ABI_ELFv1, PPC_ABI_ELFv2 }; private: @@ -60,29 +60,6 @@ class PPCTargetMachine : public LLVMTargetMachine { return false; } }; - -/// PowerPC 32-bit target machine. -/// -class PPC32TargetMachine : public PPCTargetMachine { - virtual void anchor(); -public: - PPC32TargetMachine(const Target &T, const Triple &TT, StringRef CPU, - StringRef FS, const TargetOptions &Options, - Optional RM, CodeModel::Model CM, - CodeGenOpt::Level OL); -}; - -/// PowerPC 64-bit target machine. -/// -class PPC64TargetMachine : public PPCTargetMachine { - virtual void anchor(); -public: - PPC64TargetMachine(const Target &T, const Triple &TT, StringRef CPU, - StringRef FS, const TargetOptions &Options, - Optional RM, CodeModel::Model CM, - CodeGenOpt::Level OL); -}; - } // end namespace llvm #endif diff --git a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp index d9a71893afee..f85c0cf111c4 100644 --- a/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ b/contrib/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -32,8 +32,9 @@ class RISCVAsmBackend : public MCAsmBackend { : MCAsmBackend(), OSABI(OSABI), Is64Bit(Is64Bit) {} ~RISCVAsmBackend() override {} - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; @@ -69,9 +70,10 @@ bool RISCVAsmBackend::writeNopData(uint64_t Count, MCObjectWriter *OW) const { return true; } -void RISCVAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, - bool IsPCRel, MCContext &Ctx) const { +void RISCVAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsPCRel) const { return; } diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp index d1d1334163a2..c72b47b09085 100644 --- a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -203,10 +203,8 @@ namespace { return InfosBE[Kind - FirstTargetFixupKind]; } - void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFixup &Fixup, const MCFragment *DF, - const MCValue &Target, uint64_t &Value, - bool &IsResolved) override { + void processFixupValue(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, bool &IsResolved) override { switch ((Sparc::Fixups)Fixup.getKind()) { default: break; case Sparc::fixup_sparc_wplt30: @@ -273,9 +271,9 @@ namespace { ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) : SparcAsmBackend(T), OSType(OSType) { } - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, - MCContext &Ctx) const override { + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override { Value = adjustFixupValue(Fixup.getKind(), Value); if (!Value) return; // Doesn't change encoding. diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp index 627e49a95f3c..2c040dce994b 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp +++ b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp @@ -15,6 +15,12 @@ using namespace llvm; +void SparcELFTargetObjectFile::Initialize(MCContext &Ctx, + const TargetMachine &TM) { + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + InitializeELF(TM.Options.UseInitArray); +} + const MCExpr *SparcELFTargetObjectFile::getTTypeGlobalReference( const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM, MachineModuleInfo *MMI, MCStreamer &Streamer) const { diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h index fe8800625a56..3b1b345c3b19 100644 --- a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h +++ b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h @@ -23,6 +23,8 @@ class SparcELFTargetObjectFile : public TargetLoweringObjectFileELF { TargetLoweringObjectFileELF() {} + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + const MCExpr *getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM, diff --git a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp index fd1fd7bc40dc..6b32a7926437 100644 --- a/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp +++ b/contrib/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp @@ -50,8 +50,9 @@ class SystemZMCAsmBackend : public MCAsmBackend { return SystemZ::NumTargetFixupKinds; } const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } @@ -89,15 +90,17 @@ SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { return Infos[Kind - FirstTargetFixupKind]; } -void SystemZMCAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, - bool IsPCRel, MCContext &Ctx) const { +void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm, + const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, uint64_t Value, + bool IsPCRel) const { MCFixupKind Kind = Fixup.getKind(); unsigned Offset = Fixup.getOffset(); unsigned BitSize = getFixupKindInfo(Kind).TargetSize; unsigned Size = (BitSize + 7) / 8; - assert(Offset + Size <= DataSize && "Invalid fixup offset!"); + assert(Offset + Size <= Data.size() && "Invalid fixup offset!"); // Big-endian insertion of Size bytes. Value = extractBitsForFixup(Kind, Value); diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp index a28a91e834f6..0cb2b5a14ce7 100644 --- a/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp +++ b/contrib/llvm/lib/Target/SystemZ/SystemZFrameLowering.cpp @@ -277,8 +277,21 @@ void SystemZFrameLowering:: processFunctionBeforeFrameFinalized(MachineFunction &MF, RegScavenger *RS) const { MachineFrameInfo &MFFrame = MF.getFrameInfo(); - uint64_t MaxReach = (MFFrame.estimateStackSize(MF) + - SystemZMC::CallFrameSize * 2); + // Get the size of our stack frame to be allocated ... + uint64_t StackSize = (MFFrame.estimateStackSize(MF) + + SystemZMC::CallFrameSize); + // ... and the maximum offset we may need to reach into the + // caller's frame to access the save area or stack arguments. + int64_t MaxArgOffset = SystemZMC::CallFrameSize; + for (int I = MFFrame.getObjectIndexBegin(); I != 0; ++I) + if (MFFrame.getObjectOffset(I) >= 0) { + int64_t ArgOffset = SystemZMC::CallFrameSize + + MFFrame.getObjectOffset(I) + + MFFrame.getObjectSize(I); + MaxArgOffset = std::max(MaxArgOffset, ArgOffset); + } + + uint64_t MaxReach = StackSize + MaxArgOffset; if (!isUInt<12>(MaxReach)) { // We may need register scavenging slots if some parts of the frame // are outside the reach of an unsigned 12-bit displacement. diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index ac4c3f6db684..fef4a8c92a36 100644 --- a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1322,11 +1322,6 @@ SystemZTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, return DAG.getNode(SystemZISD::RET_FLAG, DL, MVT::Other, RetOps); } -SDValue SystemZTargetLowering::prepareVolatileOrAtomicLoad( - SDValue Chain, const SDLoc &DL, SelectionDAG &DAG) const { - return DAG.getNode(SystemZISD::SERIALIZE, DL, MVT::Other, Chain); -} - // Return true if Op is an intrinsic node with chain that returns the CC value // as its only (other) argument. Provide the associated SystemZISD opcode and // the mask of valid CC values if so. @@ -2059,6 +2054,7 @@ static void adjustForTestUnderMask(SelectionDAG &DAG, const SDLoc &DL, if (NewC.ICmpType != SystemZICMP::SignedOnly && NewC.Op0.getOpcode() == ISD::SHL && isSimpleShift(NewC.Op0, ShiftVal) && + (MaskVal >> ShiftVal != 0) && (NewCCMask = getTestUnderMaskCond(BitSize, NewC.CCMask, MaskVal >> ShiftVal, CmpVal >> ShiftVal, @@ -2068,6 +2064,7 @@ static void adjustForTestUnderMask(SelectionDAG &DAG, const SDLoc &DL, } else if (NewC.ICmpType != SystemZICMP::SignedOnly && NewC.Op0.getOpcode() == ISD::SRL && isSimpleShift(NewC.Op0, ShiftVal) && + (MaskVal << ShiftVal != 0) && (NewCCMask = getTestUnderMaskCond(BitSize, NewC.CCMask, MaskVal << ShiftVal, CmpVal << ShiftVal, @@ -3212,12 +3209,15 @@ SDValue SystemZTargetLowering::lowerATOMIC_FENCE(SDValue Op, return DAG.getNode(SystemZISD::MEMBARRIER, DL, MVT::Other, Op.getOperand(0)); } -// Op is an atomic load. Lower it into a normal volatile load. +// Op is an atomic load. Lower it into a serialization followed +// by a normal volatile load. SDValue SystemZTargetLowering::lowerATOMIC_LOAD(SDValue Op, SelectionDAG &DAG) const { auto *Node = cast(Op.getNode()); + SDValue Chain = SDValue(DAG.getMachineNode(SystemZ::Serialize, SDLoc(Op), + MVT::Other, Node->getChain()), 0); return DAG.getExtLoad(ISD::EXTLOAD, SDLoc(Op), Op.getValueType(), - Node->getChain(), Node->getBasePtr(), + Chain, Node->getBasePtr(), Node->getMemoryVT(), Node->getMemOperand()); } @@ -4688,7 +4688,6 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(STRCMP); OPCODE(SEARCH_STRING); OPCODE(IPM); - OPCODE(SERIALIZE); OPCODE(MEMBARRIER); OPCODE(TBEGIN); OPCODE(TBEGIN_NOFLOAT); diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h index 79c8c4d92669..5dcb19c0a35d 100644 --- a/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/contrib/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -139,9 +139,6 @@ enum NodeType : unsigned { // Store the CC value in bits 29 and 28 of an integer. IPM, - // Perform a serialization operation. (BCR 15,0 or BCR 14,0.) - SERIALIZE, - // Compiler barrier only; generate a no-op. MEMBARRIER, @@ -471,8 +468,6 @@ class SystemZTargetLowering : public TargetLowering { const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const override; - SDValue prepareVolatileOrAtomicLoad(SDValue Chain, const SDLoc &DL, - SelectionDAG &DAG) const override; SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const override; ISD::NodeType getExtendForAtomicOps() const override { @@ -522,7 +517,6 @@ class SystemZTargetLowering : public TargetLowering { unsigned Opcode) const; SDValue lowerATOMIC_LOAD_SUB(SDValue Op, SelectionDAG &DAG) const; SDValue lowerATOMIC_CMP_SWAP(SDValue Op, SelectionDAG &DAG) const; - SDValue lowerLOAD_SEQUENCE_POINT(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const; SDValue lowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const; SDValue lowerPREFETCH(SDValue Op, SelectionDAG &DAG) const; diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index fa5ecdd85243..9f5e6288348e 100644 --- a/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/contrib/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -189,18 +189,15 @@ let isBranch = 1, isTerminator = 1 in { //===----------------------------------------------------------------------===// // Unconditional trap. -// FIXME: This trap instruction should be marked as isTerminator, but there is -// currently a general bug that allows non-terminators to be placed between -// terminators. Temporarily leave this unmarked until the bug is fixed. -let isBarrier = 1, hasCtrlDep = 1 in +let hasCtrlDep = 1 in def Trap : Alias<4, (outs), (ins), [(trap)]>; // Conditional trap. -let isTerminator = 1, hasCtrlDep = 1, Uses = [CC] in +let hasCtrlDep = 1, Uses = [CC] in def CondTrap : Alias<4, (outs), (ins cond4:$valid, cond4:$R1), []>; // Fused compare-and-trap instructions. -let isTerminator = 1, hasCtrlDep = 1 in { +let hasCtrlDep = 1 in { // These patterns work the same way as for compare-and-branch. defm CRT : CmpBranchRRFcPair<"crt", 0xB972, GR32>; defm CGRT : CmpBranchRRFcPair<"cgrt", 0xB960, GR64>; @@ -1449,7 +1446,7 @@ let Predicates = [FeatureExecutionHint] in { // A serialization instruction that acts as a barrier for all memory // accesses, which expands to "bcr 14, 0". let hasSideEffects = 1 in -def Serialize : Alias<2, (outs), (ins), [(z_serialize)]>; +def Serialize : Alias<2, (outs), (ins), []>; // A pseudo instruction that serves as a compiler barrier. let hasSideEffects = 1, hasNoSchedulingInfo = 1 in diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp b/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp index ab6020f3f189..b6feaa49d858 100644 --- a/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp +++ b/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp @@ -23,7 +23,7 @@ using namespace llvm; #ifndef NDEBUG // Print the set of SUs void SystemZPostRASchedStrategy::SUSet:: -dump(SystemZHazardRecognizer &HazardRec) { +dump(SystemZHazardRecognizer &HazardRec) const { dbgs() << "{"; for (auto &SU : *this) { HazardRec.dumpSU(SU, dbgs()); diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.h b/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.h index 12357e0348a9..3dfef388691e 100644 --- a/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.h +++ b/contrib/llvm/lib/Target/SystemZ/SystemZMachineScheduler.h @@ -72,7 +72,7 @@ class SystemZPostRASchedStrategy : public MachineSchedStrategy { // A set of SUs with a sorter and dump method. struct SUSet : std::set { #ifndef NDEBUG - void dump(SystemZHazardRecognizer &HazardRec); + void dump(SystemZHazardRecognizer &HazardRec) const; #endif }; diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZOperators.td b/contrib/llvm/lib/Target/SystemZ/SystemZOperators.td index adfc69c5d4cf..ab2392809f3b 100644 --- a/contrib/llvm/lib/Target/SystemZ/SystemZOperators.td +++ b/contrib/llvm/lib/Target/SystemZ/SystemZOperators.td @@ -191,8 +191,6 @@ def z_sdivrem64 : SDNode<"SystemZISD::SDIVREM64", SDT_ZGR128Binary64>; def z_udivrem32 : SDNode<"SystemZISD::UDIVREM32", SDT_ZGR128Binary32>; def z_udivrem64 : SDNode<"SystemZISD::UDIVREM64", SDT_ZGR128Binary64>; -def z_serialize : SDNode<"SystemZISD::SERIALIZE", SDTNone, - [SDNPHasChain, SDNPMayStore]>; def z_membarrier : SDNode<"SystemZISD::MEMBARRIER", SDTNone, [SDNPHasChain, SDNPSideEffect]>; diff --git a/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.h b/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.h index eb2f17a2091c..a10ca64fa632 100644 --- a/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.h +++ b/contrib/llvm/lib/Target/SystemZ/SystemZTargetMachine.h @@ -51,8 +51,6 @@ class SystemZTargetMachine : public LLVMTargetMachine { } bool targetSchedulesPostRAScheduling() const override { return true; }; - - bool isMachineVerifierClean() const override { return false; } }; } // end namespace llvm diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp index 4f20096c1583..1357cb5735f8 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp @@ -37,8 +37,9 @@ class WebAssemblyAsmBackendELF final : public MCAsmBackend { : MCAsmBackend(), Is64Bit(Is64Bit) {} ~WebAssemblyAsmBackendELF() override {} - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; @@ -77,8 +78,9 @@ class WebAssemblyAsmBackend final : public MCAsmBackend { const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override; MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; @@ -105,9 +107,11 @@ bool WebAssemblyAsmBackendELF::writeNopData(uint64_t Count, return true; } -void WebAssemblyAsmBackendELF::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, - bool IsPCRel, MCContext &Ctx) const { +void WebAssemblyAsmBackendELF::applyFixup(const MCAssembler &Asm, + const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const { const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); @@ -119,7 +123,7 @@ void WebAssemblyAsmBackendELF::applyFixup(const MCFixup &Fixup, char *Data, Value <<= Info.TargetOffset; unsigned Offset = Fixup.getOffset(); - assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); // For each byte of the fragment that the fixup touches, mask in the // bits from the fixup value. @@ -163,9 +167,11 @@ bool WebAssemblyAsmBackend::writeNopData(uint64_t Count, return true; } -void WebAssemblyAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, - bool IsPCRel, MCContext &Ctx) const { +void WebAssemblyAsmBackend::applyFixup(const MCAssembler &Asm, + const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const { const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); @@ -177,7 +183,7 @@ void WebAssemblyAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, Value <<= Info.TargetOffset; unsigned Offset = Fixup.getOffset(); - assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); // For each byte of the fragment that the fixup touches, mask in the // bits from the fixup value. diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp index c56c591def36..3e3b52fca569 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -36,7 +36,6 @@ STATISTIC(MCNumFixups, "Number of MC fixups created."); namespace { class WebAssemblyMCCodeEmitter final : public MCCodeEmitter { const MCInstrInfo &MCII; - MCContext &Ctx; // Implementation generated by tablegen. uint64_t getBinaryCodeForInstr(const MCInst &MI, @@ -48,14 +47,12 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter { const MCSubtargetInfo &STI) const override; public: - WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) - : MCII(mcii), Ctx(ctx) {} + WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {} }; } // end anonymous namespace -MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, - MCContext &Ctx) { - return new WebAssemblyMCCodeEmitter(MCII, Ctx); +MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) { + return new WebAssemblyMCCodeEmitter(MCII); } void WebAssemblyMCCodeEmitter::encodeInstruction( @@ -89,11 +86,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction( } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) { encodeSLEB128(int64_t(MO.getImm()), OS); } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) { - Fixups.push_back(MCFixup::create( - OS.tell() - Start, MCConstantExpr::create(MO.getImm(), Ctx), - MCFixupKind(WebAssembly::fixup_code_global_index), MI.getLoc())); - ++MCNumFixups; - encodeULEB128(uint64_t(MO.getImm()), OS); + llvm_unreachable("wasm globals should only be accessed symbolicly"); } else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) { encodeSLEB128(int64_t(MO.getImm()), OS); } else { @@ -135,6 +128,9 @@ void WebAssemblyMCCodeEmitter::encodeInstruction( Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) { FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32); PaddedSize = 5; + } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) { + FixupKind = MCFixupKind(WebAssembly::fixup_code_global_index); + PaddedSize = 5; } else { llvm_unreachable("unexpected symbolic operand kind"); } diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp index 9fd3ec81c258..9580eeaa33d7 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp @@ -74,7 +74,7 @@ static MCInstPrinter *createMCInstPrinter(const Triple & /*T*/, static MCCodeEmitter *createCodeEmitter(const MCInstrInfo &MCII, const MCRegisterInfo & /*MRI*/, MCContext &Ctx) { - return createWebAssemblyMCCodeEmitter(MCII, Ctx); + return createWebAssemblyMCCodeEmitter(MCII); } static MCAsmBackend *createAsmBackend(const Target & /*T*/, diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index 0ba700a86b74..4d676c32a09c 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -35,8 +35,7 @@ class raw_pwrite_stream; Target &getTheWebAssemblyTarget32(); Target &getTheWebAssemblyTarget64(); -MCCodeEmitter *createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, - MCContext &Ctx); +MCCodeEmitter *createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII); MCAsmBackend *createWebAssemblyAsmBackend(const Triple &TT); diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp index 19e14f3261aa..9cf77829f3bc 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -68,6 +68,8 @@ WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, bool IsFunction = IsFunctionExpr(Fixup.getValue()); switch (unsigned(Fixup.getKind())) { + case WebAssembly::fixup_code_global_index: + return wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB; case WebAssembly::fixup_code_sleb128_i32: if (IsFunction) return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index b999091e2d29..f51585a10ca1 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -96,13 +96,6 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { MCConstantExpr::create(Size, OutContext)); } } - - if (!TM.getTargetTriple().isOSBinFormatELF()) { - MachineModuleInfoWasm &MMIW = MMI->getObjFileInfo(); - getTargetStreamer()->emitGlobal(MMIW.getGlobals()); - if (MMIW.hasStackPointerGlobal()) - getTargetStreamer()->emitStackPointer(MMIW.getStackPointerGlobal()); - } } void WebAssemblyAsmPrinter::EmitConstantPool() { diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp index 09338a4898e0..c980f4b87f91 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -63,12 +63,16 @@ class WebAssemblyFastISel final : public FastISel { public: // Innocuous defaults for our address. Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; } - void setKind(BaseKind K) { Kind = K; } + void setKind(BaseKind K) { + assert(!isSet() && "Can't change kind with non-zero base"); + Kind = K; + } BaseKind getKind() const { return Kind; } bool isRegBase() const { return Kind == RegBase; } bool isFIBase() const { return Kind == FrameIndexBase; } void setReg(unsigned Reg) { assert(isRegBase() && "Invalid base register access!"); + assert(Base.Reg == 0 && "Overwriting non-zero register"); Base.Reg = Reg; } unsigned getReg() const { @@ -77,6 +81,7 @@ class WebAssemblyFastISel final : public FastISel { } void setFI(unsigned FI) { assert(isFIBase() && "Invalid base frame index access!"); + assert(Base.FI == 0 && "Overwriting non-zero frame index"); Base.FI = FI; } unsigned getFI() const { @@ -91,6 +96,13 @@ class WebAssemblyFastISel final : public FastISel { int64_t getOffset() const { return Offset; } void setGlobalValue(const GlobalValue *G) { GV = G; } const GlobalValue *getGlobalValue() const { return GV; } + bool isSet() const { + if (isRegBase()) { + return Base.Reg != 0; + } else { + return Base.FI != 0; + } + } }; /// Keep a pointer to the WebAssemblySubtarget around so that we can make the @@ -297,6 +309,9 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) { DenseMap::iterator SI = FuncInfo.StaticAllocaMap.find(AI); if (SI != FuncInfo.StaticAllocaMap.end()) { + if (Addr.isSet()) { + return false; + } Addr.setKind(Address::FrameIndexBase); Addr.setFI(SI->second); return true; @@ -341,6 +356,9 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) { break; } } + if (Addr.isSet()) { + return false; + } Addr.setReg(getRegForValue(Obj)); return Addr.getReg() != 0; } diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index 4209bc333f23..a37d6136e44e 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -104,10 +104,10 @@ static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF, const DebugLoc &DL) { const auto *TII = MF.getSubtarget().getInstrInfo(); + const char *ES = "__stack_pointer"; + auto *SPSymbol = MF.createExternalSymbolName(ES); if (MF.getSubtarget() .getTargetTriple().isOSBinFormatELF()) { - const char *ES = "__stack_pointer"; - auto *SPSymbol = MF.createExternalSymbolName(ES); MachineRegisterInfo &MRI = MF.getRegInfo(); const TargetRegisterClass *PtrRC = MRI.getTargetRegisterInfo()->getPointerRegClass(MF); @@ -125,10 +125,8 @@ static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF, .addReg(SrcReg) .addMemOperand(MMO); } else { - MachineModuleInfoWasm &MMIW = - MF.getMMI().getObjFileInfo(); BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::SET_GLOBAL_I32)) - .addImm(MMIW.getStackPointerGlobal()) + .addExternalSymbol(SPSymbol) .addReg(SrcReg); } } @@ -171,10 +169,11 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, unsigned SPReg = WebAssembly::SP32; if (StackSize) SPReg = MRI.createVirtualRegister(PtrRC); + + const char *ES = "__stack_pointer"; + auto *SPSymbol = MF.createExternalSymbolName(ES); if (MF.getSubtarget() .getTargetTriple().isOSBinFormatELF()) { - const char *ES = "__stack_pointer"; - auto *SPSymbol = MF.createExternalSymbolName(ES); unsigned Zero = MRI.createVirtualRegister(PtrRC); BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero) @@ -189,22 +188,8 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF, .addReg(Zero) // addr .addMemOperand(LoadMMO); } else { - auto &MMIW = MF.getMMI().getObjFileInfo(); - if (!MMIW.hasStackPointerGlobal()) { - MMIW.setStackPointerGlobal(MMIW.getGlobals().size()); - - // Create the stack-pointer global. For now, just use the - // Emscripten/Binaryen ABI names. - wasm::Global G; - G.Type = wasm::ValType::I32; - G.Mutable = true; - G.InitialValue = 0; - G.InitialModule = "env"; - G.InitialName = "STACKTOP"; - MMIW.addGlobal(G); - } BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::GET_GLOBAL_I32), SPReg) - .addImm(MMIW.getStackPointerGlobal()); + .addExternalSymbol(SPSymbol); } bool HasBP = hasBP(MF); diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 6650191807dc..ea9e3fa862ce 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -170,28 +170,16 @@ static void Query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read, if (MI.mayStore()) { Write = true; - const MachineFunction &MF = *MI.getParent()->getParent(); - if (MF.getSubtarget() - .getTargetTriple().isOSBinFormatELF()) { - // Check for stores to __stack_pointer. - for (auto MMO : MI.memoperands()) { - const MachinePointerInfo &MPI = MMO->getPointerInfo(); - if (MPI.V.is()) { - auto PSV = MPI.V.get(); - if (const ExternalSymbolPseudoSourceValue *EPSV = - dyn_cast(PSV)) - if (StringRef(EPSV->getSymbol()) == "__stack_pointer") - StackPointer = true; - } - } - } else { - // Check for sets of the stack pointer. - const MachineModuleInfoWasm &MMIW = - MF.getMMI().getObjFileInfo(); - if ((MI.getOpcode() == WebAssembly::SET_LOCAL_I32 || - MI.getOpcode() == WebAssembly::SET_LOCAL_I64) && - MI.getOperand(0).getImm() == MMIW.getStackPointerGlobal()) { - StackPointer = true; + // Check for stores to __stack_pointer. + for (auto MMO : MI.memoperands()) { + const MachinePointerInfo &MPI = MMO->getPointerInfo(); + if (MPI.V.is()) { + auto PSV = MPI.V.get(); + if (const ExternalSymbolPseudoSourceValue *EPSV = + dyn_cast(PSV)) + if (StringRef(EPSV->getSymbol()) == "__stack_pointer") { + StackPointer = true; + } } } } else if (MI.hasOrderedMemoryRef()) { diff --git a/contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp b/contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp index e5d3209ec6a9..d30cc724c203 100644 --- a/contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp +++ b/contrib/llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp @@ -1705,8 +1705,7 @@ bool X86AsmParser::ParseIntelDotOperator(const MCExpr *Disp, if (isParsingInlineAsm() && Tok.is(AsmToken::Identifier)) { SMLoc Loc = SMLoc::getFromPointer(DotDispStr.data()); unsigned Len = DotDispStr.size(); - unsigned Val = OrigDispVal + DotDispVal; - InstInfo->AsmRewrites->emplace_back(AOK_DotOperator, Loc, Len, Val); + InstInfo->AsmRewrites->emplace_back(AOK_DotOperator, Loc, Len, DotDispVal); } NewDisp = MCConstantExpr::create(OrigDispVal + DotDispVal, getContext()); diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp index 7a9e4f4468ec..914fb36f91a7 100644 --- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -108,12 +108,12 @@ class X86AsmBackend : public MCAsmBackend { return Infos[Kind - FirstTargetFixupKind]; } - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, - uint64_t Value, bool IsPCRel, MCContext &Ctx) const override { + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsPCRel) const override { unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind()); - assert(Fixup.getOffset() + Size <= DataSize && - "Invalid fixup offset!"); + assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!"); // Check that uppper bits are either all zeros or all ones. // Specifically ignore overflow/underflow as long as the leakage is diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp index 4097ef224d50..caf98bffb80d 100644 --- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp +++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86MachObjectWriter.cpp @@ -153,8 +153,7 @@ void X86MachObjectWriter::RecordX86_64Relocation( const MCSymbol *B_Base = Asm.getAtom(*B); // Neither symbol can be modified. - if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || - Target.getSymB()->getKind() != MCSymbolRefExpr::VK_None) { + if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None) { Asm.getContext().reportError(Fixup.getLoc(), "unsupported relocation of modified symbol"); return; diff --git a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp index 105580c913a1..5892f1de33ee 100644 --- a/contrib/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp +++ b/contrib/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFObjectWriter.cpp @@ -10,6 +10,7 @@ #include "MCTargetDesc/X86FixupKinds.h" #include "MCTargetDesc/X86MCTargetDesc.h" #include "llvm/BinaryFormat/COFF.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCValue.h" @@ -25,8 +26,8 @@ class X86WinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter { X86WinCOFFObjectWriter(bool Is64Bit); ~X86WinCOFFObjectWriter() override = default; - unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, - bool IsCrossSection, + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsCrossSection, const MCAsmBackend &MAB) const override; }; @@ -36,11 +37,19 @@ X86WinCOFFObjectWriter::X86WinCOFFObjectWriter(bool Is64Bit) : MCWinCOFFObjectTargetWriter(Is64Bit ? COFF::IMAGE_FILE_MACHINE_AMD64 : COFF::IMAGE_FILE_MACHINE_I386) {} -unsigned X86WinCOFFObjectWriter::getRelocType(const MCValue &Target, +unsigned X86WinCOFFObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, const MCFixup &Fixup, bool IsCrossSection, const MCAsmBackend &MAB) const { - unsigned FixupKind = IsCrossSection ? FK_PCRel_4 : Fixup.getKind(); + unsigned FixupKind = Fixup.getKind(); + if (IsCrossSection) { + if (FixupKind != FK_Data_4) { + Ctx.reportError(Fixup.getLoc(), "Cannot represent this expression"); + return COFF::IMAGE_REL_AMD64_ADDR32; + } + FixupKind = FK_PCRel_4; + } MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); diff --git a/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp b/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp index 2777fa89330f..e3aa227702be 100644 --- a/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -748,17 +748,7 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF, else CallOp = X86::CALLpcrel32; - const char *Symbol; - if (Is64Bit) { - if (STI.isTargetCygMing()) { - Symbol = "___chkstk_ms"; - } else { - Symbol = "__chkstk"; - } - } else if (STI.isTargetCygMing()) - Symbol = "_alloca"; - else - Symbol = "_chkstk"; + StringRef Symbol = STI.getTargetLowering()->getStackProbeSymbolName(MF); MachineInstrBuilder CI; MachineBasicBlock::iterator ExpansionMBBI = std::prev(MBBI); @@ -769,10 +759,11 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF, // For the large code model, we have to call through a register. Use R11, // as it is scratch in all supported calling conventions. BuildMI(MBB, MBBI, DL, TII.get(X86::MOV64ri), X86::R11) - .addExternalSymbol(Symbol); + .addExternalSymbol(MF.createExternalSymbolName(Symbol)); CI = BuildMI(MBB, MBBI, DL, TII.get(CallOp)).addReg(X86::R11); } else { - CI = BuildMI(MBB, MBBI, DL, TII.get(CallOp)).addExternalSymbol(Symbol); + CI = BuildMI(MBB, MBBI, DL, TII.get(CallOp)) + .addExternalSymbol(MF.createExternalSymbolName(Symbol)); } unsigned AX = Is64Bit ? X86::RAX : X86::EAX; @@ -783,13 +774,16 @@ void X86FrameLowering::emitStackProbeCall(MachineFunction &MF, .addReg(SP, RegState::Define | RegState::Implicit) .addReg(X86::EFLAGS, RegState::Define | RegState::Implicit); - if (Is64Bit) { + if (STI.isTargetWin64() || !STI.isOSWindows()) { + // MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves. // MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp - // themselves. It also does not clobber %rax so we can reuse it when + // themselves. They also does not clobber %rax so we can reuse it when // adjusting %rsp. - BuildMI(MBB, MBBI, DL, TII.get(X86::SUB64rr), X86::RSP) - .addReg(X86::RSP) - .addReg(X86::RAX); + // All other platforms do not specify a particular ABI for the stack probe + // function, so we arbitrarily define it to not adjust %esp/%rsp itself. + BuildMI(MBB, MBBI, DL, TII.get(getSUBrrOpcode(Is64Bit)), SP) + .addReg(SP) + .addReg(AX); } if (InProlog) { @@ -978,7 +972,8 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, X86FI->setCalleeSavedFrameSize( X86FI->getCalleeSavedFrameSize() - TailCallReturnAddrDelta); - bool UseStackProbe = (STI.isOSWindows() && !STI.isTargetMachO()); + bool UseRedZone = false; + bool UseStackProbe = !STI.getTargetLowering()->getStackProbeSymbolName(MF).empty(); // The default stack probe size is 4096 if the function has no stackprobesize // attribute. @@ -1007,6 +1002,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, !TRI->needsStackRealignment(MF) && !MFI.hasVarSizedObjects() && // No dynamic alloca. !MFI.adjustsStack() && // No calls. + !UseStackProbe && // No stack probes. !IsWin64CC && // Win64 has no Red Zone !MFI.hasCopyImplyingStackAdjustment() && // Don't push and pop. !MF.shouldSplitStack()) { // Regular stack @@ -1015,6 +1011,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, X86FI->setUsesRedZone(MinSize > 0 || StackSize > 0); StackSize = std::max(MinSize, StackSize > 128 ? StackSize - 128 : 0); MFI.setStackSize(StackSize); + UseRedZone = true; } // Insert stack pointer adjustment for later moving of return addr. Only @@ -1192,6 +1189,8 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, if (IsWin64Prologue && !IsFunclet && TRI->needsStackRealignment(MF)) AlignedNumBytes = alignTo(AlignedNumBytes, MaxAlign); if (AlignedNumBytes >= StackProbeSize && UseStackProbe) { + assert(!UseRedZone && "The Red Zone is not accounted for in stack probes"); + // Check whether EAX is livein for this block. bool isEAXAlive = isEAXLiveIn(MBB); diff --git a/contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index 2a1633de0a23..3c4589ab18f6 100644 --- a/contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/contrib/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -204,6 +204,11 @@ namespace { bool selectVectorAddr(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Scale, SDValue &Index, SDValue &Disp, SDValue &Segment); + template + bool selectAddrOfGatherScatterNode(GatherScatterSDNode *Parent, SDValue N, + SDValue &Base, SDValue &Scale, + SDValue &Index, SDValue &Disp, + SDValue &Segment); bool selectMOV64Imm32(SDValue N, SDValue &Imm); bool selectLEAAddr(SDValue N, SDValue &Base, SDValue &Scale, SDValue &Index, SDValue &Disp, @@ -1415,13 +1420,10 @@ bool X86DAGToDAGISel::matchAddressBase(SDValue N, X86ISelAddressMode &AM) { return false; } -bool X86DAGToDAGISel::selectVectorAddr(SDNode *Parent, SDValue N, SDValue &Base, - SDValue &Scale, SDValue &Index, - SDValue &Disp, SDValue &Segment) { - - MaskedGatherScatterSDNode *Mgs = dyn_cast(Parent); - if (!Mgs) - return false; +template +bool X86DAGToDAGISel::selectAddrOfGatherScatterNode( + GatherScatterSDNode *Mgs, SDValue N, SDValue &Base, SDValue &Scale, + SDValue &Index, SDValue &Disp, SDValue &Segment) { X86ISelAddressMode AM; unsigned AddrSpace = Mgs->getPointerInfo().getAddrSpace(); // AddrSpace 256 -> GS, 257 -> FS, 258 -> SS. @@ -1453,6 +1455,18 @@ bool X86DAGToDAGISel::selectVectorAddr(SDNode *Parent, SDValue N, SDValue &Base, return true; } +bool X86DAGToDAGISel::selectVectorAddr(SDNode *Parent, SDValue N, SDValue &Base, + SDValue &Scale, SDValue &Index, + SDValue &Disp, SDValue &Segment) { + if (auto Mgs = dyn_cast(Parent)) + return selectAddrOfGatherScatterNode( + Mgs, N, Base, Scale, Index, Disp, Segment); + if (auto X86Gather = dyn_cast(Parent)) + return selectAddrOfGatherScatterNode( + X86Gather, N, Base, Scale, Index, Disp, Segment); + return false; +} + /// Returns true if it is able to pattern match an addressing mode. /// It returns the operands which make up the maximal addressing mode it can /// match by reference. diff --git a/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp b/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp index 172eba0002d4..f777e5628988 100644 --- a/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/contrib/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -1662,6 +1662,12 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM, MaxStoresPerMemcpyOptSize = 4; MaxStoresPerMemmove = 8; // For @llvm.memmove -> sequence of stores MaxStoresPerMemmoveOptSize = 4; + + // TODO: These control memcmp expansion in CGP and are set low to prevent + // altering the vector expansion for 16/32 byte memcmp in SelectionDAGBuilder. + MaxLoadsPerMemcmp = 1; + MaxLoadsPerMemcmpOptSize = 1; + // Set loop alignment to 2^ExperimentalPrefLoopAlignment bytes (default: 2^4). setPrefLoopAlignment(ExperimentalPrefLoopAlignment); @@ -14272,9 +14278,8 @@ SDValue X86TargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op, // If we are inserting a element, see if we can do this more efficiently with // a blend shuffle with a rematerializable vector than a costly integer // insertion. - // TODO: pre-SSE41 targets will tend to use bit masking - this could still - // be beneficial if we are inserting several zeros and can combine the masks. - if ((IsZeroElt || IsAllOnesElt) && Subtarget.hasSSE41() && NumElts <= 8) { + if ((IsZeroElt || IsAllOnesElt) && Subtarget.hasSSE41() && + 16 <= EltVT.getSizeInBits()) { SmallVector BlendMask; for (unsigned i = 0; i != NumElts; ++i) BlendMask.push_back(i == IdxVal ? i + NumElts : i); @@ -17621,23 +17626,21 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { if ((isAllOnesConstant(Op1) || isAllOnesConstant(Op2)) && (CondCode == X86::COND_E || CondCode == X86::COND_NE)) { SDValue Y = isAllOnesConstant(Op2) ? Op1 : Op2; - SDValue CmpOp0 = Cmp.getOperand(0); + // Apply further optimizations for special cases // (select (x != 0), -1, 0) -> neg & sbb // (select (x == 0), 0, -1) -> neg & sbb if (isNullConstant(Y) && - (isAllOnesConstant(Op1) == (CondCode == X86::COND_NE))) { - SDVTList VTs = DAG.getVTList(CmpOp0.getValueType(), MVT::i32); - SDValue Neg = DAG.getNode(X86ISD::SUB, DL, VTs, - DAG.getConstant(0, DL, - CmpOp0.getValueType()), - CmpOp0); - SDValue Res = DAG.getNode(X86ISD::SETCC_CARRY, DL, Op.getValueType(), - DAG.getConstant(X86::COND_B, DL, MVT::i8), - SDValue(Neg.getNode(), 1)); - return Res; - } + (isAllOnesConstant(Op1) == (CondCode == X86::COND_NE))) { + SDVTList VTs = DAG.getVTList(CmpOp0.getValueType(), MVT::i32); + SDValue Zero = DAG.getConstant(0, DL, CmpOp0.getValueType()); + SDValue Neg = DAG.getNode(X86ISD::SUB, DL, VTs, Zero, CmpOp0); + SDValue Res = DAG.getNode(X86ISD::SETCC_CARRY, DL, Op.getValueType(), + DAG.getConstant(X86::COND_B, DL, MVT::i8), + SDValue(Neg.getNode(), 1)); + return Res; + } Cmp = DAG.getNode(X86ISD::CMP, DL, MVT::i32, CmpOp0, DAG.getConstant(1, DL, CmpOp0.getValueType())); @@ -18648,8 +18651,9 @@ X86TargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); bool SplitStack = MF.shouldSplitStack(); + bool EmitStackProbe = !getStackProbeSymbolName(MF).empty(); bool Lower = (Subtarget.isOSWindows() && !Subtarget.isTargetMachO()) || - SplitStack; + SplitStack || EmitStackProbe; SDLoc dl(Op); // Get the inputs. @@ -23705,6 +23709,57 @@ static SDValue LowerMGATHER(SDValue Op, const X86Subtarget &Subtarget, SDValue RetOps[] = {Exract, NewGather.getValue(1)}; return DAG.getMergeValues(RetOps, dl); } + if (N->getMemoryVT() == MVT::v2i32 && Subtarget.hasVLX()) { + // There is a special case when the return type is v2i32 is illegal and + // the type legaizer extended it to v2i64. Without this conversion we end up + // with VPGATHERQQ (reading q-words from the memory) instead of VPGATHERQD. + // In order to avoid this situation, we'll build an X86 specific Gather node + // with index v2i64 and value type v4i32. + assert(VT == MVT::v2i64 && Src0.getValueType() == MVT::v2i64 && + "Unexpected type in masked gather"); + Src0 = DAG.getVectorShuffle(MVT::v4i32, dl, + DAG.getBitcast(MVT::v4i32, Src0), + DAG.getUNDEF(MVT::v4i32), { 0, 2, -1, -1 }); + // The mask should match the destination type. Extending mask with zeroes + // is not necessary since instruction itself reads only two values from + // memory. + Mask = ExtendToType(Mask, MVT::v4i1, DAG, false); + SDValue Ops[] = { N->getChain(), Src0, Mask, N->getBasePtr(), Index }; + SDValue NewGather = DAG.getTargetMemSDNode( + DAG.getVTList(MVT::v4i32, MVT::Other), Ops, dl, N->getMemoryVT(), + N->getMemOperand()); + + SDValue Sext = getExtendInVec(X86ISD::VSEXT, dl, MVT::v2i64, + NewGather.getValue(0), DAG); + SDValue RetOps[] = { Sext, NewGather.getValue(1) }; + return DAG.getMergeValues(RetOps, dl); + } + if (N->getMemoryVT() == MVT::v2f32 && Subtarget.hasVLX()) { + // This transformation is for optimization only. + // The type legalizer extended mask and index to 4 elements vector + // in order to match requirements of the common gather node - same + // vector width of index and value. X86 Gather node allows mismatch + // of vector width in order to select more optimal instruction at the + // end. + assert(VT == MVT::v4f32 && Src0.getValueType() == MVT::v4f32 && + "Unexpected type in masked gather"); + if (Mask.getOpcode() == ISD::CONCAT_VECTORS && + ISD::isBuildVectorAllZeros(Mask.getOperand(1).getNode()) && + Index.getOpcode() == ISD::CONCAT_VECTORS && + Index.getOperand(1).isUndef()) { + Mask = ExtendToType(Mask.getOperand(0), MVT::v4i1, DAG, false); + Index = Index.getOperand(0); + } else + return Op; + SDValue Ops[] = { N->getChain(), Src0, Mask, N->getBasePtr(), Index }; + SDValue NewGather = DAG.getTargetMemSDNode( + DAG.getVTList(MVT::v4f32, MVT::Other), Ops, dl, N->getMemoryVT(), + N->getMemOperand()); + + SDValue RetOps[] = { NewGather.getValue(0), NewGather.getValue(1) }; + return DAG.getMergeValues(RetOps, dl); + + } return Op; } @@ -24508,6 +24563,7 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const { case X86ISD::CVTS2SI_RND: return "X86ISD::CVTS2SI_RND"; case X86ISD::CVTS2UI_RND: return "X86ISD::CVTS2UI_RND"; case X86ISD::LWPINS: return "X86ISD::LWPINS"; + case X86ISD::MGATHER: return "X86ISD::MGATHER"; } return nullptr; } @@ -29868,7 +29924,7 @@ static SDValue combineSelectOfTwoConstants(SDNode *N, SelectionDAG &DAG) { if (N->getValueType(0) == MVT::i32) Diff = (unsigned)Diff; - bool isFastMultiplier = false; + bool IsFastMultiplier = false; if (Diff < 10) { switch ((unsigned char)Diff) { default: @@ -29880,12 +29936,12 @@ static SDValue combineSelectOfTwoConstants(SDNode *N, SelectionDAG &DAG) { case 5: // result = lea base(cond, cond*4) case 8: // result = lea base( , cond*8) case 9: // result = lea base(cond, cond*8) - isFastMultiplier = true; + IsFastMultiplier = true; break; } } - if (isFastMultiplier) { + if (IsFastMultiplier) { APInt Diff = TrueC->getAPIntValue() - FalseC->getAPIntValue(); if (NeedsCondInvert) // Invert the condition if needed. Cond = DAG.getNode(ISD::XOR, DL, Cond.getValueType(), Cond, @@ -34841,23 +34897,56 @@ static SDValue combineAddOrSubToADCOrSBB(SDNode *N, SelectionDAG &DAG) { !Cmp.getOperand(0).getValueType().isInteger()) return SDValue(); - // (cmp Z, 1) sets the carry flag if Z is 0. SDValue Z = Cmp.getOperand(0); - SDValue NewCmp = DAG.getNode(X86ISD::CMP, DL, MVT::i32, Z, - DAG.getConstant(1, DL, Z.getValueType())); + EVT ZVT = Z.getValueType(); - SDVTList VTs = DAG.getVTList(N->getValueType(0), MVT::i32); + // If X is -1 or 0, then we have an opportunity to avoid constants required in + // the general case below. + if (auto *ConstantX = dyn_cast(X)) { + // 'neg' sets the carry flag when Z != 0, so create 0 or -1 using 'sbb' with + // fake operands: + // 0 - (Z != 0) --> sbb %eax, %eax, (neg Z) + // -1 + (Z == 0) --> sbb %eax, %eax, (neg Z) + if ((IsSub && CC == X86::COND_NE && ConstantX->isNullValue()) || + (!IsSub && CC == X86::COND_E && ConstantX->isAllOnesValue())) { + SDValue Zero = DAG.getConstant(0, DL, ZVT); + SDVTList X86SubVTs = DAG.getVTList(ZVT, MVT::i32); + SDValue Neg = DAG.getNode(X86ISD::SUB, DL, X86SubVTs, Zero, Z); + return DAG.getNode(X86ISD::SETCC_CARRY, DL, VT, + DAG.getConstant(X86::COND_B, DL, MVT::i8), + SDValue(Neg.getNode(), 1)); + } + + // cmp with 1 sets the carry flag when Z == 0, so create 0 or -1 using 'sbb' + // with fake operands: + // 0 - (Z == 0) --> sbb %eax, %eax, (cmp Z, 1) + // -1 + (Z != 0) --> sbb %eax, %eax, (cmp Z, 1) + if ((IsSub && CC == X86::COND_E && ConstantX->isNullValue()) || + (!IsSub && CC == X86::COND_NE && ConstantX->isAllOnesValue())) { + SDValue One = DAG.getConstant(1, DL, ZVT); + SDValue Cmp1 = DAG.getNode(X86ISD::CMP, DL, MVT::i32, Z, One); + return DAG.getNode(X86ISD::SETCC_CARRY, DL, VT, + DAG.getConstant(X86::COND_B, DL, MVT::i8), Cmp1); + } + } + + // (cmp Z, 1) sets the carry flag if Z is 0. + SDValue One = DAG.getConstant(1, DL, ZVT); + SDValue Cmp1 = DAG.getNode(X86ISD::CMP, DL, MVT::i32, Z, One); + + // Add the flags type for ADC/SBB nodes. + SDVTList VTs = DAG.getVTList(VT, MVT::i32); // X - (Z != 0) --> sub X, (zext(setne Z, 0)) --> adc X, -1, (cmp Z, 1) // X + (Z != 0) --> add X, (zext(setne Z, 0)) --> sbb X, -1, (cmp Z, 1) if (CC == X86::COND_NE) return DAG.getNode(IsSub ? X86ISD::ADC : X86ISD::SBB, DL, VTs, X, - DAG.getConstant(-1ULL, DL, VT), NewCmp); + DAG.getConstant(-1ULL, DL, VT), Cmp1); // X - (Z == 0) --> sub X, (zext(sete Z, 0)) --> sbb X, 0, (cmp Z, 1) // X + (Z == 0) --> add X, (zext(sete Z, 0)) --> adc X, 0, (cmp Z, 1) return DAG.getNode(IsSub ? X86ISD::SBB : X86ISD::ADC, DL, VTs, X, - DAG.getConstant(0, DL, VT), NewCmp); + DAG.getConstant(0, DL, VT), Cmp1); } static SDValue combineLoopMAddPattern(SDNode *N, SelectionDAG &DAG, @@ -34976,6 +35065,32 @@ static SDValue combineLoopSADPattern(SDNode *N, SelectionDAG &DAG, return DAG.getNode(ISD::ADD, DL, VT, Sad, Phi); } +/// Convert vector increment or decrement to sub/add with an all-ones constant: +/// add X, <1, 1...> --> sub X, <-1, -1...> +/// sub X, <1, 1...> --> add X, <-1, -1...> +/// The all-ones vector constant can be materialized using a pcmpeq instruction +/// that is commonly recognized as an idiom (has no register dependency), so +/// that's better/smaller than loading a splat 1 constant. +static SDValue combineIncDecVector(SDNode *N, SelectionDAG &DAG) { + assert(N->getOpcode() == ISD::ADD || N->getOpcode() == ISD::SUB && + "Unexpected opcode for increment/decrement transform"); + + // Pseudo-legality check: getOnesVector() expects one of these types, so bail + // out and wait for legalization if we have an unsupported vector length. + EVT VT = N->getValueType(0); + if (!VT.is128BitVector() && !VT.is256BitVector() && !VT.is512BitVector()) + return SDValue(); + + SDNode *N1 = N->getOperand(1).getNode(); + APInt SplatVal; + if (!ISD::isConstantSplatVector(N1, SplatVal) || !SplatVal.isOneValue()) + return SDValue(); + + SDValue AllOnesVec = getOnesVector(VT, DAG, SDLoc(N)); + unsigned NewOpcode = N->getOpcode() == ISD::ADD ? ISD::SUB : ISD::ADD; + return DAG.getNode(NewOpcode, SDLoc(N), VT, N->getOperand(0), AllOnesVec); +} + static SDValue combineAdd(SDNode *N, SelectionDAG &DAG, const X86Subtarget &Subtarget) { const SDNodeFlags Flags = N->getFlags(); @@ -34995,6 +35110,9 @@ static SDValue combineAdd(SDNode *N, SelectionDAG &DAG, isHorizontalBinOp(Op0, Op1, true)) return DAG.getNode(X86ISD::HADD, SDLoc(N), VT, Op0, Op1); + if (SDValue V = combineIncDecVector(N, DAG)) + return V; + return combineAddOrSubToADCOrSBB(N, DAG); } @@ -35028,6 +35146,9 @@ static SDValue combineSub(SDNode *N, SelectionDAG &DAG, isHorizontalBinOp(Op0, Op1, false)) return DAG.getNode(X86ISD::HSUB, SDLoc(N), VT, Op0, Op1); + if (SDValue V = combineIncDecVector(N, DAG)) + return V; + return combineAddOrSubToADCOrSBB(N, DAG); } @@ -36335,3 +36456,22 @@ void X86TargetLowering::insertCopiesSplitCSR( bool X86TargetLowering::supportSwiftError() const { return Subtarget.is64Bit(); } + +/// Returns the name of the symbol used to emit stack probes or the empty +/// string if not applicable. +StringRef X86TargetLowering::getStackProbeSymbolName(MachineFunction &MF) const { + // If the function specifically requests stack probes, emit them. + if (MF.getFunction()->hasFnAttribute("probe-stack")) + return MF.getFunction()->getFnAttribute("probe-stack").getValueAsString(); + + // Generally, if we aren't on Windows, the platform ABI does not include + // support for stack probes, so don't emit them. + if (!Subtarget.isOSWindows() || Subtarget.isTargetMachO()) + return ""; + + // We need a stack probe to conform to the Windows ABI. Choose the right + // symbol. + if (Subtarget.is64Bit()) + return Subtarget.isTargetCygMing() ? "___chkstk_ms" : "__chkstk"; + return Subtarget.isTargetCygMing() ? "_alloca" : "_chkstk"; +} diff --git a/contrib/llvm/lib/Target/X86/X86ISelLowering.h b/contrib/llvm/lib/Target/X86/X86ISelLowering.h index f51b6641db2f..e1ade92979dc 100644 --- a/contrib/llvm/lib/Target/X86/X86ISelLowering.h +++ b/contrib/llvm/lib/Target/X86/X86ISelLowering.h @@ -615,7 +615,10 @@ namespace llvm { // Vector truncating store with unsigned/signed saturation VTRUNCSTOREUS, VTRUNCSTORES, // Vector truncating masked store with unsigned/signed saturation - VMTRUNCSTOREUS, VMTRUNCSTORES + VMTRUNCSTOREUS, VMTRUNCSTORES, + + // X86 specific gather + MGATHER // WARNING: Do not add anything in the end unless you want the node to // have memop! In fact, starting from FIRST_TARGET_MEMORY_OPCODE all @@ -1056,6 +1059,8 @@ namespace llvm { bool supportSwiftError() const override; + StringRef getStackProbeSymbolName(MachineFunction &MF) const override; + unsigned getMaxSupportedInterleaveFactor() const override { return 4; } /// \brief Lower interleaved load(s) into target specific @@ -1065,6 +1070,12 @@ namespace llvm { ArrayRef Indices, unsigned Factor) const override; + /// \brief Lower interleaved store(s) into target specific + /// instructions/intrinsics. + bool lowerInterleavedStore(StoreInst *SI, ShuffleVectorInst *SVI, + unsigned Factor) const override; + + void finalizeLowering(MachineFunction &MF) const override; protected: @@ -1397,6 +1408,19 @@ namespace llvm { } }; + // X86 specific Gather node. + class X86MaskedGatherSDNode : public MaskedGatherScatterSDNode { + public: + X86MaskedGatherSDNode(unsigned Order, + const DebugLoc &dl, SDVTList VTs, EVT MemVT, + MachineMemOperand *MMO) + : MaskedGatherScatterSDNode(X86ISD::MGATHER, Order, dl, VTs, MemVT, MMO) + {} + static bool classof(const SDNode *N) { + return N->getOpcode() == X86ISD::MGATHER; + } + }; + } // end namespace llvm #endif // LLVM_LIB_TARGET_X86_X86ISELLOWERING_H diff --git a/contrib/llvm/lib/Target/X86/X86InstrAVX512.td b/contrib/llvm/lib/Target/X86/X86InstrAVX512.td index 2620679df251..01a70323224c 100644 --- a/contrib/llvm/lib/Target/X86/X86InstrAVX512.td +++ b/contrib/llvm/lib/Target/X86/X86InstrAVX512.td @@ -7265,13 +7265,13 @@ avx512_rndscale_scalar opc, string OpcodeStr, X86VectorVTInfo _> { let Predicates = [HasAVX512] in { def : Pat<(ffloor _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), - (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x1))), _.FRC)>; + (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x9))), _.FRC)>; def : Pat<(fceil _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), - (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x2))), _.FRC)>; + (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0xa))), _.FRC)>; def : Pat<(ftrunc _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), - (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x3))), _.FRC)>; + (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0xb))), _.FRC)>; def : Pat<(frint _.FRC:$src), (COPY_TO_REGCLASS (_.VT (!cast(NAME##r) (_.VT (IMPLICIT_DEF)), (_.VT (COPY_TO_REGCLASS _.FRC:$src, _.RC)), (i32 0x4))), _.FRC)>; @@ -7281,13 +7281,13 @@ avx512_rndscale_scalar opc, string OpcodeStr, X86VectorVTInfo _> { def : Pat<(ffloor (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), - addr:$src, (i32 0x1))), _.FRC)>; + addr:$src, (i32 0x9))), _.FRC)>; def : Pat<(fceil (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), - addr:$src, (i32 0x2))), _.FRC)>; + addr:$src, (i32 0xa))), _.FRC)>; def : Pat<(ftrunc (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), - addr:$src, (i32 0x3))), _.FRC)>; + addr:$src, (i32 0xb))), _.FRC)>; def : Pat<(frint (_.ScalarLdFrag addr:$src)), (COPY_TO_REGCLASS (_.VT (!cast(NAME##m) (_.VT (IMPLICIT_DEF)), addr:$src, (i32 0x4))), _.FRC)>; @@ -7869,7 +7869,7 @@ let Predicates = [HasVLX] in { defm NAME##D##SUFF##Z128: avx512_gather, EVEX_V128; defm NAME##Q##SUFF##Z128: avx512_gather, EVEX_V128; + vx64xmem, X86mgatherv2i64>, EVEX_V128; } } @@ -8471,26 +8471,26 @@ multiclass avx512_shuff_packed_128; + (VRNDSCALEPSZrri VR512:$src, (i32 0x9))>; def : Pat<(v16f32 (fnearbyint VR512:$src)), (VRNDSCALEPSZrri VR512:$src, (i32 0xC))>; def : Pat<(v16f32 (fceil VR512:$src)), - (VRNDSCALEPSZrri VR512:$src, (i32 0x2))>; + (VRNDSCALEPSZrri VR512:$src, (i32 0xA))>; def : Pat<(v16f32 (frint VR512:$src)), (VRNDSCALEPSZrri VR512:$src, (i32 0x4))>; def : Pat<(v16f32 (ftrunc VR512:$src)), - (VRNDSCALEPSZrri VR512:$src, (i32 0x3))>; + (VRNDSCALEPSZrri VR512:$src, (i32 0xB))>; def : Pat<(v8f64 (ffloor VR512:$src)), - (VRNDSCALEPDZrri VR512:$src, (i32 0x1))>; + (VRNDSCALEPDZrri VR512:$src, (i32 0x9))>; def : Pat<(v8f64 (fnearbyint VR512:$src)), (VRNDSCALEPDZrri VR512:$src, (i32 0xC))>; def : Pat<(v8f64 (fceil VR512:$src)), - (VRNDSCALEPDZrri VR512:$src, (i32 0x2))>; + (VRNDSCALEPDZrri VR512:$src, (i32 0xA))>; def : Pat<(v8f64 (frint VR512:$src)), (VRNDSCALEPDZrri VR512:$src, (i32 0x4))>; def : Pat<(v8f64 (ftrunc VR512:$src)), - (VRNDSCALEPDZrri VR512:$src, (i32 0x3))>; + (VRNDSCALEPDZrri VR512:$src, (i32 0xB))>; } defm VSHUFF32X4 : avx512_shuff_packed_128<"vshuff32x4",avx512vl_f32_info, 0x23>, diff --git a/contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td b/contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td index c28b35b22977..8b5bbf24f6f6 100644 --- a/contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td +++ b/contrib/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td @@ -641,7 +641,7 @@ def sdmem : Operand { // SSE pattern fragments //===----------------------------------------------------------------------===// -// Vector load wrappers to prevent folding of non-temporal aligned loads on +// Vector load wrappers to prevent folding of non-temporal aligned loads on // supporting targets. def vec128load : PatFrag<(ops node:$ptr), (load node:$ptr), [{ return !Subtarget->hasSSE41() || !cast(N)->isNonTemporal() || @@ -754,16 +754,6 @@ def memopv4f32 : PatFrag<(ops node:$ptr), (v4f32 (memop node:$ptr))>; def memopv2f64 : PatFrag<(ops node:$ptr), (v2f64 (memop node:$ptr))>; def memopv2i64 : PatFrag<(ops node:$ptr), (v2i64 (memop node:$ptr))>; -// These are needed to match a scalar memop that is used in a vector-only -// math instruction such as the FP logical ops: andps, andnps, orps, xorps. -// The memory operand is required to be a 128-bit load, so it must be converted -// from a vector to a scalar. -def memopfsf32_128 : PatFrag<(ops node:$ptr), - (f32 (extractelt (memopv4f32 node:$ptr), (iPTR 0)))>; -def memopfsf64_128 : PatFrag<(ops node:$ptr), - (f64 (extractelt (memopv2f64 node:$ptr), (iPTR 0)))>; - - // SSSE3 uses MMX registers for some instructions. They aren't aligned on a // 16-byte boundary. // FIXME: 8 byte alignment for mmx reads is not required @@ -773,6 +763,9 @@ def memop64 : PatFrag<(ops node:$ptr), (load node:$ptr), [{ def memopmmx : PatFrag<(ops node:$ptr), (x86mmx (memop64 node:$ptr))>; +def X86masked_gather : SDNode<"X86ISD::MGATHER", SDTMaskedGather, + [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; + def mgatherv4i32 : PatFrag<(ops node:$src1, node:$src2, node:$src3), (masked_gather node:$src1, node:$src2, node:$src3) , [{ if (MaskedGatherSDNode *Mgt = dyn_cast(N)) @@ -796,6 +789,15 @@ def mgatherv2i64 : PatFrag<(ops node:$src1, node:$src2, node:$src3), Mgt->getBasePtr().getValueType() == MVT::v2i64); return false; }]>; +def X86mgatherv2i64 : PatFrag<(ops node:$src1, node:$src2, node:$src3), + (X86masked_gather node:$src1, node:$src2, node:$src3) , [{ + if (X86MaskedGatherSDNode *Mgt = dyn_cast(N)) + return (Mgt->getIndex().getValueType() == MVT::v2i64 || + Mgt->getBasePtr().getValueType() == MVT::v2i64) && + (Mgt->getMemoryVT() == MVT::v2i32 || + Mgt->getMemoryVT() == MVT::v2f32); + return false; +}]>; def mgatherv4i64 : PatFrag<(ops node:$src1, node:$src2, node:$src3), (masked_gather node:$src1, node:$src2, node:$src3) , [{ if (MaskedGatherSDNode *Mgt = dyn_cast(N)) diff --git a/contrib/llvm/lib/Target/X86/X86InstrSSE.td b/contrib/llvm/lib/Target/X86/X86InstrSSE.td index 8490b972eb5c..fe87bbd99473 100644 --- a/contrib/llvm/lib/Target/X86/X86InstrSSE.td +++ b/contrib/llvm/lib/Target/X86/X86InstrSSE.td @@ -1744,7 +1744,7 @@ def VCVTSD2SSrm : I<0x5A, MRMSrcMem, (outs FR32:$dst), Sched<[WriteCvtF2FLd, ReadAfterLd]>, VEX_WIG; } -def : Pat<(f32 (fpround FR64:$src)), +def : Pat<(f32 (fpround FR64:$src)), (VCVTSD2SSrr (COPY_TO_REGCLASS FR64:$src, FR32), FR64:$src)>, Requires<[UseAVX]>; diff --git a/contrib/llvm/lib/Target/X86/X86InstructionSelector.cpp b/contrib/llvm/lib/Target/X86/X86InstructionSelector.cpp index 77dead8d2413..f98c2a7e802d 100644 --- a/contrib/llvm/lib/Target/X86/X86InstructionSelector.cpp +++ b/contrib/llvm/lib/Target/X86/X86InstructionSelector.cpp @@ -72,9 +72,24 @@ class X86InstructionSelector : public InstructionSelector { MachineFunction &MF) const; bool selectCmp(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; - bool selectUadde(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; + bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const; + bool selectInsert(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF) const; + bool selectExtract(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF) const; + + // emit insert subreg instruction and insert it before MachineInstr &I + bool emitInsertSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I, + MachineRegisterInfo &MRI, MachineFunction &MF) const; + // emit extract subreg instruction and insert it before MachineInstr &I + bool emitExtractSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I, + MachineRegisterInfo &MRI, MachineFunction &MF) const; + + const TargetRegisterClass *getRegClass(LLT Ty, const RegisterBank &RB) const; + const TargetRegisterClass *getRegClass(LLT Ty, unsigned Reg, + MachineRegisterInfo &MRI) const; const X86TargetMachine &TM; const X86Subtarget &STI; @@ -113,8 +128,8 @@ X86InstructionSelector::X86InstructionSelector(const X86TargetMachine &TM, // FIXME: This should be target-independent, inferred from the types declared // for each class in the bank. -static const TargetRegisterClass * -getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) { +const TargetRegisterClass * +X86InstructionSelector::getRegClass(LLT Ty, const RegisterBank &RB) const { if (RB.getID() == X86::GPRRegBankID) { if (Ty.getSizeInBits() <= 8) return &X86::GR8RegClass; @@ -127,13 +142,13 @@ getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) { } if (RB.getID() == X86::VECRRegBankID) { if (Ty.getSizeInBits() == 32) - return &X86::FR32XRegClass; + return STI.hasAVX512() ? &X86::FR32XRegClass : &X86::FR32RegClass; if (Ty.getSizeInBits() == 64) - return &X86::FR64XRegClass; + return STI.hasAVX512() ? &X86::FR64XRegClass : &X86::FR64RegClass; if (Ty.getSizeInBits() == 128) - return &X86::VR128XRegClass; + return STI.hasAVX512() ? &X86::VR128XRegClass : &X86::VR128RegClass; if (Ty.getSizeInBits() == 256) - return &X86::VR256XRegClass; + return STI.hasAVX512() ? &X86::VR256XRegClass : &X86::VR256RegClass; if (Ty.getSizeInBits() == 512) return &X86::VR512RegClass; } @@ -141,10 +156,16 @@ getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) { llvm_unreachable("Unknown RegBank!"); } +const TargetRegisterClass * +X86InstructionSelector::getRegClass(LLT Ty, unsigned Reg, + MachineRegisterInfo &MRI) const { + const RegisterBank &RegBank = *RBI.getRegBank(Reg, MRI, TRI); + return getRegClass(Ty, RegBank); +} + // Set X86 Opcode and constrain DestReg. -static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, - MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, - const RegisterBankInfo &RBI) { +bool X86InstructionSelector::selectCopy(MachineInstr &I, + MachineRegisterInfo &MRI) const { unsigned DstReg = I.getOperand(0).getReg(); if (TargetRegisterInfo::isPhysicalRegister(DstReg)) { @@ -171,7 +192,7 @@ static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, switch (RegBank.getID()) { case X86::GPRRegBankID: assert((DstSize <= 64) && "GPRs cannot get more than 64-bit width values."); - RC = getRegClassForTypeOnBank(MRI.getType(DstReg), RegBank); + RC = getRegClass(MRI.getType(DstReg), RegBank); // Change the physical register if (SrcSize > DstSize && TargetRegisterInfo::isPhysicalRegister(SrcReg)) { @@ -186,7 +207,7 @@ static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, } break; case X86::VECRRegBankID: - RC = getRegClassForTypeOnBank(MRI.getType(DstReg), RegBank); + RC = getRegClass(MRI.getType(DstReg), RegBank); break; default: llvm_unreachable("Unknown RegBank!"); @@ -220,7 +241,7 @@ bool X86InstructionSelector::select(MachineInstr &I) const { // Certain non-generic instructions also need some special handling. if (I.isCopy()) - return selectCopy(I, TII, MRI, TRI, RBI); + return selectCopy(I, MRI); // TODO: handle more cases - LOAD_STACK_GUARD, PHI return true; @@ -249,6 +270,10 @@ bool X86InstructionSelector::select(MachineInstr &I) const { return true; if (selectUadde(I, MRI, MF)) return true; + if (selectExtract(I, MRI, MF)) + return true; + if (selectInsert(I, MRI, MF)) + return true; return false; } @@ -326,6 +351,34 @@ unsigned X86InstructionSelector::getLoadStoreOp(LLT &Ty, const RegisterBank &RB, return Opc; } +// Fill in an address from the given instruction. +void X86SelectAddress(const MachineInstr &I, const MachineRegisterInfo &MRI, + X86AddressMode &AM) { + + assert(I.getOperand(0).isReg() && "unsupported opperand."); + assert(MRI.getType(I.getOperand(0).getReg()).isPointer() && + "unsupported type."); + + if (I.getOpcode() == TargetOpcode::G_GEP) { + if (auto COff = getConstantVRegVal(I.getOperand(2).getReg(), MRI)) { + int64_t Imm = *COff; + if (isInt<32>(Imm)) { // Check for displacement overflow. + AM.Disp = static_cast(Imm); + AM.Base.Reg = I.getOperand(1).getReg(); + return; + } + } + } else if (I.getOpcode() == TargetOpcode::G_FRAME_INDEX) { + AM.Base.FrameIndex = I.getOperand(1).getIndex(); + AM.BaseType = X86AddressMode::FrameIndexBase; + return; + } + + // Default behavior. + AM.Base.Reg = I.getOperand(0).getReg(); + return; +} + bool X86InstructionSelector::selectLoadStoreOp(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const { @@ -340,18 +393,28 @@ bool X86InstructionSelector::selectLoadStoreOp(MachineInstr &I, const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI); auto &MemOp = **I.memoperands_begin(); + if (MemOp.getOrdering() != AtomicOrdering::NotAtomic) { + DEBUG(dbgs() << "Atomic load/store not supported yet\n"); + return false; + } + unsigned NewOpc = getLoadStoreOp(Ty, RB, Opc, MemOp.getAlignment()); if (NewOpc == Opc) return false; + X86AddressMode AM; + X86SelectAddress(*MRI.getVRegDef(I.getOperand(1).getReg()), MRI, AM); + I.setDesc(TII.get(NewOpc)); MachineInstrBuilder MIB(MF, I); - if (Opc == TargetOpcode::G_LOAD) - addOffset(MIB, 0); - else { + if (Opc == TargetOpcode::G_LOAD) { + I.RemoveOperand(1); + addFullAddress(MIB, AM); + } else { // G_STORE (VAL, Addr), X86Store instruction (Addr, VAL) + I.RemoveOperand(1); I.RemoveOperand(0); - addOffset(MIB, 0).addUse(DefReg); + addFullAddress(MIB, AM).addUse(DefReg); } return constrainSelectedInstRegOperands(I, TII, TRI, RBI); } @@ -461,11 +524,11 @@ bool X86InstructionSelector::selectTrunc(MachineInstr &I, if (DstRB.getID() != X86::GPRRegBankID) return false; - const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB); + const TargetRegisterClass *DstRC = getRegClass(DstTy, DstRB); if (!DstRC) return false; - const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB); + const TargetRegisterClass *SrcRC = getRegClass(SrcTy, SrcRB); if (!SrcRC) return false; @@ -519,9 +582,8 @@ bool X86InstructionSelector::selectZext(MachineInstr &I, else return false; - const RegisterBank &RegBank = *RBI.getRegBank(DstReg, MRI, TRI); unsigned DefReg = - MRI.createVirtualRegister(getRegClassForTypeOnBank(DstTy, RegBank)); + MRI.createVirtualRegister(getRegClass(DstTy, DstReg, MRI)); BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::SUBREG_TO_REG), DefReg) @@ -656,6 +718,202 @@ bool X86InstructionSelector::selectUadde(MachineInstr &I, return true; } +bool X86InstructionSelector::selectExtract(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + + if (I.getOpcode() != TargetOpcode::G_EXTRACT) + return false; + + const unsigned DstReg = I.getOperand(0).getReg(); + const unsigned SrcReg = I.getOperand(1).getReg(); + int64_t Index = I.getOperand(2).getImm(); + + const LLT DstTy = MRI.getType(DstReg); + const LLT SrcTy = MRI.getType(SrcReg); + + // Meanwile handle vector type only. + if (!DstTy.isVector()) + return false; + + if (Index % DstTy.getSizeInBits() != 0) + return false; // Not extract subvector. + + if (Index == 0) { + // Replace by extract subreg copy. + if (!emitExtractSubreg(DstReg, SrcReg, I, MRI, MF)) + return false; + + I.eraseFromParent(); + return true; + } + + bool HasAVX = STI.hasAVX(); + bool HasAVX512 = STI.hasAVX512(); + bool HasVLX = STI.hasVLX(); + + if (SrcTy.getSizeInBits() == 256 && DstTy.getSizeInBits() == 128) { + if (HasVLX) + I.setDesc(TII.get(X86::VEXTRACTF32x4Z256rr)); + else if (HasAVX) + I.setDesc(TII.get(X86::VEXTRACTF128rr)); + else + return false; + } else if (SrcTy.getSizeInBits() == 512 && HasAVX512) { + if (DstTy.getSizeInBits() == 128) + I.setDesc(TII.get(X86::VEXTRACTF32x4Zrr)); + else if (DstTy.getSizeInBits() == 256) + I.setDesc(TII.get(X86::VEXTRACTF64x4Zrr)); + else + return false; + } else + return false; + + // Convert to X86 VEXTRACT immediate. + Index = Index / DstTy.getSizeInBits(); + I.getOperand(2).setImm(Index); + + return constrainSelectedInstRegOperands(I, TII, TRI, RBI); +} + +bool X86InstructionSelector::emitExtractSubreg(unsigned DstReg, unsigned SrcReg, + MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + + const LLT DstTy = MRI.getType(DstReg); + const LLT SrcTy = MRI.getType(SrcReg); + unsigned SubIdx = X86::NoSubRegister; + + if (!DstTy.isVector() || !SrcTy.isVector()) + return false; + + assert(SrcTy.getSizeInBits() > DstTy.getSizeInBits() && + "Incorrect Src/Dst register size"); + + if (DstTy.getSizeInBits() == 128) + SubIdx = X86::sub_xmm; + else if (DstTy.getSizeInBits() == 256) + SubIdx = X86::sub_ymm; + else + return false; + + const TargetRegisterClass *DstRC = getRegClass(DstTy, DstReg, MRI); + const TargetRegisterClass *SrcRC = getRegClass(SrcTy, SrcReg, MRI); + + SrcRC = TRI.getSubClassWithSubReg(SrcRC, SubIdx); + + if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) || + !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { + DEBUG(dbgs() << "Failed to constrain G_TRUNC\n"); + return false; + } + + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), DstReg) + .addReg(SrcReg, 0, SubIdx); + + return true; +} + +bool X86InstructionSelector::emitInsertSubreg(unsigned DstReg, unsigned SrcReg, + MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + + const LLT DstTy = MRI.getType(DstReg); + const LLT SrcTy = MRI.getType(SrcReg); + unsigned SubIdx = X86::NoSubRegister; + + // TODO: support scalar types + if (!DstTy.isVector() || !SrcTy.isVector()) + return false; + + assert(SrcTy.getSizeInBits() < DstTy.getSizeInBits() && + "Incorrect Src/Dst register size"); + + if (SrcTy.getSizeInBits() == 128) + SubIdx = X86::sub_xmm; + else if (SrcTy.getSizeInBits() == 256) + SubIdx = X86::sub_ymm; + else + return false; + + const TargetRegisterClass *SrcRC = getRegClass(SrcTy, SrcReg, MRI); + const TargetRegisterClass *DstRC = getRegClass(DstTy, DstReg, MRI); + + if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) || + !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { + DEBUG(dbgs() << "Failed to constrain INSERT_SUBREG\n"); + return false; + } + + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY)) + .addReg(DstReg, RegState::DefineNoRead, SubIdx) + .addReg(SrcReg); + + return true; +} + +bool X86InstructionSelector::selectInsert(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + + if (I.getOpcode() != TargetOpcode::G_INSERT) + return false; + + const unsigned DstReg = I.getOperand(0).getReg(); + const unsigned SrcReg = I.getOperand(1).getReg(); + const unsigned InsertReg = I.getOperand(2).getReg(); + int64_t Index = I.getOperand(3).getImm(); + + const LLT DstTy = MRI.getType(DstReg); + const LLT InsertRegTy = MRI.getType(InsertReg); + + // Meanwile handle vector type only. + if (!DstTy.isVector()) + return false; + + if (Index % InsertRegTy.getSizeInBits() != 0) + return false; // Not insert subvector. + + if (Index == 0 && MRI.getVRegDef(SrcReg)->isImplicitDef()) { + // Replace by subreg copy. + if (!emitInsertSubreg(DstReg, InsertReg, I, MRI, MF)) + return false; + + I.eraseFromParent(); + return true; + } + + bool HasAVX = STI.hasAVX(); + bool HasAVX512 = STI.hasAVX512(); + bool HasVLX = STI.hasVLX(); + + if (DstTy.getSizeInBits() == 256 && InsertRegTy.getSizeInBits() == 128) { + if (HasVLX) + I.setDesc(TII.get(X86::VINSERTF32x4Z256rr)); + else if (HasAVX) + I.setDesc(TII.get(X86::VINSERTF128rr)); + else + return false; + } else if (DstTy.getSizeInBits() == 512 && HasAVX512) { + if (InsertRegTy.getSizeInBits() == 128) + I.setDesc(TII.get(X86::VINSERTF32x4Zrr)); + else if (InsertRegTy.getSizeInBits() == 256) + I.setDesc(TII.get(X86::VINSERTF64x4Zrr)); + else + return false; + } else + return false; + + // Convert to X86 VINSERT immediate. + Index = Index / InsertRegTy.getSizeInBits(); + + I.getOperand(3).setImm(Index); + + return constrainSelectedInstRegOperands(I, TII, TRI, RBI); +} + InstructionSelector * llvm::createX86InstructionSelector(const X86TargetMachine &TM, X86Subtarget &Subtarget, diff --git a/contrib/llvm/lib/Target/X86/X86InterleavedAccess.cpp b/contrib/llvm/lib/Target/X86/X86InterleavedAccess.cpp index 806d6cc888f0..f0ed4bc16e2f 100644 --- a/contrib/llvm/lib/Target/X86/X86InterleavedAccess.cpp +++ b/contrib/llvm/lib/Target/X86/X86InterleavedAccess.cpp @@ -16,6 +16,7 @@ #include "X86ISelLowering.h" #include "X86TargetMachine.h" +#include "llvm/Analysis/VectorUtils.h" using namespace llvm; @@ -50,9 +51,8 @@ class X86InterleavedAccessGroup { IRBuilder<> &Builder; /// \brief Breaks down a vector \p 'Inst' of N elements into \p NumSubVectors - /// sub vectors of type \p T. Returns true and the sub-vectors in - /// \p DecomposedVectors if it decomposes the Inst, returns false otherwise. - bool decompose(Instruction *Inst, unsigned NumSubVectors, VectorType *T, + /// sub vectors of type \p T. Returns the sub-vectors in \p DecomposedVectors. + void decompose(Instruction *Inst, unsigned NumSubVectors, VectorType *T, SmallVectorImpl &DecomposedVectors); /// \brief Performs matrix transposition on a 4x4 matrix \p InputVectors and @@ -80,8 +80,7 @@ class X86InterleavedAccessGroup { /// target information \p STarget. explicit X86InterleavedAccessGroup(Instruction *I, ArrayRef Shuffs, - ArrayRef Ind, - const unsigned F, + ArrayRef Ind, const unsigned F, const X86Subtarget &STarget, IRBuilder<> &B) : Inst(I), Shuffles(Shuffs), Indices(Ind), Factor(F), Subtarget(STarget), @@ -102,48 +101,61 @@ bool X86InterleavedAccessGroup::isSupported() const { uint64_t ShuffleVecSize = DL.getTypeSizeInBits(ShuffleVecTy); Type *ShuffleEltTy = ShuffleVecTy->getVectorElementType(); - if (DL.getTypeSizeInBits(Inst->getType()) < Factor * ShuffleVecSize) - return false; + // Currently, lowering is supported for 4-element vectors of 64 bits on AVX. + uint64_t ExpectedShuffleVecSize; + if (isa(Inst)) + ExpectedShuffleVecSize = 256; + else + ExpectedShuffleVecSize = 1024; - // Currently, lowering is supported for 64 bits on AVX. - if (!Subtarget.hasAVX() || ShuffleVecSize != 256 || + if (!Subtarget.hasAVX() || ShuffleVecSize != ExpectedShuffleVecSize || DL.getTypeSizeInBits(ShuffleEltTy) != 64 || Factor != 4) return false; return true; } -bool X86InterleavedAccessGroup::decompose( +void X86InterleavedAccessGroup::decompose( Instruction *VecInst, unsigned NumSubVectors, VectorType *SubVecTy, SmallVectorImpl &DecomposedVectors) { + + assert((isa(VecInst) || isa(VecInst)) && + "Expected Load or Shuffle"); + Type *VecTy = VecInst->getType(); (void)VecTy; assert(VecTy->isVectorTy() && DL.getTypeSizeInBits(VecTy) >= DL.getTypeSizeInBits(SubVecTy) * NumSubVectors && "Invalid Inst-size!!!"); - assert(VecTy->getVectorElementType() == SubVecTy->getVectorElementType() && - "Element type mismatched!!!"); - if (!isa(VecInst)) - return false; + if (auto *SVI = dyn_cast(VecInst)) { + Value *Op0 = SVI->getOperand(0); + Value *Op1 = SVI->getOperand(1); + // Generate N(= NumSubVectors) shuffles of T(= SubVecTy) type. + for (unsigned i = 0; i < NumSubVectors; ++i) + DecomposedVectors.push_back( + cast(Builder.CreateShuffleVector( + Op0, Op1, createSequentialMask(Builder, Indices[i], + SubVecTy->getVectorNumElements(), 0)))); + return; + } + + // Decompose the load instruction. LoadInst *LI = cast(VecInst); Type *VecBasePtrTy = SubVecTy->getPointerTo(LI->getPointerAddressSpace()); - Value *VecBasePtr = Builder.CreateBitCast(LI->getPointerOperand(), VecBasePtrTy); - // Generate N loads of T type + // Generate N loads of T type. for (unsigned i = 0; i < NumSubVectors; i++) { - // TODO: Support inbounds GEP + // TODO: Support inbounds GEP. Value *NewBasePtr = Builder.CreateGEP(VecBasePtr, Builder.getInt32(i)); Instruction *NewLoad = Builder.CreateAlignedLoad(NewBasePtr, LI->getAlignment()); DecomposedVectors.push_back(NewLoad); } - - return true; } void X86InterleavedAccessGroup::transpose_4x4( @@ -181,21 +193,46 @@ void X86InterleavedAccessGroup::transpose_4x4( // instructions/intrinsics. bool X86InterleavedAccessGroup::lowerIntoOptimizedSequence() { SmallVector DecomposedVectors; - VectorType *VecTy = Shuffles[0]->getType(); - // Try to generate target-sized register(/instruction). - if (!decompose(Inst, Factor, VecTy, DecomposedVectors)) - return false; - SmallVector TransposedVectors; - // Perform matrix-transposition in order to compute interleaved - // results by generating some sort of (optimized) target-specific - // instructions. + VectorType *ShuffleTy = Shuffles[0]->getType(); + + if (isa(Inst)) { + // Try to generate target-sized register(/instruction). + decompose(Inst, Factor, ShuffleTy, DecomposedVectors); + + // Perform matrix-transposition in order to compute interleaved + // results by generating some sort of (optimized) target-specific + // instructions. + transpose_4x4(DecomposedVectors, TransposedVectors); + + // Now replace the unoptimized-interleaved-vectors with the + // transposed-interleaved vectors. + for (unsigned i = 0, e = Shuffles.size(); i < e; ++i) + Shuffles[i]->replaceAllUsesWith(TransposedVectors[Indices[i]]); + + return true; + } + + Type *ShuffleEltTy = ShuffleTy->getVectorElementType(); + unsigned NumSubVecElems = ShuffleTy->getVectorNumElements() / Factor; + + // Lower the interleaved stores: + // 1. Decompose the interleaved wide shuffle into individual shuffle + // vectors. + decompose(Shuffles[0], Factor, + VectorType::get(ShuffleEltTy, NumSubVecElems), DecomposedVectors); + + // 2. Transpose the interleaved-vectors into vectors of contiguous + // elements. transpose_4x4(DecomposedVectors, TransposedVectors); - // Now replace the unoptimized-interleaved-vectors with the - // transposed-interleaved vectors. - for (unsigned i = 0; i < Shuffles.size(); i++) - Shuffles[i]->replaceAllUsesWith(TransposedVectors[Indices[i]]); + // 3. Concatenate the contiguous-vectors back into a wide vector. + Value *WideVec = concatenateVectors(Builder, TransposedVectors); + + // 4. Generate a store instruction for wide-vec. + StoreInst *SI = cast(Inst); + Builder.CreateAlignedStore(WideVec, SI->getPointerOperand(), + SI->getAlignment()); return true; } @@ -220,3 +257,29 @@ bool X86TargetLowering::lowerInterleavedLoad( return Grp.isSupported() && Grp.lowerIntoOptimizedSequence(); } + +bool X86TargetLowering::lowerInterleavedStore(StoreInst *SI, + ShuffleVectorInst *SVI, + unsigned Factor) const { + assert(Factor >= 2 && Factor <= getMaxSupportedInterleaveFactor() && + "Invalid interleave factor"); + + assert(SVI->getType()->getVectorNumElements() % Factor == 0 && + "Invalid interleaved store"); + + // Holds the indices of SVI that correspond to the starting index of each + // interleaved shuffle. + SmallVector Indices; + auto Mask = SVI->getShuffleMask(); + for (unsigned i = 0; i < Factor; i++) + Indices.push_back(Mask[i]); + + ArrayRef Shuffles = makeArrayRef(SVI); + + // Create an interleaved access group. + IRBuilder<> Builder(SI); + X86InterleavedAccessGroup Grp(SI, Shuffles, Indices, Factor, Subtarget, + Builder); + + return Grp.isSupported() && Grp.lowerIntoOptimizedSequence(); +} diff --git a/contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h b/contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h index bc73bb1ae8c5..6b1add8ff8ed 100644 --- a/contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h +++ b/contrib/llvm/lib/Target/X86/X86IntrinsicsInfo.h @@ -510,12 +510,6 @@ static const IntrinsicData IntrinsicsWithoutChain[] = { X86ISD::SHUF128, 0), X86_INTRINSIC_DATA(avx512_mask_broadcasti64x4_512, BRCST_SUBVEC_TO_VEC, X86ISD::SHUF128, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_b_128, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_b_256, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_b_512, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_d_128, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_d_256, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_d_512, CMP_MASK_CC, X86ISD::CMPM, 0), X86_INTRINSIC_DATA(avx512_mask_cmp_pd_128, CMP_MASK_CC, X86ISD::CMPM, 0), X86_INTRINSIC_DATA(avx512_mask_cmp_pd_256, CMP_MASK_CC, X86ISD::CMPM, 0), X86_INTRINSIC_DATA(avx512_mask_cmp_pd_512, CMP_MASK_CC, X86ISD::CMPM, @@ -524,16 +518,10 @@ static const IntrinsicData IntrinsicsWithoutChain[] = { X86_INTRINSIC_DATA(avx512_mask_cmp_ps_256, CMP_MASK_CC, X86ISD::CMPM, 0), X86_INTRINSIC_DATA(avx512_mask_cmp_ps_512, CMP_MASK_CC, X86ISD::CMPM, X86ISD::CMPM_RND), - X86_INTRINSIC_DATA(avx512_mask_cmp_q_128, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_q_256, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_q_512, CMP_MASK_CC, X86ISD::CMPM, 0), X86_INTRINSIC_DATA(avx512_mask_cmp_sd, CMP_MASK_SCALAR_CC, X86ISD::FSETCCM, X86ISD::FSETCCM_RND), X86_INTRINSIC_DATA(avx512_mask_cmp_ss, CMP_MASK_SCALAR_CC, X86ISD::FSETCCM, X86ISD::FSETCCM_RND), - X86_INTRINSIC_DATA(avx512_mask_cmp_w_128, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_w_256, CMP_MASK_CC, X86ISD::CMPM, 0), - X86_INTRINSIC_DATA(avx512_mask_cmp_w_512, CMP_MASK_CC, X86ISD::CMPM, 0), X86_INTRINSIC_DATA(avx512_mask_compress_d_128, COMPRESS_EXPAND_IN_REG, X86ISD::COMPRESS, 0), X86_INTRINSIC_DATA(avx512_mask_compress_d_256, COMPRESS_EXPAND_IN_REG, @@ -1171,18 +1159,6 @@ static const IntrinsicData IntrinsicsWithoutChain[] = { X86ISD::FSUBS_RND, 0), X86_INTRINSIC_DATA(avx512_mask_sub_ss_round, INTR_TYPE_SCALAR_MASK_RM, X86ISD::FSUBS_RND, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_b_128, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_b_256, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_b_512, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_d_128, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_d_256, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_d_512, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_q_128, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_q_256, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_q_512, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_w_128, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_w_256, CMP_MASK_CC, X86ISD::CMPMU, 0), - X86_INTRINSIC_DATA(avx512_mask_ucmp_w_512, CMP_MASK_CC, X86ISD::CMPMU, 0), X86_INTRINSIC_DATA(avx512_mask_vcvtph2ps_128, INTR_TYPE_1OP_MASK_RM, X86ISD::CVTPH2PS, 0), X86_INTRINSIC_DATA(avx512_mask_vcvtph2ps_256, INTR_TYPE_1OP_MASK_RM, diff --git a/contrib/llvm/lib/Target/X86/X86LegalizerInfo.cpp b/contrib/llvm/lib/Target/X86/X86LegalizerInfo.cpp index 979aaee110aa..a584eabcc1b2 100644 --- a/contrib/llvm/lib/Target/X86/X86LegalizerInfo.cpp +++ b/contrib/llvm/lib/Target/X86/X86LegalizerInfo.cpp @@ -214,12 +214,24 @@ void X86LegalizerInfo::setLegalizerInfoAVX() { if (!Subtarget.hasAVX()) return; + const LLT v16s8 = LLT::vector(16, 8); + const LLT v8s16 = LLT::vector(8, 16); + const LLT v4s32 = LLT::vector(4, 32); + const LLT v2s64 = LLT::vector(2, 64); + + const LLT v32s8 = LLT::vector(32, 8); + const LLT v16s16 = LLT::vector(16, 16); const LLT v8s32 = LLT::vector(8, 32); const LLT v4s64 = LLT::vector(4, 64); for (unsigned MemOp : {G_LOAD, G_STORE}) for (auto Ty : {v8s32, v4s64}) setAction({MemOp, Ty}, Legal); + + for (auto Ty : {v32s8, v16s16, v8s32, v4s64}) + setAction({G_INSERT, Ty}, Legal); + for (auto Ty : {v16s8, v8s16, v4s32, v2s64}) + setAction({G_INSERT, 1, Ty}, Legal); } void X86LegalizerInfo::setLegalizerInfoAVX2() { @@ -243,6 +255,18 @@ void X86LegalizerInfo::setLegalizerInfoAVX512() { if (!Subtarget.hasAVX512()) return; + const LLT v16s8 = LLT::vector(16, 8); + const LLT v8s16 = LLT::vector(8, 16); + const LLT v4s32 = LLT::vector(4, 32); + const LLT v2s64 = LLT::vector(2, 64); + + const LLT v32s8 = LLT::vector(32, 8); + const LLT v16s16 = LLT::vector(16, 16); + const LLT v8s32 = LLT::vector(8, 32); + const LLT v4s64 = LLT::vector(4, 64); + + const LLT v64s8 = LLT::vector(64, 8); + const LLT v32s16 = LLT::vector(32, 16); const LLT v16s32 = LLT::vector(16, 32); const LLT v8s64 = LLT::vector(8, 64); @@ -256,13 +280,15 @@ void X86LegalizerInfo::setLegalizerInfoAVX512() { for (auto Ty : {v16s32, v8s64}) setAction({MemOp, Ty}, Legal); + for (auto Ty : {v64s8, v32s16, v16s32, v8s64}) + setAction({G_INSERT, Ty}, Legal); + for (auto Ty : {v32s8, v16s16, v8s32, v4s64, v16s8, v8s16, v4s32, v2s64}) + setAction({G_INSERT, 1, Ty}, Legal); + /************ VLX *******************/ if (!Subtarget.hasVLX()) return; - const LLT v4s32 = LLT::vector(4, 32); - const LLT v8s32 = LLT::vector(8, 32); - for (auto Ty : {v4s32, v8s32}) setAction({G_MUL, Ty}, Legal); } diff --git a/contrib/llvm/lib/Target/X86/X86MacroFusion.cpp b/contrib/llvm/lib/Target/X86/X86MacroFusion.cpp index dd21e2b7c4a1..8fdf10617059 100644 --- a/contrib/llvm/lib/Target/X86/X86MacroFusion.cpp +++ b/contrib/llvm/lib/Target/X86/X86MacroFusion.cpp @@ -2,39 +2,31 @@ // // The LLVM Compiler Infrastructure // -// \file This file is distributed under the University of Illinois Open Source +// This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // -// This file contains the X86 implementation of the DAG scheduling mutation to -// pair instructions back to back. +/// \file This file contains the X86 implementation of the DAG scheduling +/// mutation to pair instructions back to back. // //===----------------------------------------------------------------------===// #include "X86MacroFusion.h" #include "X86Subtarget.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Target/TargetInstrInfo.h" - -#define DEBUG_TYPE "misched" - -STATISTIC(NumFused, "Number of instr pairs fused"); +#include "llvm/CodeGen/MacroFusion.h" using namespace llvm; -static cl::opt EnableMacroFusion("x86-misched-fusion", cl::Hidden, - cl::desc("Enable scheduling for macro fusion."), cl::init(true)); - -namespace { - -/// \brief Verify that the instruction pair, First and Second, -/// should be scheduled back to back. If either instruction is unspecified, -/// then verify that the other instruction may be part of a pair at all. -static bool shouldScheduleAdjacent(const X86Subtarget &ST, - const MachineInstr *First, - const MachineInstr *Second) { +/// \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. +static bool shouldScheduleAdjacent(const TargetInstrInfo &TII, + const TargetSubtargetInfo &TSI, + const MachineInstr *FirstMI, + const MachineInstr &SecondMI) { + const X86Subtarget &ST = static_cast(TSI); // Check if this processor supports macro-fusion. Since this is a minor // heuristic, we haven't specifically reserved a feature. hasAVX is a decent // proxy for SandyBridge+. @@ -47,13 +39,10 @@ static bool shouldScheduleAdjacent(const X86Subtarget &ST, FuseInc } FuseKind; - assert((First || Second) && "At least one instr must be specified"); - unsigned FirstOpcode = First - ? First->getOpcode() + unsigned FirstOpcode = FirstMI + ? FirstMI->getOpcode() : static_cast(X86::INSTRUCTION_LIST_END); - unsigned SecondOpcode = Second - ? Second->getOpcode() - : static_cast(X86::INSTRUCTION_LIST_END); + unsigned SecondOpcode = SecondMI.getOpcode(); switch (SecondOpcode) { default: @@ -203,69 +192,11 @@ static bool shouldScheduleAdjacent(const X86Subtarget &ST, } } -/// \brief Post-process the DAG to create cluster edges between instructions -/// that may be fused by the processor into a single operation. -class X86MacroFusion : public ScheduleDAGMutation { -public: - X86MacroFusion() {} - - void apply(ScheduleDAGInstrs *DAGInstrs) override; -}; - -void X86MacroFusion::apply(ScheduleDAGInstrs *DAGInstrs) { - ScheduleDAGMI *DAG = static_cast(DAGInstrs); - const X86Subtarget &ST = DAG->MF.getSubtarget(); - - // For now, assume targets can only fuse with the branch. - SUnit &ExitSU = DAG->ExitSU; - MachineInstr *Branch = ExitSU.getInstr(); - if (!Branch || !shouldScheduleAdjacent(ST, nullptr, Branch)) - return; - - for (SDep &PredDep : ExitSU.Preds) { - if (PredDep.isWeak()) - continue; - SUnit &SU = *PredDep.getSUnit(); - MachineInstr &Pred = *SU.getInstr(); - if (!shouldScheduleAdjacent(ST, &Pred, Branch)) - continue; - - // Create a single weak edge from SU to ExitSU. The only effect is to cause - // bottom-up scheduling to heavily prioritize the clustered SU. There is no - // need to copy predecessor edges from ExitSU to SU, since top-down - // scheduling cannot prioritize ExitSU anyway. To defer top-down scheduling - // of SU, we could create an artificial edge from the deepest root, but it - // hasn't been needed yet. - bool Success = DAG->addEdge(&ExitSU, SDep(&SU, SDep::Cluster)); - (void)Success; - assert(Success && "No DAG nodes should be reachable from ExitSU"); - - // Adjust latency of data deps between the nodes. - for (SDep &PredDep : ExitSU.Preds) - if (PredDep.getSUnit() == &SU) - PredDep.setLatency(0); - for (SDep &SuccDep : SU.Succs) - if (SuccDep.getSUnit() == &ExitSU) - SuccDep.setLatency(0); - - ++NumFused; - DEBUG(dbgs() << DAG->MF.getName() << "(): Macro fuse "; - SU.print(dbgs(), DAG); - dbgs() << " - ExitSU" - << " / " << DAG->TII->getName(Pred.getOpcode()) << " - " - << DAG->TII->getName(Branch->getOpcode()) << '\n';); - - break; - } -} - -} // end namespace - namespace llvm { std::unique_ptr createX86MacroFusionDAGMutation () { - return EnableMacroFusion ? make_unique() : nullptr; + return createBranchMacroFusionDAGMutation(shouldScheduleAdjacent); } } // end namespace llvm diff --git a/contrib/llvm/lib/Target/X86/X86MacroFusion.h b/contrib/llvm/lib/Target/X86/X86MacroFusion.h index e630f802e8e6..13fa2d78a018 100644 --- a/contrib/llvm/lib/Target/X86/X86MacroFusion.h +++ b/contrib/llvm/lib/Target/X86/X86MacroFusion.h @@ -2,23 +2,18 @@ // // The LLVM Compiler Infrastructure // -// \file This file is distributed under the University of Illinois Open Source +// This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // -// This file contains the X86 definition of the DAG scheduling mutation to pair -// instructions back to back. +/// \file This file contains the X86 definition of the DAG scheduling mutation +/// to pair instructions back to back. // //===----------------------------------------------------------------------===// -#include "X86InstrInfo.h" #include "llvm/CodeGen/MachineScheduler.h" -//===----------------------------------------------------------------------===// -// X86MacroFusion - DAG post-processing to encourage fusion of macro ops. -//===----------------------------------------------------------------------===// - namespace llvm { /// Note that you have to add: diff --git a/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp b/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp index 278b57eb00b7..a9f42cacf788 100644 --- a/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp +++ b/contrib/llvm/lib/Target/X86/X86TargetMachine.cpp @@ -91,6 +91,8 @@ static std::unique_ptr createTLOF(const Triple &TT) { return llvm::make_unique(); if (TT.isOSLinux() || TT.isOSNaCl() || TT.isOSIAMCU()) return llvm::make_unique(); + if (TT.isOSSolaris()) + return llvm::make_unique(); if (TT.isOSFuchsia()) return llvm::make_unique(); if (TT.isOSBinFormatELF()) diff --git a/contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp b/contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp index 4fd95717478e..8627c06d4431 100644 --- a/contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp +++ b/contrib/llvm/lib/Target/X86/X86TargetObjectFile.cpp @@ -86,6 +86,12 @@ X86LinuxNaClTargetObjectFile::Initialize(MCContext &Ctx, InitializeELF(TM.Options.UseInitArray); } +void X86SolarisTargetObjectFile::Initialize(MCContext &Ctx, + const TargetMachine &TM) { + TargetLoweringObjectFileELF::Initialize(Ctx, TM); + InitializeELF(TM.Options.UseInitArray); +} + const MCExpr *X86WindowsTargetObjectFile::lowerRelativeReference( const GlobalValue *LHS, const GlobalValue *RHS, const TargetMachine &TM) const { diff --git a/contrib/llvm/lib/Target/X86/X86TargetObjectFile.h b/contrib/llvm/lib/Target/X86/X86TargetObjectFile.h index 39d2e84e5ed7..f6aa570b6332 100644 --- a/contrib/llvm/lib/Target/X86/X86TargetObjectFile.h +++ b/contrib/llvm/lib/Target/X86/X86TargetObjectFile.h @@ -66,6 +66,11 @@ namespace llvm { void Initialize(MCContext &Ctx, const TargetMachine &TM) override; }; + /// \brief This implementation is used for Solaris on x86/x86-64. + class X86SolarisTargetObjectFile : public X86ELFTargetObjectFile { + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; + }; + /// \brief This implementation is used for Windows targets on x86 and x86-64. class X86WindowsTargetObjectFile : public TargetLoweringObjectFileCOFF { const MCExpr * diff --git a/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp b/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp index 11ba7025e1b7..5ba8534d32d3 100644 --- a/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp +++ b/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.cpp @@ -2178,17 +2178,6 @@ int X86TTIImpl::getGatherScatterOpCost(unsigned Opcode, Type *SrcVTy, return getGSVectorCost(Opcode, SrcVTy, Ptr, Alignment, AddressSpace); } -bool X86TTIImpl::isLSRCostLess(TargetTransformInfo::LSRCost &C1, - TargetTransformInfo::LSRCost &C2) { - // X86 specific here are "instruction number 1st priority". - return std::tie(C1.Insns, C1.NumRegs, C1.AddRecCost, - C1.NumIVMuls, C1.NumBaseAdds, - C1.ScaleCost, C1.ImmCost, C1.SetupCost) < - std::tie(C2.Insns, C2.NumRegs, C2.AddRecCost, - C2.NumIVMuls, C2.NumBaseAdds, - C2.ScaleCost, C2.ImmCost, C2.SetupCost); -} - bool X86TTIImpl::isLegalMaskedLoad(Type *DataTy) { Type *ScalarTy = DataTy->getScalarType(); int DataWidth = isa(ScalarTy) ? @@ -2243,6 +2232,12 @@ bool X86TTIImpl::areInlineCompatible(const Function *Caller, return (CallerBits & CalleeBits) == CalleeBits; } +bool X86TTIImpl::expandMemCmp(Instruction *I, unsigned &MaxLoadSize) { + // TODO: We can increase these based on available vector ops. + MaxLoadSize = ST->is64Bit() ? 8 : 4; + return true; +} + bool X86TTIImpl::enableInterleavedAccessVectorization() { // TODO: We expect this to be beneficial regardless of arch, // but there are currently some unexplained performance artifacts on Atom. @@ -2250,6 +2245,114 @@ bool X86TTIImpl::enableInterleavedAccessVectorization() { return !(ST->isAtom()); } +// Get estimation for interleaved load/store operations for AVX2. +// \p Factor is the interleaved-access factor (stride) - number of +// (interleaved) elements in the group. +// \p Indices contains the indices for a strided load: when the +// interleaved load has gaps they indicate which elements are used. +// If Indices is empty (or if the number of indices is equal to the size +// of the interleaved-access as given in \p Factor) the access has no gaps. +// +// As opposed to AVX-512, AVX2 does not have generic shuffles that allow +// computing the cost using a generic formula as a function of generic +// shuffles. We therefore use a lookup table instead, filled according to +// the instruction sequences that codegen currently generates. +int X86TTIImpl::getInterleavedMemoryOpCostAVX2(unsigned Opcode, Type *VecTy, + unsigned Factor, + ArrayRef Indices, + unsigned Alignment, + unsigned AddressSpace) { + + // We currently Support only fully-interleaved groups, with no gaps. + // TODO: Support also strided loads (interleaved-groups with gaps). + if (Indices.size() && Indices.size() != Factor) + return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices, + Alignment, AddressSpace); + + // VecTy for interleave memop is . + // So, for VF=4, Interleave Factor = 3, Element type = i32 we have + // VecTy = <12 x i32>. + MVT LegalVT = getTLI()->getTypeLegalizationCost(DL, VecTy).second; + + // This function can be called with VecTy=<6xi128>, Factor=3, in which case + // the VF=2, while v2i128 is an unsupported MVT vector type + // (see MachineValueType.h::getVectorVT()). + if (!LegalVT.isVector()) + return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices, + Alignment, AddressSpace); + + unsigned VF = VecTy->getVectorNumElements() / Factor; + Type *ScalarTy = VecTy->getVectorElementType(); + + // Calculate the number of memory operations (NumOfMemOps), required + // for load/store the VecTy. + unsigned VecTySize = DL.getTypeStoreSize(VecTy); + unsigned LegalVTSize = LegalVT.getStoreSize(); + unsigned NumOfMemOps = (VecTySize + LegalVTSize - 1) / LegalVTSize; + + // Get the cost of one memory operation. + Type *SingleMemOpTy = VectorType::get(VecTy->getVectorElementType(), + LegalVT.getVectorNumElements()); + unsigned MemOpCost = + getMemoryOpCost(Opcode, SingleMemOpTy, Alignment, AddressSpace); + + VectorType *VT = VectorType::get(ScalarTy, VF); + EVT ETy = TLI->getValueType(DL, VT); + if (!ETy.isSimple()) + return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices, + Alignment, AddressSpace); + + // TODO: Complete for other data-types and strides. + // Each combination of Stride, ElementTy and VF results in a different + // sequence; The cost tables are therefore accessed with: + // Factor (stride) and VectorType=VFxElemType. + // The Cost accounts only for the shuffle sequence; + // The cost of the loads/stores is accounted for separately. + // + static const CostTblEntry AVX2InterleavedLoadTbl[] = { + { 3, MVT::v2i8, 10 }, //(load 6i8 and) deinterleave into 3 x 2i8 + { 3, MVT::v4i8, 4 }, //(load 12i8 and) deinterleave into 3 x 4i8 + { 3, MVT::v8i8, 9 }, //(load 24i8 and) deinterleave into 3 x 8i8 + { 3, MVT::v16i8, 18}, //(load 48i8 and) deinterleave into 3 x 16i8 + { 3, MVT::v32i8, 42 }, //(load 96i8 and) deinterleave into 3 x 32i8 + + { 4, MVT::v2i8, 12 }, //(load 8i8 and) deinterleave into 4 x 2i8 + { 4, MVT::v4i8, 4 }, //(load 16i8 and) deinterleave into 4 x 4i8 + { 4, MVT::v8i8, 20 }, //(load 32i8 and) deinterleave into 4 x 8i8 + { 4, MVT::v16i8, 39 }, //(load 64i8 and) deinterleave into 4 x 16i8 + { 4, MVT::v32i8, 80 } //(load 128i8 and) deinterleave into 4 x 32i8 + }; + + static const CostTblEntry AVX2InterleavedStoreTbl[] = { + { 3, MVT::v2i8, 7 }, //interleave 3 x 2i8 into 6i8 (and store) + { 3, MVT::v4i8, 8 }, //interleave 3 x 4i8 into 12i8 (and store) + { 3, MVT::v8i8, 11 }, //interleave 3 x 8i8 into 24i8 (and store) + { 3, MVT::v16i8, 17 }, //interleave 3 x 16i8 into 48i8 (and store) + { 3, MVT::v32i8, 32 }, //interleave 3 x 32i8 into 96i8 (and store) + + { 4, MVT::v2i8, 12 }, //interleave 4 x 2i8 into 8i8 (and store) + { 4, MVT::v4i8, 9 }, //interleave 4 x 4i8 into 16i8 (and store) + { 4, MVT::v8i8, 16 }, //interleave 4 x 8i8 into 32i8 (and store) + { 4, MVT::v16i8, 20 }, //interleave 4 x 16i8 into 64i8 (and store) + { 4, MVT::v32i8, 40 } //interleave 4 x 32i8 into 128i8 (and store) + }; + + if (Opcode == Instruction::Load) { + if (const auto *Entry = + CostTableLookup(AVX2InterleavedLoadTbl, Factor, ETy.getSimpleVT())) + return NumOfMemOps * MemOpCost + Entry->Cost; + } else { + assert(Opcode == Instruction::Store && + "Expected Store Instruction at this point"); + if (const auto *Entry = + CostTableLookup(AVX2InterleavedStoreTbl, Factor, ETy.getSimpleVT())) + return NumOfMemOps * MemOpCost + Entry->Cost; + } + + return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices, + Alignment, AddressSpace); +} + // Get estimation for interleaved load/store operations and strided load. // \p Indices contains indices for strided load. // \p Factor - the factor of interleaving. @@ -2358,6 +2461,10 @@ int X86TTIImpl::getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy, if (ST->hasAVX512() && HasAVX512Solution && (!RequiresBW || ST->hasBWI())) return getInterleavedMemoryOpCostAVX512(Opcode, VecTy, Factor, Indices, Alignment, AddressSpace); + if (ST->hasAVX2()) + return getInterleavedMemoryOpCostAVX2(Opcode, VecTy, Factor, Indices, + Alignment, AddressSpace); + return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices, Alignment, AddressSpace); } diff --git a/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h b/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h index 09ce2c90498d..ad0a0a211301 100644 --- a/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h +++ b/contrib/llvm/lib/Target/X86/X86TargetTransformInfo.h @@ -93,6 +93,9 @@ class X86TTIImpl : public BasicTTIImplBase { int getInterleavedMemoryOpCostAVX512(unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef Indices, unsigned Alignment, unsigned AddressSpace); + int getInterleavedMemoryOpCostAVX2(unsigned Opcode, Type *VecTy, + unsigned Factor, ArrayRef Indices, + unsigned Alignment, unsigned AddressSpace); int getIntImmCost(int64_t); @@ -101,15 +104,13 @@ class X86TTIImpl : public BasicTTIImplBase { int getIntImmCost(unsigned Opcode, unsigned Idx, const APInt &Imm, Type *Ty); int getIntImmCost(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, Type *Ty); - bool isLSRCostLess(TargetTransformInfo::LSRCost &C1, - TargetTransformInfo::LSRCost &C2); bool isLegalMaskedLoad(Type *DataType); bool isLegalMaskedStore(Type *DataType); bool isLegalMaskedGather(Type *DataType); bool isLegalMaskedScatter(Type *DataType); bool areInlineCompatible(const Function *Caller, const Function *Callee) const; - + bool expandMemCmp(Instruction *I, unsigned &MaxLoadSize); bool enableInterleavedAccessVectorization(); private: int getGSScalarCost(unsigned Opcode, Type *DataTy, bool VariableMask, diff --git a/contrib/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp b/contrib/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp index 797e4ffc2d45..f304b9c9a8da 100644 --- a/contrib/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp +++ b/contrib/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp @@ -31,7 +31,7 @@ namespace { enum { OPT_INVALID = 0, -#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, #include "Options.inc" #undef OPTION }; @@ -41,11 +41,9 @@ enum { #undef PREFIX static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ - { \ - X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \ - OPT_##GROUP, OPT_##ALIAS, X6 \ - }, +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10, X11) \ + {X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, \ + X8, X7, OPT_##GROUP, OPT_##ALIAS, X6, X11}, #include "Options.inc" #undef OPTION }; diff --git a/contrib/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp b/contrib/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp index 4bc64ab698ff..087a8aa2c624 100644 --- a/contrib/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/contrib/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -72,10 +72,6 @@ static cl::opt RunLoopRerolling("reroll-loops", cl::Hidden, cl::desc("Run the loop rerolling pass")); -static cl::opt RunLoadCombine("combine-loads", cl::init(false), - cl::Hidden, - cl::desc("Run the load combining pass")); - static cl::opt RunNewGVN("enable-newgvn", cl::init(false), cl::Hidden, cl::desc("Run the NewGVN pass")); @@ -174,7 +170,6 @@ PassManagerBuilder::PassManagerBuilder() { SLPVectorize = RunSLPVectorization; LoopVectorize = RunLoopVectorization; RerollLoops = RunLoopRerolling; - LoadCombine = RunLoadCombine; NewGVN = RunNewGVN; DisableGVNLoadPRE = false; VerifyInput = false; @@ -296,6 +291,8 @@ void PassManagerBuilder::addPGOInstrPasses(legacy::PassManagerBase &MPM) { InstrProfOptions Options; if (!PGOInstrGen.empty()) Options.InstrProfileOutput = PGOInstrGen; + Options.DoCounterPromotion = true; + MPM.add(createLoopRotatePass()); MPM.add(createInstrProfilingLegacyPass(Options)); } if (!PGOInstrUse.empty()) @@ -407,9 +404,6 @@ void PassManagerBuilder::addFunctionSimplificationPasses( } } - if (LoadCombine) - MPM.add(createLoadCombinePass()); - MPM.add(createAggressiveDCEPass()); // Delete dead instructions MPM.add(createCFGSimplificationPass()); // Merge & remove BBs // Clean up after everything. @@ -850,9 +844,6 @@ void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) { // alignments. PM.add(createAlignmentFromAssumptionsPass()); - if (LoadCombine) - PM.add(createLoadCombinePass()); - // Cleanup and simplify the code after the scalar optimizations. addInstructionCombiningPass(PM); addExtensionsToPM(EP_Peephole, PM); diff --git a/contrib/llvm/lib/Transforms/IPO/SampleProfile.cpp b/contrib/llvm/lib/Transforms/IPO/SampleProfile.cpp index 67bc8f5f6b7a..656421ee58df 100644 --- a/contrib/llvm/lib/Transforms/IPO/SampleProfile.cpp +++ b/contrib/llvm/lib/Transforms/IPO/SampleProfile.cpp @@ -690,6 +690,9 @@ bool SampleProfileLoader::inlineHotFunctions( for (auto I : CIS) { InlineFunctionInfo IFI(nullptr, ACT ? &GetAssumptionCache : nullptr); Function *CalledFunction = CallSite(I).getCalledFunction(); + // Do not inline recursive calls. + if (CalledFunction == &F) + continue; Instruction *DI = I; if (!CalledFunction && !PromotedInsns.count(I) && CallSite(I).isIndirectCall()) diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 287a5167fe2a..d5f0dd191415 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -988,15 +988,24 @@ static Instruction *foldAddWithConstant(BinaryOperator &Add, return new ZExtInst(Builder.CreateNUWAdd(X, NewC), Ty); } - // Shifts and add used to flip and mask off the low bit: - // add (ashr (shl i32 X, 31), 31), 1 --> and (not X), 1 - const APInt *C3; - if (C->isOneValue() && - match(Op0, - m_OneUse(m_AShr(m_Shl(m_Value(X), m_APInt(C2)), m_APInt(C3)))) && - C2 == C3 && *C2 == Ty->getScalarSizeInBits() - 1) { - Value *NotX = Builder.CreateNot(X); - return BinaryOperator::CreateAnd(NotX, ConstantInt::get(Ty, 1)); + if (C->isOneValue() && Op0->hasOneUse()) { + // add (sext i1 X), 1 --> zext (not X) + // TODO: The smallest IR representation is (select X, 0, 1), and that would + // not require the one-use check. But we need to remove a transform in + // visitSelect and make sure that IR value tracking for select is equal or + // better than for these ops. + if (match(Op0, m_SExt(m_Value(X))) && + X->getType()->getScalarSizeInBits() == 1) + return new ZExtInst(Builder.CreateNot(X), Ty); + + // Shifts and add used to flip and mask off the low bit: + // add (ashr (shl i32 X, 31), 31), 1 --> and (not X), 1 + const APInt *C3; + if (match(Op0, m_AShr(m_Shl(m_Value(X), m_APInt(C2)), m_APInt(C3))) && + C2 == C3 && *C2 == Ty->getScalarSizeInBits() - 1) { + Value *NotX = Builder.CreateNot(X); + return BinaryOperator::CreateAnd(NotX, ConstantInt::get(Ty, 1)); + } } return nullptr; diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index a881bda5ba98..d3d8cefe9735 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1097,20 +1097,11 @@ static Instruction *foldLogicCastConstant(BinaryOperator &Logic, CastInst *Cast, Type *DestTy = Logic.getType(); Type *SrcTy = Cast->getSrcTy(); - // If the first operand is bitcast, move the logic operation ahead of the - // bitcast (do the logic operation in the original type). This can eliminate - // bitcasts and allow combines that would otherwise be impeded by the bitcast. + // Move the logic operation ahead of a zext if the constant is unchanged in + // the smaller source type. Performing the logic in a smaller type may provide + // more information to later folds, and the smaller logic instruction may be + // cheaper (particularly in the case of vectors). Value *X; - if (match(Cast, m_BitCast(m_Value(X)))) { - Value *NewConstant = ConstantExpr::getBitCast(C, SrcTy); - Value *NewOp = Builder->CreateBinOp(LogicOpc, X, NewConstant); - return CastInst::CreateBitOrPointerCast(NewOp, DestTy); - } - - // Similarly, move the logic operation ahead of a zext if the constant is - // unchanged in the smaller source type. Performing the logic in a smaller - // type may provide more information to later folds, and the smaller logic - // instruction may be cheaper (particularly in the case of vectors). if (match(Cast, m_OneUse(m_ZExt(m_Value(X))))) { Constant *TruncC = ConstantExpr::getTrunc(C, SrcTy); Constant *ZextTruncC = ConstantExpr::getZExt(TruncC, DestTy); @@ -1239,9 +1230,10 @@ static Instruction *foldAndToXor(BinaryOperator &I, // (A | ~B) & (B | ~A) --> ~(A ^ B) // (~B | A) & (~A | B) --> ~(A ^ B) // (~B | A) & (B | ~A) --> ~(A ^ B) - if (match(Op0, m_c_Or(m_Value(A), m_Not(m_Value(B)))) && - match(Op1, m_c_Or(m_Not(m_Specific(A)), m_Specific(B)))) - return BinaryOperator::CreateNot(Builder.CreateXor(A, B)); + if (Op0->hasOneUse() || Op1->hasOneUse()) + if (match(Op0, m_c_Or(m_Value(A), m_Not(m_Value(B)))) && + match(Op1, m_c_Or(m_Not(m_Specific(A)), m_Specific(B)))) + return BinaryOperator::CreateNot(Builder.CreateXor(A, B)); return nullptr; } @@ -1256,9 +1248,10 @@ static Instruction *foldOrToXor(BinaryOperator &I, // Operand complexity canonicalization guarantees that the 'and' is Op0. // (A & B) | ~(A | B) --> ~(A ^ B) // (A & B) | ~(B | A) --> ~(A ^ B) - if (match(Op0, m_And(m_Value(A), m_Value(B))) && - match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) - return BinaryOperator::CreateNot(Builder.CreateXor(A, B)); + if (Op0->hasOneUse() || Op1->hasOneUse()) + if (match(Op0, m_And(m_Value(A), m_Value(B))) && + match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) + return BinaryOperator::CreateNot(Builder.CreateXor(A, B)); // (A & ~B) | (~A & B) --> A ^ B // (A & ~B) | (B & ~A) --> A ^ B @@ -1442,13 +1435,13 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { // (A ^ B) & ((B ^ C) ^ A) -> (A ^ B) & ~C if (match(Op0, m_Xor(m_Value(A), m_Value(B)))) if (match(Op1, m_Xor(m_Xor(m_Specific(B), m_Value(C)), m_Specific(A)))) - if (Op1->hasOneUse() || cast(Op1)->hasOneUse()) + if (Op1->hasOneUse() || IsFreeToInvert(C, C->hasOneUse())) return BinaryOperator::CreateAnd(Op0, Builder->CreateNot(C)); // ((A ^ C) ^ B) & (B ^ A) -> (B ^ A) & ~C if (match(Op0, m_Xor(m_Xor(m_Value(A), m_Value(C)), m_Value(B)))) if (match(Op1, m_Xor(m_Specific(B), m_Specific(A)))) - if (Op0->hasOneUse() || cast(Op0)->hasOneUse()) + if (Op0->hasOneUse() || IsFreeToInvert(C, C->hasOneUse())) return BinaryOperator::CreateAnd(Op1, Builder->CreateNot(C)); // (A | B) & ((~A) ^ B) -> (A & B) @@ -1579,11 +1572,14 @@ static Value *getSelectCondition(Value *A, Value *B, // If A and B are sign-extended, look through the sexts to find the booleans. Value *Cond; + Value *NotB; if (match(A, m_SExt(m_Value(Cond))) && Cond->getType()->getScalarType()->isIntegerTy(1) && - match(B, m_CombineOr(m_Not(m_SExt(m_Specific(Cond))), - m_SExt(m_Not(m_Specific(Cond)))))) - return Cond; + match(B, m_OneUse(m_Not(m_Value(NotB))))) { + NotB = peekThroughBitcast(NotB, true); + if (match(NotB, m_SExt(m_Specific(Cond)))) + return Cond; + } // All scalar (and most vector) possibilities should be handled now. // Try more matches that only apply to non-splat constant vectors. @@ -1615,12 +1611,8 @@ static Value *matchSelectFromAndOr(Value *A, Value *C, Value *B, Value *D, // The potential condition of the select may be bitcasted. In that case, look // through its bitcast and the corresponding bitcast of the 'not' condition. Type *OrigType = A->getType(); - Value *SrcA, *SrcB; - if (match(A, m_OneUse(m_BitCast(m_Value(SrcA)))) && - match(B, m_OneUse(m_BitCast(m_Value(SrcB))))) { - A = SrcA; - B = SrcB; - } + A = peekThroughBitcast(A, true); + B = peekThroughBitcast(B, true); if (Value *Cond = getSelectCondition(A, B, Builder)) { // ((bc Cond) & C) | ((bc ~Cond) & D) --> bc (select Cond, (bc C), (bc D)) @@ -1922,8 +1914,9 @@ Value *InstCombiner::foldOrOfFCmps(FCmpInst *LHS, FCmpInst *RHS) { /// (A & C1) | B /// /// when the XOR of the two constants is "all ones" (-1). -Instruction *InstCombiner::FoldOrWithConstants(BinaryOperator &I, Value *Op, - Value *A, Value *B, Value *C) { +static Instruction *FoldOrWithConstants(BinaryOperator &I, Value *Op, + Value *A, Value *B, Value *C, + InstCombiner::BuilderTy *Builder) { ConstantInt *CI1 = dyn_cast(C); if (!CI1) return nullptr; @@ -1944,15 +1937,16 @@ Instruction *InstCombiner::FoldOrWithConstants(BinaryOperator &I, Value *Op, /// \brief This helper function folds: /// -/// ((A | B) & C1) ^ (B & C2) +/// ((A ^ B) & C1) | (B & C2) /// /// into: /// /// (A & C1) ^ B /// /// when the XOR of the two constants is "all ones" (-1). -Instruction *InstCombiner::FoldXorWithConstants(BinaryOperator &I, Value *Op, - Value *A, Value *B, Value *C) { +static Instruction *FoldXorWithConstants(BinaryOperator &I, Value *Op, + Value *A, Value *B, Value *C, + InstCombiner::BuilderTy *Builder) { ConstantInt *CI1 = dyn_cast(C); if (!CI1) return nullptr; @@ -2112,46 +2106,36 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { } // ((A|B)&1)|(B&-2) -> (A&1) | B - if (match(A, m_Or(m_Value(V1), m_Specific(B))) || - match(A, m_Or(m_Specific(B), m_Value(V1)))) { - Instruction *Ret = FoldOrWithConstants(I, Op1, V1, B, C); - if (Ret) return Ret; + if (match(A, m_c_Or(m_Value(V1), m_Specific(B)))) { + if (Instruction *Ret = FoldOrWithConstants(I, Op1, V1, B, C, Builder)) + return Ret; } // (B&-2)|((A|B)&1) -> (A&1) | B - if (match(B, m_Or(m_Specific(A), m_Value(V1))) || - match(B, m_Or(m_Value(V1), m_Specific(A)))) { - Instruction *Ret = FoldOrWithConstants(I, Op0, A, V1, D); - if (Ret) return Ret; + if (match(B, m_c_Or(m_Specific(A), m_Value(V1)))) { + if (Instruction *Ret = FoldOrWithConstants(I, Op0, A, V1, D, Builder)) + return Ret; } // ((A^B)&1)|(B&-2) -> (A&1) ^ B - if (match(A, m_Xor(m_Value(V1), m_Specific(B))) || - match(A, m_Xor(m_Specific(B), m_Value(V1)))) { - Instruction *Ret = FoldXorWithConstants(I, Op1, V1, B, C); - if (Ret) return Ret; + if (match(A, m_c_Xor(m_Value(V1), m_Specific(B)))) { + if (Instruction *Ret = FoldXorWithConstants(I, Op1, V1, B, C, Builder)) + return Ret; } // (B&-2)|((A^B)&1) -> (A&1) ^ B - if (match(B, m_Xor(m_Specific(A), m_Value(V1))) || - match(B, m_Xor(m_Value(V1), m_Specific(A)))) { - Instruction *Ret = FoldXorWithConstants(I, Op0, A, V1, D); - if (Ret) return Ret; + if (match(B, m_c_Xor(m_Specific(A), m_Value(V1)))) { + if (Instruction *Ret = FoldXorWithConstants(I, Op0, A, V1, D, Builder)) + return Ret; } } // (A ^ B) | ((B ^ C) ^ A) -> (A ^ B) | C - // FIXME: The two hasOneUse calls here are the same call, maybe we were - // supposed to check Op1->operand(0)? if (match(Op0, m_Xor(m_Value(A), m_Value(B)))) if (match(Op1, m_Xor(m_Xor(m_Specific(B), m_Value(C)), m_Specific(A)))) - if (Op1->hasOneUse() || cast(Op1)->hasOneUse()) - return BinaryOperator::CreateOr(Op0, C); + return BinaryOperator::CreateOr(Op0, C); // ((A ^ C) ^ B) | (B ^ A) -> (B ^ A) | C - // FIXME: The two hasOneUse calls here are the same call, maybe we were - // supposed to check Op0->operand(0)? if (match(Op0, m_Xor(m_Xor(m_Value(A), m_Value(C)), m_Value(B)))) if (match(Op1, m_Xor(m_Specific(B), m_Specific(A)))) - if (Op0->hasOneUse() || cast(Op0)->hasOneUse()) - return BinaryOperator::CreateOr(Op1, C); + return BinaryOperator::CreateOr(Op1, C); // ((B | C) & A) | B -> B | (A & C) if (match(Op0, m_And(m_Or(m_Specific(Op1), m_Value(C)), m_Value(A)))) @@ -2357,6 +2341,30 @@ Value *InstCombiner::foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS) { } } + // Instead of trying to imitate the folds for and/or, decompose this 'xor' + // into those logic ops. That is, try to turn this into an and-of-icmps + // because we have many folds for that pattern. + // + // This is based on a truth table definition of xor: + // X ^ Y --> (X | Y) & !(X & Y) + if (Value *OrICmp = SimplifyBinOp(Instruction::Or, LHS, RHS, SQ)) { + // TODO: If OrICmp is true, then the definition of xor simplifies to !(X&Y). + // TODO: If OrICmp is false, the whole thing is false (InstSimplify?). + if (Value *AndICmp = SimplifyBinOp(Instruction::And, LHS, RHS, SQ)) { + // TODO: Independently handle cases where the 'and' side is a constant. + if (OrICmp == LHS && AndICmp == RHS && RHS->hasOneUse()) { + // (LHS | RHS) & !(LHS & RHS) --> LHS & !RHS + RHS->setPredicate(RHS->getInversePredicate()); + return Builder->CreateAnd(LHS, RHS); + } + if (OrICmp == RHS && AndICmp == LHS && LHS->hasOneUse()) { + // !(LHS & RHS) & (LHS | RHS) --> !LHS & RHS + LHS->setPredicate(LHS->getInversePredicate()); + return Builder->CreateAnd(LHS, RHS); + } + } + } + return nullptr; } diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index c0830a5d2112..dbed7ad4eae8 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1409,6 +1409,47 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombiner &IC) { } } + // Add range metadata since known bits can't completely reflect what we know. + // TODO: Handle splat vectors. + auto *IT = dyn_cast(Op0->getType()); + if (IT && IT->getBitWidth() != 1 && !II.getMetadata(LLVMContext::MD_range)) { + Metadata *LowAndHigh[] = { + ConstantAsMetadata::get(ConstantInt::get(IT, DefiniteZeros)), + ConstantAsMetadata::get(ConstantInt::get(IT, PossibleZeros + 1))}; + II.setMetadata(LLVMContext::MD_range, + MDNode::get(II.getContext(), LowAndHigh)); + return &II; + } + + return nullptr; +} + +static Instruction *foldCtpop(IntrinsicInst &II, InstCombiner &IC) { + assert(II.getIntrinsicID() == Intrinsic::ctpop && + "Expected ctpop intrinsic"); + Value *Op0 = II.getArgOperand(0); + // FIXME: Try to simplify vectors of integers. + auto *IT = dyn_cast(Op0->getType()); + if (!IT) + return nullptr; + + unsigned BitWidth = IT->getBitWidth(); + KnownBits Known(BitWidth); + IC.computeKnownBits(Op0, Known, 0, &II); + + unsigned MinCount = Known.countMinPopulation(); + unsigned MaxCount = Known.countMaxPopulation(); + + // Add range metadata since known bits can't completely reflect what we know. + if (IT->getBitWidth() != 1 && !II.getMetadata(LLVMContext::MD_range)) { + Metadata *LowAndHigh[] = { + ConstantAsMetadata::get(ConstantInt::get(IT, MinCount)), + ConstantAsMetadata::get(ConstantInt::get(IT, MaxCount + 1))}; + II.setMetadata(LLVMContext::MD_range, + MDNode::get(II.getContext(), LowAndHigh)); + return &II; + } + return nullptr; } @@ -1981,6 +2022,11 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { return I; break; + case Intrinsic::ctpop: + if (auto *I = foldCtpop(*II, *this)) + return I; + break; + case Intrinsic::uadd_with_overflow: case Intrinsic::sadd_with_overflow: case Intrinsic::umul_with_overflow: diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index 38e95fb11639..d3049389dfb9 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -1896,6 +1896,18 @@ static Instruction *foldBitCastBitwiseLogic(BitCastInst &BitCast, return BinaryOperator::Create(BO->getOpcode(), CastedOp0, X); } + // Canonicalize vector bitcasts to come before vector bitwise logic with a + // constant. This eases recognition of special constants for later ops. + // Example: + // icmp u/s (a ^ signmask), (b ^ signmask) --> icmp s/u a, b + Constant *C; + if (match(BO->getOperand(1), m_Constant(C))) { + // bitcast (logic X, C) --> logic (bitcast X, C') + Value *CastedOp0 = Builder.CreateBitCast(BO->getOperand(0), DestTy); + Value *CastedC = ConstantExpr::getBitCast(C, DestTy); + return BinaryOperator::Create(BO->getOpcode(), CastedOp0, CastedC); + } + return nullptr; } diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 1ef4acfb058c..6ad32490a328 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2434,6 +2434,77 @@ Instruction *InstCombiner::foldICmpAddConstant(ICmpInst &Cmp, return nullptr; } +bool InstCombiner::matchThreeWayIntCompare(SelectInst *SI, Value *&LHS, + Value *&RHS, ConstantInt *&Less, + ConstantInt *&Equal, + ConstantInt *&Greater) { + // TODO: Generalize this to work with other comparison idioms or ensure + // they get canonicalized into this form. + + // select i1 (a == b), i32 Equal, i32 (select i1 (a < b), i32 Less, i32 + // Greater), where Equal, Less and Greater are placeholders for any three + // constants. + ICmpInst::Predicate PredA, PredB; + if (match(SI->getTrueValue(), m_ConstantInt(Equal)) && + match(SI->getCondition(), m_ICmp(PredA, m_Value(LHS), m_Value(RHS))) && + PredA == ICmpInst::ICMP_EQ && + match(SI->getFalseValue(), + m_Select(m_ICmp(PredB, m_Specific(LHS), m_Specific(RHS)), + m_ConstantInt(Less), m_ConstantInt(Greater))) && + PredB == ICmpInst::ICMP_SLT) { + return true; + } + return false; +} + +Instruction *InstCombiner::foldICmpSelectConstant(ICmpInst &Cmp, + Instruction *Select, + ConstantInt *C) { + + assert(C && "Cmp RHS should be a constant int!"); + // If we're testing a constant value against the result of a three way + // comparison, the result can be expressed directly in terms of the + // original values being compared. Note: We could possibly be more + // aggressive here and remove the hasOneUse test. The original select is + // really likely to simplify or sink when we remove a test of the result. + Value *OrigLHS, *OrigRHS; + ConstantInt *C1LessThan, *C2Equal, *C3GreaterThan; + if (Cmp.hasOneUse() && + matchThreeWayIntCompare(cast(Select), OrigLHS, OrigRHS, + C1LessThan, C2Equal, C3GreaterThan)) { + assert(C1LessThan && C2Equal && C3GreaterThan); + + bool TrueWhenLessThan = + ConstantExpr::getCompare(Cmp.getPredicate(), C1LessThan, C) + ->isAllOnesValue(); + bool TrueWhenEqual = + ConstantExpr::getCompare(Cmp.getPredicate(), C2Equal, C) + ->isAllOnesValue(); + bool TrueWhenGreaterThan = + ConstantExpr::getCompare(Cmp.getPredicate(), C3GreaterThan, C) + ->isAllOnesValue(); + + // This generates the new instruction that will replace the original Cmp + // Instruction. Instead of enumerating the various combinations when + // TrueWhenLessThan, TrueWhenEqual and TrueWhenGreaterThan are true versus + // false, we rely on chaining of ORs and future passes of InstCombine to + // simplify the OR further (i.e. a s< b || a == b becomes a s<= b). + + // When none of the three constants satisfy the predicate for the RHS (C), + // the entire original Cmp can be simplified to a false. + Value *Cond = Builder->getFalse(); + if (TrueWhenLessThan) + Cond = Builder->CreateOr(Cond, Builder->CreateICmp(ICmpInst::ICMP_SLT, OrigLHS, OrigRHS)); + if (TrueWhenEqual) + Cond = Builder->CreateOr(Cond, Builder->CreateICmp(ICmpInst::ICMP_EQ, OrigLHS, OrigRHS)); + if (TrueWhenGreaterThan) + Cond = Builder->CreateOr(Cond, Builder->CreateICmp(ICmpInst::ICMP_SGT, OrigLHS, OrigRHS)); + + return replaceInstUsesWith(Cmp, Cond); + } + return nullptr; +} + /// Try to fold integer comparisons with a constant operand: icmp Pred X, C /// where X is some kind of instruction. Instruction *InstCombiner::foldICmpInstWithConstant(ICmpInst &Cmp) { @@ -2493,11 +2564,28 @@ Instruction *InstCombiner::foldICmpInstWithConstant(ICmpInst &Cmp) { return I; } + // Match against CmpInst LHS being instructions other than binary operators. Instruction *LHSI; - if (match(Cmp.getOperand(0), m_Instruction(LHSI)) && - LHSI->getOpcode() == Instruction::Trunc) - if (Instruction *I = foldICmpTruncConstant(Cmp, LHSI, C)) - return I; + if (match(Cmp.getOperand(0), m_Instruction(LHSI))) { + switch (LHSI->getOpcode()) { + case Instruction::Select: + { + // For now, we only support constant integers while folding the + // ICMP(SELECT)) pattern. We can extend this to support vector of integers + // similar to the cases handled by binary ops above. + if (ConstantInt *ConstRHS = dyn_cast(Cmp.getOperand(1))) + if (Instruction *I = foldICmpSelectConstant(Cmp, LHSI, ConstRHS)) + return I; + break; + } + case Instruction::Trunc: + if (Instruction *I = foldICmpTruncConstant(Cmp, LHSI, C)) + return I; + break; + default: + break; + } + } if (Instruction *I = foldICmpIntrinsicWithConstant(Cmp, C)) return I; @@ -3110,8 +3198,7 @@ Instruction *InstCombiner::foldICmpBinOp(ICmpInst &I) { if (BO0) { // Transform A & (L - 1) `ult` L --> L != 0 auto LSubOne = m_Add(m_Specific(Op1), m_AllOnes()); - auto BitwiseAnd = - m_CombineOr(m_And(m_Value(), LSubOne), m_And(LSubOne, m_Value())); + auto BitwiseAnd = m_c_And(m_Value(), LSubOne); if (match(BO0, BitwiseAnd) && Pred == ICmpInst::ICMP_ULT) { auto *Zero = Constant::getNullValue(BO0->getType()); diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/contrib/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index 1a7db146df42..1b0fe84dd4dd 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -95,6 +95,18 @@ static inline bool isCanonicalPredicate(CmpInst::Predicate Pred) { } } +/// Return the source operand of a potentially bitcasted value while optionally +/// checking if it has one use. If there is no bitcast or the one use check is +/// not met, return the input value itself. +static inline Value *peekThroughBitcast(Value *V, bool OneUseOnly = false) { + if (auto *BitCast = dyn_cast(V)) + if (!OneUseOnly || BitCast->hasOneUse()) + return BitCast->getOperand(0); + + // V is not a bitcast or V has more than one use and OneUseOnly is true. + return V; +} + /// \brief Add one to a Constant static inline Constant *AddOne(Constant *C) { return ConstantExpr::getAdd(C, ConstantInt::get(C->getType(), 1)); @@ -276,10 +288,6 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner Instruction *visitFDiv(BinaryOperator &I); Value *simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1, bool Inverted); Instruction *visitAnd(BinaryOperator &I); - Instruction *FoldOrWithConstants(BinaryOperator &I, Value *Op, Value *A, - Value *B, Value *C); - Instruction *FoldXorWithConstants(BinaryOperator &I, Value *Op, Value *A, - Value *B, Value *C); Instruction *visitOr(BinaryOperator &I); Instruction *visitXor(BinaryOperator &I); Instruction *visitShl(BinaryOperator &I); @@ -595,6 +603,15 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner Instruction::BinaryOps, Value *, Value *, Value *, Value *); + /// Match a select chain which produces one of three values based on whether + /// the LHS is less than, equal to, or greater than RHS respectively. + /// Return true if we matched a three way compare idiom. The LHS, RHS, Less, + /// Equal and Greater values are saved in the matching process and returned to + /// the caller. + bool matchThreeWayIntCompare(SelectInst *SI, Value *&LHS, Value *&RHS, + ConstantInt *&Less, ConstantInt *&Equal, + ConstantInt *&Greater); + /// \brief Attempts to replace V with a simpler value based on the demanded /// bits. Value *SimplifyDemandedUseBits(Value *V, APInt DemandedMask, KnownBits &Known, @@ -672,6 +689,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner Instruction *foldICmpBinOp(ICmpInst &Cmp); Instruction *foldICmpEquality(ICmpInst &Cmp); + Instruction *foldICmpSelectConstant(ICmpInst &Cmp, Instruction *Select, + ConstantInt *C); Instruction *foldICmpTruncConstant(ICmpInst &Cmp, Instruction *Trunc, const APInt *C); Instruction *foldICmpAndConstant(ICmpInst &Cmp, BinaryOperator *And, diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index a4d84ae81aa0..ca370c73fca4 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -169,6 +169,18 @@ isOnlyCopiedFromConstantGlobal(AllocaInst *AI, return nullptr; } +/// Returns true if V is dereferenceable for size of alloca. +static bool isDereferenceableForAllocaSize(const Value *V, const AllocaInst *AI, + const DataLayout &DL) { + if (AI->isArrayAllocation()) + return false; + uint64_t AllocaSize = DL.getTypeStoreSize(AI->getAllocatedType()); + if (!AllocaSize) + return false; + return isDereferenceableAndAlignedPointer(V, AI->getAlignment(), + APInt(64, AllocaSize), DL); +} + static Instruction *simplifyAllocaArraySize(InstCombiner &IC, AllocaInst &AI) { // Check for array size of 1 (scalar allocation). if (!AI.isArrayAllocation()) { @@ -390,7 +402,8 @@ Instruction *InstCombiner::visitAllocaInst(AllocaInst &AI) { if (MemTransferInst *Copy = isOnlyCopiedFromConstantGlobal(&AI, ToDelete)) { unsigned SourceAlign = getOrEnforceKnownAlignment( Copy->getSource(), AI.getAlignment(), DL, &AI, &AC, &DT); - if (AI.getAlignment() <= SourceAlign) { + if (AI.getAlignment() <= SourceAlign && + isDereferenceableForAllocaSize(Copy->getSource(), &AI, DL)) { DEBUG(dbgs() << "Found alloca equal to global: " << AI << '\n'); DEBUG(dbgs() << " memcpy = " << *Copy << '\n'); for (unsigned i = 0, e = ToDelete.size(); i != e; ++i) @@ -476,21 +489,7 @@ static LoadInst *combineLoadToNewType(InstCombiner &IC, LoadInst &LI, Type *NewT break; case LLVMContext::MD_nonnull: - // This only directly applies if the new type is also a pointer. - if (NewTy->isPointerTy()) { - NewLoad->setMetadata(ID, N); - break; - } - // If it's integral now, translate it to !range metadata. - if (NewTy->isIntegerTy()) { - auto *ITy = cast(NewTy); - auto *NullInt = ConstantExpr::getPtrToInt( - ConstantPointerNull::get(cast(Ptr->getType())), ITy); - auto *NonNullInt = - ConstantExpr::getAdd(NullInt, ConstantInt::get(ITy, 1)); - NewLoad->setMetadata(LLVMContext::MD_range, - MDB.createRange(NonNullInt, NullInt)); - } + copyNonnullMetadata(LI, N, *NewLoad); break; case LLVMContext::MD_align: case LLVMContext::MD_dereferenceable: @@ -500,17 +499,7 @@ static LoadInst *combineLoadToNewType(InstCombiner &IC, LoadInst &LI, Type *NewT NewLoad->setMetadata(ID, N); break; case LLVMContext::MD_range: - // FIXME: It would be nice to propagate this in some way, but the type - // conversions make it hard. - - // If it's a pointer now and the range does not contain 0, make it !nonnull. - if (NewTy->isPointerTy()) { - unsigned BitWidth = IC.getDataLayout().getTypeSizeInBits(NewTy); - if (!getConstantRangeFromMetadata(*N).contains(APInt(BitWidth, 0))) { - MDNode *NN = MDNode::get(LI.getContext(), None); - NewLoad->setMetadata(LLVMContext::MD_nonnull, NN); - } - } + copyRangeMetadata(IC.getDataLayout(), LI, N, *NewLoad); break; } } diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index b9674d85634d..33951e66497a 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -303,7 +303,7 @@ Instruction *InstCombiner::foldSelectIntoOp(SelectInst &SI, Value *TrueVal, /// We want to turn: /// (select (icmp eq (and X, C1), 0), Y, (or Y, C2)) /// into: -/// (or (shl (and X, C1), C3), y) +/// (or (shl (and X, C1), C3), Y) /// iff: /// C1 and C2 are both powers of 2 /// where: @@ -317,19 +317,44 @@ static Value *foldSelectICmpAndOr(const SelectInst &SI, Value *TrueVal, Value *FalseVal, InstCombiner::BuilderTy *Builder) { const ICmpInst *IC = dyn_cast(SI.getCondition()); - if (!IC || !IC->isEquality() || !SI.getType()->isIntegerTy()) + if (!IC || !SI.getType()->isIntegerTy()) return nullptr; Value *CmpLHS = IC->getOperand(0); Value *CmpRHS = IC->getOperand(1); - if (!match(CmpRHS, m_Zero())) - return nullptr; + Value *V; + unsigned C1Log; + bool IsEqualZero; + bool NeedAnd = false; + if (IC->isEquality()) { + if (!match(CmpRHS, m_Zero())) + return nullptr; - Value *X; - const APInt *C1; - if (!match(CmpLHS, m_And(m_Value(X), m_Power2(C1)))) + const APInt *C1; + if (!match(CmpLHS, m_And(m_Value(), m_Power2(C1)))) + return nullptr; + + V = CmpLHS; + C1Log = C1->logBase2(); + IsEqualZero = IC->getPredicate() == ICmpInst::ICMP_EQ; + } else if (IC->getPredicate() == ICmpInst::ICMP_SLT || + IC->getPredicate() == ICmpInst::ICMP_SGT) { + // We also need to recognize (icmp slt (trunc (X)), 0) and + // (icmp sgt (trunc (X)), -1). + IsEqualZero = IC->getPredicate() == ICmpInst::ICMP_SGT; + if ((IsEqualZero && !match(CmpRHS, m_AllOnes())) || + (!IsEqualZero && !match(CmpRHS, m_Zero()))) + return nullptr; + + if (!match(CmpLHS, m_OneUse(m_Trunc(m_Value(V))))) + return nullptr; + + C1Log = CmpLHS->getType()->getScalarSizeInBits() - 1; + NeedAnd = true; + } else { return nullptr; + } const APInt *C2; bool OrOnTrueVal = false; @@ -340,11 +365,27 @@ static Value *foldSelectICmpAndOr(const SelectInst &SI, Value *TrueVal, if (!OrOnFalseVal && !OrOnTrueVal) return nullptr; - Value *V = CmpLHS; Value *Y = OrOnFalseVal ? TrueVal : FalseVal; - unsigned C1Log = C1->logBase2(); unsigned C2Log = C2->logBase2(); + + bool NeedXor = (!IsEqualZero && OrOnFalseVal) || (IsEqualZero && OrOnTrueVal); + bool NeedShift = C1Log != C2Log; + bool NeedZExtTrunc = Y->getType()->getIntegerBitWidth() != + V->getType()->getIntegerBitWidth(); + + // Make sure we don't create more instructions than we save. + Value *Or = OrOnFalseVal ? FalseVal : TrueVal; + if ((NeedShift + NeedXor + NeedZExtTrunc) > + (IC->hasOneUse() + Or->hasOneUse())) + return nullptr; + + if (NeedAnd) { + // Insert the AND instruction on the input to the truncate. + APInt C1 = APInt::getOneBitSet(V->getType()->getScalarSizeInBits(), C1Log); + V = Builder->CreateAnd(V, ConstantInt::get(V->getType(), C1)); + } + if (C2Log > C1Log) { V = Builder->CreateZExtOrTrunc(V, Y->getType()); V = Builder->CreateShl(V, C2Log - C1Log); @@ -354,9 +395,7 @@ static Value *foldSelectICmpAndOr(const SelectInst &SI, Value *TrueVal, } else V = Builder->CreateZExtOrTrunc(V, Y->getType()); - ICmpInst::Predicate Pred = IC->getPredicate(); - if ((Pred == ICmpInst::ICMP_NE && OrOnFalseVal) || - (Pred == ICmpInst::ICMP_EQ && OrOnTrueVal)) + if (NeedXor) V = Builder->CreateXor(V, *C2); return Builder->CreateOr(V, Y); diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 8cec865c6422..1bb1a85367d1 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -556,8 +556,7 @@ Instruction *InstCombiner::visitShl(BinaryOperator &I) { // The inexact versions are deferred to DAGCombine, so we don't hide shl // behind a bit mask. const APInt *ShOp1; - if (match(Op0, m_CombineOr(m_Exact(m_LShr(m_Value(X), m_APInt(ShOp1))), - m_Exact(m_AShr(m_Value(X), m_APInt(ShOp1)))))) { + if (match(Op0, m_Exact(m_Shr(m_Value(X), m_APInt(ShOp1))))) { unsigned ShrAmt = ShOp1->getZExtValue(); if (ShrAmt < ShAmt) { // If C1 < C2: (X >>?,exact C1) << C2 --> X << (C2 - C1) diff --git a/contrib/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/contrib/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index 65e6d2e35905..02fac4fb37a4 100644 --- a/contrib/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/contrib/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -939,9 +939,19 @@ Instruction *InstCombiner::foldOpIntoPhi(Instruction &I, PHINode *PN) { // `TrueVInPred`. if (InC && !isa(InC) && isa(InC)) InV = InC->isNullValue() ? FalseVInPred : TrueVInPred; - else + else { + // Generate the select in the same block as PN's current incoming block. + // Note: ThisBB need not be the NonConstBB because vector constants + // which are constants by definition are handled here. + // FIXME: This can lead to an increase in IR generation because we might + // generate selects for vector constant phi operand, that could not be + // folded to TrueVInPred or FalseVInPred as done for ConstantInt. For + // non-vector phis, this transformation was always profitable because + // the select would be generated exactly once in the NonConstBB. + Builder->SetInsertPoint(ThisBB->getTerminator()); InV = Builder->CreateSelect(PN->getIncomingValue(i), TrueVInPred, FalseVInPred, "phitmp"); + } NewPN->addIncoming(InV, ThisBB); } } else if (CmpInst *CI = dyn_cast(&I)) { @@ -3002,6 +3012,7 @@ static bool AddReachableCodeToWorklist(BasicBlock *BB, const DataLayout &DL, ++NumDeadInst; DEBUG(dbgs() << "IC: DCE: " << *Inst << '\n'); Inst->eraseFromParent(); + MadeIRChange = true; continue; } @@ -3015,6 +3026,7 @@ static bool AddReachableCodeToWorklist(BasicBlock *BB, const DataLayout &DL, ++NumConstProp; if (isInstructionTriviallyDead(Inst, TLI)) Inst->eraseFromParent(); + MadeIRChange = true; continue; } diff --git a/contrib/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp b/contrib/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp index 0d308810009d..4089d81ea3e1 100644 --- a/contrib/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp +++ b/contrib/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp @@ -642,7 +642,12 @@ static bool promoteIndirectCalls(Module &M, bool InLTO, bool SamplePGO) { if (DisableICP) return false; InstrProfSymtab Symtab; - Symtab.create(M, InLTO); + if (Error E = Symtab.create(M, InLTO)) { + std::string SymtabFailure = toString(std::move(E)); + DEBUG(dbgs() << "Failed to create symtab: " << SymtabFailure << "\n"); + (void)SymtabFailure; + return false; + } bool Changed = false; for (auto &F : M) { if (F.isDeclaration()) diff --git a/contrib/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/contrib/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp index 37f88d5f95f1..9c14b0149fdc 100644 --- a/contrib/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/contrib/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -19,12 +19,14 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" +#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" @@ -40,7 +42,10 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include "llvm/Transforms/Utils/SSAUpdater.h" #include #include #include @@ -92,6 +97,35 @@ cl::opt NumCountersPerValueSite( // is usually smaller than 2. cl::init(1.0)); +cl::opt AtomicCounterUpdatePromoted( + "atomic-counter-update-promoted", cl::ZeroOrMore, + cl::desc("Do counter update using atomic fetch add " + " for promoted counters only"), + cl::init(false)); + +// If the option is not specified, the default behavior about whether +// counter promotion is done depends on how instrumentaiton lowering +// pipeline is setup, i.e., the default value of true of this option +// does not mean the promotion will be done by default. Explicitly +// setting this option can override the default behavior. +cl::opt DoCounterPromotion("do-counter-promotion", cl::ZeroOrMore, + cl::desc("Do counter register promotion"), + cl::init(false)); +cl::opt MaxNumOfPromotionsPerLoop( + cl::ZeroOrMore, "max-counter-promotions-per-loop", cl::init(10), + cl::desc("Max number counter promotions per loop to avoid" + " increasing register pressure too much")); + +// A debug option +cl::opt + MaxNumOfPromotions(cl::ZeroOrMore, "max-counter-promotions", cl::init(-1), + cl::desc("Max number of allowed counter promotions")); + +cl::opt SpeculativeCounterPromotion( + cl::ZeroOrMore, "speculative-counter-promotion", cl::init(false), + cl::desc("Allow counter promotion for loops with multiple exiting blocks " + " or top-tested loops. ")); + class InstrProfilingLegacyPass : public ModulePass { InstrProfiling InstrProf; @@ -116,6 +150,123 @@ class InstrProfilingLegacyPass : public ModulePass { } }; +/// A helper class to promote one counter RMW operation in the loop +/// into register update. +/// +/// RWM update for the counter will be sinked out of the loop after +/// the transformation. +/// +class PGOCounterPromoterHelper : public LoadAndStorePromoter { +public: + PGOCounterPromoterHelper(Instruction *L, Instruction *S, SSAUpdater &SSA, + Value *Init, BasicBlock *PH, + ArrayRef ExitBlocks, + ArrayRef InsertPts) + : LoadAndStorePromoter({L, S}, SSA), Store(S), ExitBlocks(ExitBlocks), + InsertPts(InsertPts) { + assert(isa(L)); + assert(isa(S)); + SSA.AddAvailableValue(PH, Init); + } + void doExtraRewritesBeforeFinalDeletion() const override { + for (unsigned i = 0, e = ExitBlocks.size(); i != e; ++i) { + BasicBlock *ExitBlock = ExitBlocks[i]; + Instruction *InsertPos = InsertPts[i]; + // Get LiveIn value into the ExitBlock. If there are multiple + // predecessors, the value is defined by a PHI node in this + // block. + Value *LiveInValue = SSA.GetValueInMiddleOfBlock(ExitBlock); + Value *Addr = cast(Store)->getPointerOperand(); + IRBuilder<> Builder(InsertPos); + if (AtomicCounterUpdatePromoted) + Builder.CreateAtomicRMW(AtomicRMWInst::Add, Addr, LiveInValue, + AtomicOrdering::SequentiallyConsistent); + else { + LoadInst *OldVal = Builder.CreateLoad(Addr, "pgocount.promoted"); + auto *NewVal = Builder.CreateAdd(OldVal, LiveInValue); + Builder.CreateStore(NewVal, Addr); + } + } + } + +private: + Instruction *Store; + ArrayRef ExitBlocks; + ArrayRef InsertPts; +}; + +/// A helper class to do register promotion for all profile counter +/// updates in a loop. +/// +class PGOCounterPromoter { +public: + PGOCounterPromoter(ArrayRef Cands, Loop &Loop) + : Candidates(Cands), ExitBlocks(), InsertPts(), ParentLoop(Loop) { + + SmallVector LoopExitBlocks; + SmallPtrSet BlockSet; + ParentLoop.getExitBlocks(LoopExitBlocks); + + for (BasicBlock *ExitBlock : LoopExitBlocks) { + if (BlockSet.insert(ExitBlock).second) { + ExitBlocks.push_back(ExitBlock); + InsertPts.push_back(&*ExitBlock->getFirstInsertionPt()); + } + } + } + + bool run(int64_t *NumPromoted) { + // We can't insert into a catchswitch. + bool HasCatchSwitch = llvm::any_of(ExitBlocks, [](BasicBlock *Exit) { + return isa(Exit->getTerminator()); + }); + + if (HasCatchSwitch) + return false; + + if (!ParentLoop.hasDedicatedExits()) + return false; + + BasicBlock *PH = ParentLoop.getLoopPreheader(); + if (!PH) + return false; + + BasicBlock *H = ParentLoop.getHeader(); + bool TopTested = + ((ParentLoop.getBlocks().size() > 1) && ParentLoop.isLoopExiting(H)); + if (!SpeculativeCounterPromotion && + (TopTested || ParentLoop.getExitingBlock() == nullptr)) + return false; + + unsigned Promoted = 0; + for (auto &Cand : Candidates) { + + SmallVector NewPHIs; + SSAUpdater SSA(&NewPHIs); + Value *InitVal = ConstantInt::get(Cand.first->getType(), 0); + PGOCounterPromoterHelper Promoter(Cand.first, Cand.second, SSA, InitVal, + PH, ExitBlocks, InsertPts); + Promoter.run(SmallVector({Cand.first, Cand.second})); + Promoted++; + if (Promoted >= MaxNumOfPromotionsPerLoop) + break; + (*NumPromoted)++; + if (MaxNumOfPromotions != -1 && *NumPromoted >= MaxNumOfPromotions) + break; + } + + DEBUG(dbgs() << Promoted << " counters promoted for loop (depth=" + << ParentLoop.getLoopDepth() << ")\n"); + return Promoted != 0; + } + +private: + ArrayRef Candidates; + SmallVector ExitBlocks; + SmallVector InsertPts; + Loop &ParentLoop; +}; + } // end anonymous namespace PreservedAnalyses InstrProfiling::run(Module &M, ModuleAnalysisManager &AM) { @@ -147,6 +298,63 @@ static InstrProfIncrementInst *castToIncrementInst(Instruction *Instr) { return dyn_cast(Instr); } +bool InstrProfiling::lowerIntrinsics(Function *F) { + bool MadeChange = false; + PromotionCandidates.clear(); + for (BasicBlock &BB : *F) { + for (auto I = BB.begin(), E = BB.end(); I != E;) { + auto Instr = I++; + InstrProfIncrementInst *Inc = castToIncrementInst(&*Instr); + if (Inc) { + lowerIncrement(Inc); + MadeChange = true; + } else if (auto *Ind = dyn_cast(Instr)) { + lowerValueProfileInst(Ind); + MadeChange = true; + } + } + } + + if (!MadeChange) + return false; + + promoteCounterLoadStores(F); + return true; +} + +bool InstrProfiling::isCounterPromotionEnabled() const { + if (DoCounterPromotion.getNumOccurrences() > 0) + return DoCounterPromotion; + + return Options.DoCounterPromotion; +} + +void InstrProfiling::promoteCounterLoadStores(Function *F) { + if (!isCounterPromotionEnabled()) + return; + + DominatorTree DT(*F); + LoopInfo LI(DT); + DenseMap> LoopPromotionCandidates; + + for (const auto &LoadStore : PromotionCandidates) { + auto *CounterLoad = LoadStore.first; + auto *CounterStore = LoadStore.second; + BasicBlock *BB = CounterLoad->getParent(); + Loop *ParentLoop = LI.getLoopFor(BB); + if (!ParentLoop) + continue; + LoopPromotionCandidates[ParentLoop].emplace_back(CounterLoad, CounterStore); + } + + SmallVector Loops = LI.getLoopsInPreorder(); + + for (auto *Loop : Loops) { + PGOCounterPromoter Promoter(LoopPromotionCandidates[Loop], *Loop); + Promoter.run(&TotalCountersPromoted); + } +} + bool InstrProfiling::run(Module &M, const TargetLibraryInfo &TLI) { bool MadeChange = false; @@ -179,18 +387,7 @@ bool InstrProfiling::run(Module &M, const TargetLibraryInfo &TLI) { } for (Function &F : M) - for (BasicBlock &BB : F) - for (auto I = BB.begin(), E = BB.end(); I != E;) { - auto Instr = I++; - InstrProfIncrementInst *Inc = castToIncrementInst(&*Instr); - if (Inc) { - lowerIncrement(Inc); - MadeChange = true; - } else if (auto *Ind = dyn_cast(Instr)) { - lowerValueProfileInst(Ind); - MadeChange = true; - } - } + MadeChange |= lowerIntrinsics(&F); if (GlobalVariable *CoverageNamesVar = M.getNamedGlobal(getCoverageUnusedNamesVarName())) { @@ -303,9 +500,12 @@ void InstrProfiling::lowerIncrement(InstrProfIncrementInst *Inc) { IRBuilder<> Builder(Inc); uint64_t Index = Inc->getIndex()->getZExtValue(); Value *Addr = Builder.CreateConstInBoundsGEP2_64(Counters, 0, Index); - Value *Count = Builder.CreateLoad(Addr, "pgocount"); - Count = Builder.CreateAdd(Count, Inc->getStep()); - Inc->replaceAllUsesWith(Builder.CreateStore(Count, Addr)); + Value *Load = Builder.CreateLoad(Addr, "pgocount"); + auto *Count = Builder.CreateAdd(Load, Inc->getStep()); + auto *Store = Builder.CreateStore(Count, Addr); + Inc->replaceAllUsesWith(Store); + if (isCounterPromotionEnabled()) + PromotionCandidates.emplace_back(cast(Load), Store); Inc->eraseFromParent(); } diff --git a/contrib/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/contrib/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index b2d95271479c..0e7d11c55397 100644 --- a/contrib/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/contrib/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -1177,7 +1177,7 @@ void MemIntrinsicVisitor::instrumentOneMemIntrinsic(MemIntrinsic &MI) { Builder.CreateCall( Intrinsic::getDeclaration(M, Intrinsic::instrprof_value_profile), {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy), - Builder.getInt64(FuncHash), Builder.CreatePtrToInt(Length, Int64Ty), + Builder.getInt64(FuncHash), Builder.CreateZExtOrTrunc(Length, Int64Ty), Builder.getInt32(IPVK_MemOPSize), Builder.getInt32(CurCtrId)}); ++CurCtrId; } diff --git a/contrib/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/contrib/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 2a4c9526dfcd..28157783daa7 100644 --- a/contrib/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -232,8 +232,7 @@ static bool processSwitch(SwitchInst *SI, LazyValueInfo *LVI) { pred_iterator PB = pred_begin(BB), PE = pred_end(BB); if (PB == PE) return false; - // Analyse each switch case in turn. This is done in reverse order so that - // removing a case doesn't cause trouble for the iteration. + // Analyse each switch case in turn. bool Changed = false; for (auto CI = SI->case_begin(), CE = SI->case_end(); CI != CE;) { ConstantInt *Case = CI->getCaseValue(); @@ -291,7 +290,7 @@ static bool processSwitch(SwitchInst *SI, LazyValueInfo *LVI) { break; } - // Increment the case iterator sense we didn't delete it. + // Increment the case iterator since we didn't delete it. ++CI; } diff --git a/contrib/llvm/lib/Transforms/Scalar/GVN.cpp b/contrib/llvm/lib/Transforms/Scalar/GVN.cpp index 0490d93f6455..c0f628eb61e6 100644 --- a/contrib/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/GVN.cpp @@ -80,9 +80,10 @@ MaxRecurseDepth("max-recurse-depth", cl::Hidden, cl::init(1000), cl::ZeroOrMore, struct llvm::GVN::Expression { uint32_t opcode; Type *type; + bool commutative; SmallVector varargs; - Expression(uint32_t o = ~2U) : opcode(o) {} + Expression(uint32_t o = ~2U) : opcode(o), commutative(false) {} bool operator==(const Expression &other) const { if (opcode != other.opcode) @@ -246,6 +247,7 @@ GVN::Expression GVN::ValueTable::createExpr(Instruction *I) { assert(I->getNumOperands() == 2 && "Unsupported commutative instruction!"); if (e.varargs[0] > e.varargs[1]) std::swap(e.varargs[0], e.varargs[1]); + e.commutative = true; } if (CmpInst *C = dyn_cast(I)) { @@ -256,6 +258,7 @@ GVN::Expression GVN::ValueTable::createExpr(Instruction *I) { Predicate = CmpInst::getSwappedPredicate(Predicate); } e.opcode = (C->getOpcode() << 8) | Predicate; + e.commutative = true; } else if (InsertValueInst *E = dyn_cast(I)) { for (InsertValueInst::idx_iterator II = E->idx_begin(), IE = E->idx_end(); II != IE; ++II) @@ -281,6 +284,7 @@ GVN::Expression GVN::ValueTable::createCmpExpr(unsigned Opcode, Predicate = CmpInst::getSwappedPredicate(Predicate); } e.opcode = (Opcode << 8) | Predicate; + e.commutative = true; return e; } @@ -348,25 +352,25 @@ GVN::ValueTable::~ValueTable() = default; /// add - Insert a value into the table with a specified value number. void GVN::ValueTable::add(Value *V, uint32_t num) { valueNumbering.insert(std::make_pair(V, num)); + if (PHINode *PN = dyn_cast(V)) + NumberingPhi[num] = PN; } uint32_t GVN::ValueTable::lookupOrAddCall(CallInst *C) { if (AA->doesNotAccessMemory(C)) { Expression exp = createExpr(C); - uint32_t &e = expressionNumbering[exp]; - if (!e) e = nextValueNumber++; + uint32_t e = assignExpNewValueNum(exp).first; valueNumbering[C] = e; return e; } else if (AA->onlyReadsMemory(C)) { Expression exp = createExpr(C); - uint32_t &e = expressionNumbering[exp]; - if (!e) { - e = nextValueNumber++; - valueNumbering[C] = e; - return e; + auto ValNum = assignExpNewValueNum(exp); + if (ValNum.second) { + valueNumbering[C] = ValNum.first; + return ValNum.first; } if (!MD) { - e = nextValueNumber++; + uint32_t e = assignExpNewValueNum(exp).first; valueNumbering[C] = e; return e; } @@ -522,23 +526,29 @@ uint32_t GVN::ValueTable::lookupOrAdd(Value *V) { case Instruction::ExtractValue: exp = createExtractvalueExpr(cast(I)); break; + case Instruction::PHI: + valueNumbering[V] = nextValueNumber; + NumberingPhi[nextValueNumber] = cast(V); + return nextValueNumber++; default: valueNumbering[V] = nextValueNumber; return nextValueNumber++; } - uint32_t& e = expressionNumbering[exp]; - if (!e) e = nextValueNumber++; + uint32_t e = assignExpNewValueNum(exp).first; valueNumbering[V] = e; return e; } /// Returns the value number of the specified value. Fails if /// the value has not yet been numbered. -uint32_t GVN::ValueTable::lookup(Value *V) const { +uint32_t GVN::ValueTable::lookup(Value *V, bool Verify) const { DenseMap::const_iterator VI = valueNumbering.find(V); - assert(VI != valueNumbering.end() && "Value not numbered?"); - return VI->second; + if (Verify) { + assert(VI != valueNumbering.end() && "Value not numbered?"); + return VI->second; + } + return (VI != valueNumbering.end()) ? VI->second : 0; } /// Returns the value number of the given comparison, @@ -549,21 +559,28 @@ uint32_t GVN::ValueTable::lookupOrAddCmp(unsigned Opcode, CmpInst::Predicate Predicate, Value *LHS, Value *RHS) { Expression exp = createCmpExpr(Opcode, Predicate, LHS, RHS); - uint32_t& e = expressionNumbering[exp]; - if (!e) e = nextValueNumber++; - return e; + return assignExpNewValueNum(exp).first; } /// Remove all entries from the ValueTable. void GVN::ValueTable::clear() { valueNumbering.clear(); expressionNumbering.clear(); + NumberingPhi.clear(); + PhiTranslateTable.clear(); nextValueNumber = 1; + Expressions.clear(); + ExprIdx.clear(); + nextExprNumber = 0; } /// Remove a value from the value numbering. void GVN::ValueTable::erase(Value *V) { + uint32_t Num = valueNumbering.lookup(V); valueNumbering.erase(V); + // If V is PHINode, V <--> value number is an one-to-one mapping. + if (isa(V)) + NumberingPhi.erase(Num); } /// verifyRemoved - Verify that the value is removed from all internal data @@ -602,7 +619,7 @@ PreservedAnalyses GVN::run(Function &F, FunctionAnalysisManager &AM) { } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void GVN::dump(DenseMap& d) { +LLVM_DUMP_METHOD void GVN::dump(DenseMap& d) const { errs() << "{\n"; for (DenseMap::iterator I = d.begin(), E = d.end(); I != E; ++I) { @@ -1451,6 +1468,95 @@ bool GVN::processLoad(LoadInst *L) { return false; } +/// Return a pair the first field showing the value number of \p Exp and the +/// second field showing whether it is a value number newly created. +std::pair +GVN::ValueTable::assignExpNewValueNum(Expression &Exp) { + uint32_t &e = expressionNumbering[Exp]; + bool CreateNewValNum = !e; + if (CreateNewValNum) { + Expressions.push_back(Exp); + if (ExprIdx.size() < nextValueNumber + 1) + ExprIdx.resize(nextValueNumber * 2); + e = nextValueNumber; + ExprIdx[nextValueNumber++] = nextExprNumber++; + } + return {e, CreateNewValNum}; +} + +/// Return whether all the values related with the same \p num are +/// defined in \p BB. +bool GVN::ValueTable::areAllValsInBB(uint32_t Num, const BasicBlock *BB, + GVN &Gvn) { + LeaderTableEntry *Vals = &Gvn.LeaderTable[Num]; + while (Vals && Vals->BB == BB) + Vals = Vals->Next; + return !Vals; +} + +/// Wrap phiTranslateImpl to provide caching functionality. +uint32_t GVN::ValueTable::phiTranslate(const BasicBlock *Pred, + const BasicBlock *PhiBlock, uint32_t Num, + GVN &Gvn) { + auto FindRes = PhiTranslateTable.find({Num, Pred}); + if (FindRes != PhiTranslateTable.end()) + return FindRes->second; + uint32_t NewNum = phiTranslateImpl(Pred, PhiBlock, Num, Gvn); + PhiTranslateTable.insert({{Num, Pred}, NewNum}); + return NewNum; +} + +/// Translate value number \p Num using phis, so that it has the values of +/// the phis in BB. +uint32_t GVN::ValueTable::phiTranslateImpl(const BasicBlock *Pred, + const BasicBlock *PhiBlock, + uint32_t Num, GVN &Gvn) { + if (PHINode *PN = NumberingPhi[Num]) { + for (unsigned i = 0; i != PN->getNumIncomingValues(); ++i) { + if (PN->getParent() == PhiBlock && PN->getIncomingBlock(i) == Pred) + if (uint32_t TransVal = lookup(PN->getIncomingValue(i), false)) + return TransVal; + } + return Num; + } + + // If there is any value related with Num is defined in a BB other than + // PhiBlock, it cannot depend on a phi in PhiBlock without going through + // a backedge. We can do an early exit in that case to save compile time. + if (!areAllValsInBB(Num, PhiBlock, Gvn)) + return Num; + + if (Num >= ExprIdx.size() || ExprIdx[Num] == 0) + return Num; + Expression Exp = Expressions[ExprIdx[Num]]; + + for (unsigned i = 0; i < Exp.varargs.size(); i++) { + // For InsertValue and ExtractValue, some varargs are index numbers + // instead of value numbers. Those index numbers should not be + // translated. + if ((i > 1 && Exp.opcode == Instruction::InsertValue) || + (i > 0 && Exp.opcode == Instruction::ExtractValue)) + continue; + Exp.varargs[i] = phiTranslate(Pred, PhiBlock, Exp.varargs[i], Gvn); + } + + if (Exp.commutative) { + assert(Exp.varargs.size() == 2 && "Unsupported commutative expression!"); + if (Exp.varargs[0] > Exp.varargs[1]) { + std::swap(Exp.varargs[0], Exp.varargs[1]); + uint32_t Opcode = Exp.opcode >> 8; + if (Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) + Exp.opcode = (Opcode << 8) | + CmpInst::getSwappedPredicate( + static_cast(Exp.opcode & 255)); + } + } + + if (uint32_t NewNum = expressionNumbering[Exp]) + return NewNum; + return Num; +} + // In order to find a leader for a given value number at a // specific basic block, we first obtain the list of all Values for that number, // and then scan the list to find one whose block dominates the block in @@ -1495,6 +1601,15 @@ static bool isOnlyReachableViaThisEdge(const BasicBlockEdge &E, return Pred != nullptr; } + +void GVN::assignBlockRPONumber(Function &F) { + uint32_t NextBlockNumber = 1; + ReversePostOrderTraversal RPOT(&F); + for (BasicBlock *BB : RPOT) + BlockRPONumber[BB] = NextBlockNumber++; +} + + // Tries to replace instruction with const, using information from // ReplaceWithConstMap. bool GVN::replaceOperandsWithConsts(Instruction *Instr) const { @@ -1856,6 +1971,7 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, // Fabricate val-num for dead-code in order to suppress assertion in // performPRE(). assignValNumForDeadCode(); + assignBlockRPONumber(F); bool PREChanged = true; while (PREChanged) { PREChanged = performPRE(F); @@ -1927,7 +2043,7 @@ bool GVN::processBlock(BasicBlock *BB) { // Instantiate an expression in a predecessor that lacked it. bool GVN::performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred, - unsigned int ValNo) { + BasicBlock *Curr, unsigned int ValNo) { // Because we are going top-down through the block, all value numbers // will be available in the predecessor by the time we need them. Any // that weren't originally present will have been instantiated earlier @@ -1945,7 +2061,9 @@ bool GVN::performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred, success = false; break; } - if (Value *V = findLeader(Pred, VN.lookup(Op))) { + uint32_t TValNo = + VN.phiTranslate(Pred, Curr, VN.lookup(Op), *this); + if (Value *V = findLeader(Pred, TValNo)) { Instr->setOperand(i, V); } else { success = false; @@ -1962,10 +2080,12 @@ bool GVN::performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred, Instr->insertBefore(Pred->getTerminator()); Instr->setName(Instr->getName() + ".pre"); Instr->setDebugLoc(Instr->getDebugLoc()); - VN.add(Instr, ValNo); + + unsigned Num = VN.lookupOrAdd(Instr); + VN.add(Instr, Num); // Update the availability map to include the new instruction. - addToLeaderTable(ValNo, Instr, Pred); + addToLeaderTable(Num, Instr, Pred); return true; } @@ -2003,18 +2123,27 @@ bool GVN::performScalarPRE(Instruction *CurInst) { SmallVector, 8> predMap; for (BasicBlock *P : predecessors(CurrentBlock)) { - // We're not interested in PRE where the block is its - // own predecessor, or in blocks with predecessors - // that are not reachable. - if (P == CurrentBlock) { + // We're not interested in PRE where blocks with predecessors that are + // not reachable. + if (!DT->isReachableFromEntry(P)) { NumWithout = 2; break; - } else if (!DT->isReachableFromEntry(P)) { + } + // It is not safe to do PRE when P->CurrentBlock is a loop backedge, and + // when CurInst has operand defined in CurrentBlock (so it may be defined + // by phi in the loop header). + if (BlockRPONumber[P] >= BlockRPONumber[CurrentBlock] && + any_of(CurInst->operands(), [&](const Use &U) { + if (auto *Inst = dyn_cast(U.get())) + return Inst->getParent() == CurrentBlock; + return false; + })) { NumWithout = 2; break; } - Value *predV = findLeader(P, ValNo); + uint32_t TValNo = VN.phiTranslate(P, CurrentBlock, ValNo, *this); + Value *predV = findLeader(P, TValNo); if (!predV) { predMap.push_back(std::make_pair(static_cast(nullptr), P)); PREPred = P; @@ -2054,7 +2183,7 @@ bool GVN::performScalarPRE(Instruction *CurInst) { } // We need to insert somewhere, so let's give it a shot PREInstr = CurInst->clone(); - if (!performScalarPREInsertion(PREInstr, PREPred, ValNo)) { + if (!performScalarPREInsertion(PREInstr, PREPred, CurrentBlock, ValNo)) { // If we failed insertion, make sure we remove the instruction. DEBUG(verifyRemoved(PREInstr)); PREInstr->deleteValue(); @@ -2168,6 +2297,7 @@ bool GVN::iterateOnFunction(Function &F) { void GVN::cleanupGlobalSets() { VN.clear(); LeaderTable.clear(); + BlockRPONumber.clear(); TableAllocator.Reset(); } diff --git a/contrib/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/contrib/llvm/lib/Transforms/Scalar/JumpThreading.cpp index c120036464d0..05293eb0079f 100644 --- a/contrib/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -25,6 +25,7 @@ #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/ConstantRange.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" @@ -576,7 +577,12 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors( // Handle compare with phi operand, where the PHI is defined in this block. if (CmpInst *Cmp = dyn_cast(I)) { assert(Preference == WantInteger && "Compares only produce integers"); - PHINode *PN = dyn_cast(Cmp->getOperand(0)); + Type *CmpType = Cmp->getType(); + Value *CmpLHS = Cmp->getOperand(0); + Value *CmpRHS = Cmp->getOperand(1); + CmpInst::Predicate Pred = Cmp->getPredicate(); + + PHINode *PN = dyn_cast(CmpLHS); if (PN && PN->getParent() == BB) { const DataLayout &DL = PN->getModule()->getDataLayout(); // We can do this simplification if any comparisons fold to true or false. @@ -584,15 +590,15 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors( for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { BasicBlock *PredBB = PN->getIncomingBlock(i); Value *LHS = PN->getIncomingValue(i); - Value *RHS = Cmp->getOperand(1)->DoPHITranslation(BB, PredBB); + Value *RHS = CmpRHS->DoPHITranslation(BB, PredBB); - Value *Res = SimplifyCmpInst(Cmp->getPredicate(), LHS, RHS, {DL}); + Value *Res = SimplifyCmpInst(Pred, LHS, RHS, {DL}); if (!Res) { if (!isa(RHS)) continue; LazyValueInfo::Tristate - ResT = LVI->getPredicateOnEdge(Cmp->getPredicate(), LHS, + ResT = LVI->getPredicateOnEdge(Pred, LHS, cast(RHS), PredBB, BB, CxtI ? CxtI : Cmp); if (ResT == LazyValueInfo::Unknown) @@ -609,27 +615,67 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors( // If comparing a live-in value against a constant, see if we know the // live-in value on any predecessors. - if (isa(Cmp->getOperand(1)) && !Cmp->getType()->isVectorTy()) { - Constant *CmpConst = cast(Cmp->getOperand(1)); + if (isa(CmpRHS) && !CmpType->isVectorTy()) { + Constant *CmpConst = cast(CmpRHS); - if (!isa(Cmp->getOperand(0)) || - cast(Cmp->getOperand(0))->getParent() != BB) { + if (!isa(CmpLHS) || + cast(CmpLHS)->getParent() != BB) { for (BasicBlock *P : predecessors(BB)) { // If the value is known by LazyValueInfo to be a constant in a // predecessor, use that information to try to thread this block. LazyValueInfo::Tristate Res = - LVI->getPredicateOnEdge(Cmp->getPredicate(), Cmp->getOperand(0), + LVI->getPredicateOnEdge(Pred, CmpLHS, CmpConst, P, BB, CxtI ? CxtI : Cmp); if (Res == LazyValueInfo::Unknown) continue; - Constant *ResC = ConstantInt::get(Cmp->getType(), Res); + Constant *ResC = ConstantInt::get(CmpType, Res); Result.push_back(std::make_pair(ResC, P)); } return !Result.empty(); } + // InstCombine can fold some forms of constant range checks into + // (icmp (add (x, C1)), C2). See if we have we have such a thing with + // x as a live-in. + { + using namespace PatternMatch; + Value *AddLHS; + ConstantInt *AddConst; + if (isa(CmpConst) && + match(CmpLHS, m_Add(m_Value(AddLHS), m_ConstantInt(AddConst)))) { + if (!isa(AddLHS) || + cast(AddLHS)->getParent() != BB) { + for (BasicBlock *P : predecessors(BB)) { + // If the value is known by LazyValueInfo to be a ConstantRange in + // a predecessor, use that information to try to thread this + // block. + ConstantRange CR = LVI->getConstantRangeOnEdge( + AddLHS, P, BB, CxtI ? CxtI : cast(CmpLHS)); + // Propagate the range through the addition. + CR = CR.add(AddConst->getValue()); + + // Get the range where the compare returns true. + ConstantRange CmpRange = ConstantRange::makeExactICmpRegion( + Pred, cast(CmpConst)->getValue()); + + Constant *ResC; + if (CmpRange.contains(CR)) + ResC = ConstantInt::getTrue(CmpType); + else if (CmpRange.inverse().contains(CR)) + ResC = ConstantInt::getFalse(CmpType); + else + continue; + + Result.push_back(std::make_pair(ResC, P)); + } + + return !Result.empty(); + } + } + } + // Try to find a constant value for the LHS of a comparison, // and evaluate it statically if we can. PredValueInfoTy LHSVals; @@ -638,8 +684,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors( for (const auto &LHSVal : LHSVals) { Constant *V = LHSVal.first; - Constant *Folded = ConstantExpr::getCompare(Cmp->getPredicate(), - V, CmpConst); + Constant *Folded = ConstantExpr::getCompare(Pred, V, CmpConst); if (Constant *KC = getKnownConstant(Folded, WantInteger)) Result.push_back(std::make_pair(KC, LHSVal.second)); } @@ -752,6 +797,37 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { LVI->eraseBlock(SinglePred); MergeBasicBlockIntoOnlyPred(BB); + // Now that BB is merged into SinglePred (i.e. SinglePred Code followed by + // BB code within one basic block `BB`), we need to invalidate the LVI + // information associated with BB, because the LVI information need not be + // true for all of BB after the merge. For example, + // Before the merge, LVI info and code is as follows: + // SinglePred: + // %y = use of %p + // call @exit() // need not transfer execution to successor. + // assume(%p) // from this point on %p is true + // br label %BB + // BB: + // %x = use of %p + // br label exit + // + // Note that this LVI info for blocks BB and SinglPred is correct for %p + // (info2 and info1 respectively). After the merge and the deletion of the + // LVI info1 for SinglePred. We have the following code: + // BB: + // %y = use of %p + // call @exit() + // assume(%p) + // %x = use of %p <-- LVI info2 is correct from here onwards. + // br label exit + // LVI info2 for BB is incorrect at the beginning of BB. + + // Invalidate LVI information for BB if the LVI is not provably true for + // all of BB. + if (any_of(*BB, [](Instruction &I) { + return !isGuaranteedToTransferExecutionToSuccessor(&I); + })) + LVI->eraseBlock(BB); return true; } } diff --git a/contrib/llvm/lib/Transforms/Scalar/LoadCombine.cpp b/contrib/llvm/lib/Transforms/Scalar/LoadCombine.cpp deleted file mode 100644 index 025ba1bfedc1..000000000000 --- a/contrib/llvm/lib/Transforms/Scalar/LoadCombine.cpp +++ /dev/null @@ -1,295 +0,0 @@ -//===- LoadCombine.cpp - Combine Adjacent Loads ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// \file -/// This transformation combines adjacent loads. -/// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/AliasSetTracker.h" -#include "llvm/Analysis/GlobalsModRef.h" -#include "llvm/Analysis/TargetFolder.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Dominators.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/Pass.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Scalar.h" - -using namespace llvm; - -#define DEBUG_TYPE "load-combine" - -STATISTIC(NumLoadsAnalyzed, "Number of loads analyzed for combining"); -STATISTIC(NumLoadsCombined, "Number of loads combined"); - -#define LDCOMBINE_NAME "Combine Adjacent Loads" - -namespace { -struct PointerOffsetPair { - Value *Pointer; - APInt Offset; -}; - -struct LoadPOPPair { - LoadInst *Load; - PointerOffsetPair POP; - /// \brief The new load needs to be created before the first load in IR order. - unsigned InsertOrder; -}; - -class LoadCombine : public BasicBlockPass { - LLVMContext *C; - AliasAnalysis *AA; - DominatorTree *DT; - -public: - LoadCombine() : BasicBlockPass(ID), C(nullptr), AA(nullptr) { - initializeLoadCombinePass(*PassRegistry::getPassRegistry()); - } - - using llvm::Pass::doInitialization; - bool doInitialization(Function &) override; - bool runOnBasicBlock(BasicBlock &BB) override; - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesCFG(); - AU.addRequired(); - AU.addRequired(); - AU.addPreserved(); - } - - StringRef getPassName() const override { return LDCOMBINE_NAME; } - static char ID; - - typedef IRBuilder BuilderTy; - -private: - BuilderTy *Builder; - - PointerOffsetPair getPointerOffsetPair(LoadInst &); - bool combineLoads(DenseMap> &); - bool aggregateLoads(SmallVectorImpl &); - bool combineLoads(SmallVectorImpl &); -}; -} - -bool LoadCombine::doInitialization(Function &F) { - DEBUG(dbgs() << "LoadCombine function: " << F.getName() << "\n"); - C = &F.getContext(); - return true; -} - -PointerOffsetPair LoadCombine::getPointerOffsetPair(LoadInst &LI) { - auto &DL = LI.getModule()->getDataLayout(); - - PointerOffsetPair POP; - POP.Pointer = LI.getPointerOperand(); - unsigned BitWidth = DL.getPointerSizeInBits(LI.getPointerAddressSpace()); - POP.Offset = APInt(BitWidth, 0); - - while (isa(POP.Pointer) || isa(POP.Pointer)) { - if (auto *GEP = dyn_cast(POP.Pointer)) { - APInt LastOffset = POP.Offset; - if (!GEP->accumulateConstantOffset(DL, POP.Offset)) { - // Can't handle GEPs with variable indices. - POP.Offset = LastOffset; - return POP; - } - POP.Pointer = GEP->getPointerOperand(); - } else if (auto *BC = dyn_cast(POP.Pointer)) { - POP.Pointer = BC->getOperand(0); - } - } - return POP; -} - -bool LoadCombine::combineLoads( - DenseMap> &LoadMap) { - bool Combined = false; - for (auto &Loads : LoadMap) { - if (Loads.second.size() < 2) - continue; - std::sort(Loads.second.begin(), Loads.second.end(), - [](const LoadPOPPair &A, const LoadPOPPair &B) { - return A.POP.Offset.slt(B.POP.Offset); - }); - if (aggregateLoads(Loads.second)) - Combined = true; - } - return Combined; -} - -/// \brief Try to aggregate loads from a sorted list of loads to be combined. -/// -/// It is guaranteed that no writes occur between any of the loads. All loads -/// have the same base pointer. There are at least two loads. -bool LoadCombine::aggregateLoads(SmallVectorImpl &Loads) { - assert(Loads.size() >= 2 && "Insufficient loads!"); - LoadInst *BaseLoad = nullptr; - SmallVector AggregateLoads; - bool Combined = false; - bool ValidPrevOffset = false; - APInt PrevOffset; - uint64_t PrevSize = 0; - for (auto &L : Loads) { - if (ValidPrevOffset == false) { - BaseLoad = L.Load; - PrevOffset = L.POP.Offset; - PrevSize = L.Load->getModule()->getDataLayout().getTypeStoreSize( - L.Load->getType()); - AggregateLoads.push_back(L); - ValidPrevOffset = true; - continue; - } - if (L.Load->getAlignment() > BaseLoad->getAlignment()) - continue; - APInt PrevEnd = PrevOffset + PrevSize; - if (L.POP.Offset.sgt(PrevEnd)) { - // No other load will be combinable - if (combineLoads(AggregateLoads)) - Combined = true; - AggregateLoads.clear(); - ValidPrevOffset = false; - continue; - } - if (L.POP.Offset != PrevEnd) - // This load is offset less than the size of the last load. - // FIXME: We may want to handle this case. - continue; - PrevOffset = L.POP.Offset; - PrevSize = L.Load->getModule()->getDataLayout().getTypeStoreSize( - L.Load->getType()); - AggregateLoads.push_back(L); - } - if (combineLoads(AggregateLoads)) - Combined = true; - return Combined; -} - -/// \brief Given a list of combinable load. Combine the maximum number of them. -bool LoadCombine::combineLoads(SmallVectorImpl &Loads) { - // Remove loads from the end while the size is not a power of 2. - unsigned TotalSize = 0; - for (const auto &L : Loads) - TotalSize += L.Load->getType()->getPrimitiveSizeInBits(); - while (TotalSize != 0 && !isPowerOf2_32(TotalSize)) - TotalSize -= Loads.pop_back_val().Load->getType()->getPrimitiveSizeInBits(); - if (Loads.size() < 2) - return false; - - DEBUG({ - dbgs() << "***** Combining Loads ******\n"; - for (const auto &L : Loads) { - dbgs() << L.POP.Offset << ": " << *L.Load << "\n"; - } - }); - - // Find first load. This is where we put the new load. - LoadPOPPair FirstLP; - FirstLP.InsertOrder = -1u; - for (const auto &L : Loads) - if (L.InsertOrder < FirstLP.InsertOrder) - FirstLP = L; - - unsigned AddressSpace = - FirstLP.POP.Pointer->getType()->getPointerAddressSpace(); - - Builder->SetInsertPoint(FirstLP.Load); - Value *Ptr = Builder->CreateConstGEP1_64( - Builder->CreatePointerCast(Loads[0].POP.Pointer, - Builder->getInt8PtrTy(AddressSpace)), - Loads[0].POP.Offset.getSExtValue()); - LoadInst *NewLoad = new LoadInst( - Builder->CreatePointerCast( - Ptr, PointerType::get(IntegerType::get(Ptr->getContext(), TotalSize), - Ptr->getType()->getPointerAddressSpace())), - Twine(Loads[0].Load->getName()) + ".combined", false, - Loads[0].Load->getAlignment(), FirstLP.Load); - - for (const auto &L : Loads) { - Builder->SetInsertPoint(L.Load); - Value *V = Builder->CreateExtractInteger( - L.Load->getModule()->getDataLayout(), NewLoad, - cast(L.Load->getType()), - (L.POP.Offset - Loads[0].POP.Offset).getZExtValue(), "combine.extract"); - L.Load->replaceAllUsesWith(V); - } - - NumLoadsCombined += Loads.size(); - return true; -} - -bool LoadCombine::runOnBasicBlock(BasicBlock &BB) { - if (skipBasicBlock(BB)) - return false; - - AA = &getAnalysis().getAAResults(); - DT = &getAnalysis().getDomTree(); - - // Skip analysing dead blocks (not forward reachable from function entry). - if (!DT->isReachableFromEntry(&BB)) { - DEBUG(dbgs() << "LC: skipping unreachable " << BB.getName() << - " in " << BB.getParent()->getName() << "\n"); - return false; - } - - IRBuilder TheBuilder( - BB.getContext(), TargetFolder(BB.getModule()->getDataLayout())); - Builder = &TheBuilder; - - DenseMap> LoadMap; - AliasSetTracker AST(*AA); - - bool Combined = false; - unsigned Index = 0; - for (auto &I : BB) { - if (I.mayThrow() || AST.containsUnknown(&I)) { - if (combineLoads(LoadMap)) - Combined = true; - LoadMap.clear(); - AST.clear(); - continue; - } - if (I.mayWriteToMemory()) { - AST.add(&I); - continue; - } - LoadInst *LI = dyn_cast(&I); - if (!LI) - continue; - ++NumLoadsAnalyzed; - if (!LI->isSimple() || !LI->getType()->isIntegerTy()) - continue; - auto POP = getPointerOffsetPair(*LI); - if (!POP.Pointer) - continue; - LoadMap[POP.Pointer].push_back({LI, std::move(POP), Index++}); - AST.add(LI); - } - if (combineLoads(LoadMap)) - Combined = true; - return Combined; -} - -char LoadCombine::ID = 0; - -BasicBlockPass *llvm::createLoadCombinePass() { - return new LoadCombine(); -} - -INITIALIZE_PASS_BEGIN(LoadCombine, "load-combine", LDCOMBINE_NAME, false, false) -INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) -INITIALIZE_PASS_END(LoadCombine, "load-combine", LDCOMBINE_NAME, false, false) diff --git a/contrib/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/contrib/llvm/lib/Transforms/Scalar/LoopDeletion.cpp index 3151ccd279c4..c41cc42db5e2 100644 --- a/contrib/llvm/lib/Transforms/Scalar/LoopDeletion.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/LoopDeletion.cpp @@ -31,20 +31,19 @@ using namespace llvm; STATISTIC(NumDeleted, "Number of loops deleted"); /// This function deletes dead loops. The caller of this function needs to -/// guarantee that the loop is infact dead. Here we handle two kinds of dead +/// guarantee that the loop is infact dead. Here we handle two kinds of dead /// loop. The first kind (\p isLoopDead) is where only invariant values from /// within the loop are used outside of it. The second kind (\p /// isLoopNeverExecuted) is where the loop is provably never executed. We can -/// always remove never executed loops since they will not cause any -/// difference to program behaviour. +/// always remove never executed loops since they will not cause any difference +/// to program behaviour. /// /// This also updates the relevant analysis information in \p DT, \p SE, and \p /// LI. It also updates the loop PM if an updater struct is provided. // TODO: This function will be used by loop-simplifyCFG as well. So, move this // to LoopUtils.cpp static void deleteDeadLoop(Loop *L, DominatorTree &DT, ScalarEvolution &SE, - LoopInfo &LI, bool LoopIsNeverExecuted, - LPMUpdater *Updater = nullptr); + LoopInfo &LI, LPMUpdater *Updater = nullptr); /// Determines if a loop is dead. /// /// This assumes that we've already checked for unique exit and exiting blocks, @@ -168,7 +167,14 @@ static bool deleteLoopIfDead(Loop *L, DominatorTree &DT, ScalarEvolution &SE, BasicBlock *ExitBlock = L->getUniqueExitBlock(); if (ExitBlock && isLoopNeverExecuted(L)) { - deleteDeadLoop(L, DT, SE, LI, true /* LoopIsNeverExecuted */, Updater); + // Set incoming value to undef for phi nodes in the exit block. + BasicBlock::iterator BI = ExitBlock->begin(); + while (PHINode *P = dyn_cast(BI)) { + for (unsigned i = 0; i < P->getNumIncomingValues(); i++) + P->setIncomingValue(i, UndefValue::get(P->getType())); + BI++; + } + deleteDeadLoop(L, DT, SE, LI, Updater); ++NumDeleted; return true; } @@ -196,15 +202,14 @@ static bool deleteLoopIfDead(Loop *L, DominatorTree &DT, ScalarEvolution &SE, if (isa(S)) return Changed; - deleteDeadLoop(L, DT, SE, LI, false /* LoopIsNeverExecuted */, Updater); + deleteDeadLoop(L, DT, SE, LI, Updater); ++NumDeleted; return true; } static void deleteDeadLoop(Loop *L, DominatorTree &DT, ScalarEvolution &SE, - LoopInfo &LI, bool LoopIsNeverExecuted, - LPMUpdater *Updater) { + LoopInfo &LI, LPMUpdater *Updater) { assert(L->isLCSSAForm(DT) && "Expected LCSSA!"); auto *Preheader = L->getLoopPreheader(); assert(Preheader && "Preheader should exist!"); @@ -227,6 +232,8 @@ static void deleteDeadLoop(Loop *L, DominatorTree &DT, ScalarEvolution &SE, auto *ExitBlock = L->getUniqueExitBlock(); assert(ExitBlock && "Should have a unique exit block!"); + assert(L->hasDedicatedExits() && "Loop should have dedicated exits!"); + // Connect the preheader directly to the exit block. // Even when the loop is never executed, we cannot remove the edge from the // source block to the exit block. Consider the case where the unexecuted loop @@ -236,20 +243,28 @@ static void deleteDeadLoop(Loop *L, DominatorTree &DT, ScalarEvolution &SE, // non-loop, it will be deleted in a future iteration of loop deletion pass. Preheader->getTerminator()->replaceUsesOfWith(L->getHeader(), ExitBlock); - SmallVector ExitingBlocks; - L->getExitingBlocks(ExitingBlocks); // Rewrite phis in the exit block to get their inputs from the Preheader // instead of the exiting block. - BasicBlock *ExitingBlock = ExitingBlocks[0]; BasicBlock::iterator BI = ExitBlock->begin(); while (PHINode *P = dyn_cast(BI)) { - int j = P->getBasicBlockIndex(ExitingBlock); - assert(j >= 0 && "Can't find exiting block in exit block's phi node!"); - if (LoopIsNeverExecuted) - P->setIncomingValue(j, UndefValue::get(P->getType())); - P->setIncomingBlock(j, Preheader); - for (unsigned i = 1; i < ExitingBlocks.size(); ++i) - P->removeIncomingValue(ExitingBlocks[i]); + // Set the zero'th element of Phi to be from the preheader and remove all + // other incoming values. Given the loop has dedicated exits, all other + // incoming values must be from the exiting blocks. + int PredIndex = 0; + P->setIncomingBlock(PredIndex, Preheader); + // Removes all incoming values from all other exiting blocks (including + // duplicate values from an exiting block). + // Nuke all entries except the zero'th entry which is the preheader entry. + // NOTE! We need to remove Incoming Values in the reverse order as done + // below, to keep the indices valid for deletion (removeIncomingValues + // updates getNumIncomingValues and shifts all values down into the operand + // being deleted). + for (unsigned i = 0, e = P->getNumIncomingValues() - 1; i != e; ++i) + P->removeIncomingValue(e-i, false); + + assert((P->getNumIncomingValues() == 1 && + P->getIncomingBlock(PredIndex) == Preheader) && + "Should have exactly one value and that's from the preheader!"); ++BI; } diff --git a/contrib/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/contrib/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp index b027278b24f2..73436f13c94e 100644 --- a/contrib/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -131,7 +131,7 @@ static cl::opt EnablePhiElim( // The flag adds instruction count to solutions cost comparision. static cl::opt InsnsCost( - "lsr-insns-cost", cl::Hidden, cl::init(true), + "lsr-insns-cost", cl::Hidden, cl::init(false), cl::desc("Add instruction count to a LSR cost model")); // Flag to choose how to narrow complex lsr solution diff --git a/contrib/llvm/lib/Transforms/Scalar/NewGVN.cpp b/contrib/llvm/lib/Transforms/Scalar/NewGVN.cpp index cbbd55512c9f..7a7624f77542 100644 --- a/contrib/llvm/lib/Transforms/Scalar/NewGVN.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/NewGVN.cpp @@ -1244,27 +1244,24 @@ const Expression *NewGVN::performSymbolicStoreEvaluation(Instruction *I) const { // only do this for simple stores, we should expand to cover memcpys, etc. const auto *LastStore = createStoreExpression(SI, StoreRHS); const auto *LastCC = ExpressionToClass.lookup(LastStore); - // Basically, check if the congruence class the store is in is defined by a - // store that isn't us, and has the same value. MemorySSA takes care of - // ensuring the store has the same memory state as us already. - // The RepStoredValue gets nulled if all the stores disappear in a class, so - // we don't need to check if the class contains a store besides us. - if (LastCC && - LastCC->getStoredValue() == lookupOperandLeader(SI->getValueOperand())) + // We really want to check whether the expression we matched was a store. No + // easy way to do that. However, we can check that the class we found has a + // store, which, assuming the value numbering state is not corrupt, is + // sufficient, because we must also be equivalent to that store's expression + // for it to be in the same class as the load. + if (LastCC && LastCC->getStoredValue() == LastStore->getStoredValue()) return LastStore; - deleteExpression(LastStore); // Also check if our value operand is defined by a load of the same memory // location, and the memory state is the same as it was then (otherwise, it // could have been overwritten later. See test32 in // transforms/DeadStoreElimination/simple.ll). - if (auto *LI = - dyn_cast(lookupOperandLeader(SI->getValueOperand()))) { + if (auto *LI = dyn_cast(LastStore->getStoredValue())) if ((lookupOperandLeader(LI->getPointerOperand()) == - lookupOperandLeader(SI->getPointerOperand())) && + LastStore->getOperand(0)) && (lookupMemoryLeader(getMemoryAccess(LI)->getDefiningAccess()) == StoreRHS)) - return createStoreExpression(SI, StoreRHS); - } + return LastStore; + deleteExpression(LastStore); } // If the store is not equivalent to anything, value number it as a store that @@ -2332,9 +2329,7 @@ void NewGVN::updateReachableEdge(BasicBlock *From, BasicBlock *To) { // see if we know some constant value for it already. Value *NewGVN::findConditionEquivalence(Value *Cond) const { auto Result = lookupOperandLeader(Cond); - if (isa(Result)) - return Result; - return nullptr; + return isa(Result) ? Result : nullptr; } // Process the outgoing edges of a block for reachability. @@ -3014,14 +3009,27 @@ void NewGVN::verifyIterationSettled(Function &F) { // a no-longer valid StoreExpression. void NewGVN::verifyStoreExpressions() const { #ifndef NDEBUG - DenseSet> StoreExpressionSet; + // This is the only use of this, and it's not worth defining a complicated + // densemapinfo hash/equality function for it. + std::set< + std::pair>> + StoreExpressionSet; for (const auto &KV : ExpressionToClass) { if (auto *SE = dyn_cast(KV.first)) { // Make sure a version that will conflict with loads is not already there - auto Res = - StoreExpressionSet.insert({SE->getOperand(0), SE->getMemoryLeader()}); - assert(Res.second && - "Stored expression conflict exists in expression table"); + auto Res = StoreExpressionSet.insert( + {SE->getOperand(0), std::make_tuple(SE->getMemoryLeader(), KV.second, + SE->getStoredValue())}); + bool Okay = Res.second; + // It's okay to have the same expression already in there if it is + // identical in nature. + // This can happen when the leader of the stored value changes over time. + if (!Okay) + Okay = (std::get<1>(Res.first->second) == KV.second) && + (lookupOperandLeader(std::get<2>(Res.first->second)) == + lookupOperandLeader(SE->getStoredValue())); + assert(Okay && "Stored expression conflict exists in expression table"); auto *ValueExpr = ValueToExpression.lookup(SE->getStoreInst()); assert(ValueExpr && ValueExpr->equals(*SE) && "StoreExpression in ExpressionToClass is not latest " diff --git a/contrib/llvm/lib/Transforms/Scalar/Reassociate.cpp b/contrib/llvm/lib/Transforms/Scalar/Reassociate.cpp index a20890b22603..6da551bd7efd 100644 --- a/contrib/llvm/lib/Transforms/Scalar/Reassociate.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -35,6 +35,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" @@ -106,11 +107,12 @@ XorOpnd::XorOpnd(Value *V) { I->getOpcode() == Instruction::And)) { Value *V0 = I->getOperand(0); Value *V1 = I->getOperand(1); - if (isa(V0)) + const APInt *C; + if (match(V0, PatternMatch::m_APInt(C))) std::swap(V0, V1); - if (ConstantInt *C = dyn_cast(V1)) { - ConstPart = C->getValue(); + if (match(V1, PatternMatch::m_APInt(C))) { + ConstPart = *C; SymbolicPart = V0; isOr = (I->getOpcode() == Instruction::Or); return; @@ -119,7 +121,7 @@ XorOpnd::XorOpnd(Value *V) { // view the operand as "V | 0" SymbolicPart = V; - ConstPart = APInt::getNullValue(V->getType()->getIntegerBitWidth()); + ConstPart = APInt::getNullValue(V->getType()->getScalarSizeInBits()); isOr = true; } @@ -955,8 +957,8 @@ static BinaryOperator *ConvertShiftToMul(Instruction *Shl) { /// Scan backwards and forwards among values with the same rank as element i /// to see if X exists. If X does not exist, return i. This is useful when /// scanning for 'x' when we see '-x' because they both get the same rank. -static unsigned FindInOperandList(SmallVectorImpl &Ops, unsigned i, - Value *X) { +static unsigned FindInOperandList(const SmallVectorImpl &Ops, + unsigned i, Value *X) { unsigned XRank = Ops[i].Rank; unsigned e = Ops.size(); for (unsigned j = i+1; j != e && Ops[j].Rank == XRank; ++j) { @@ -1134,20 +1136,19 @@ static Value *OptimizeAndOrXor(unsigned Opcode, /// instruction. There are two special cases: 1) if the constant operand is 0, /// it will return NULL. 2) if the constant is ~0, the symbolic operand will /// be returned. -static Value *createAndInstr(Instruction *InsertBefore, Value *Opnd, +static Value *createAndInstr(Instruction *InsertBefore, Value *Opnd, const APInt &ConstOpnd) { - if (ConstOpnd != 0) { - if (!ConstOpnd.isAllOnesValue()) { - LLVMContext &Ctx = Opnd->getType()->getContext(); - Instruction *I; - I = BinaryOperator::CreateAnd(Opnd, ConstantInt::get(Ctx, ConstOpnd), - "and.ra", InsertBefore); - I->setDebugLoc(InsertBefore->getDebugLoc()); - return I; - } + if (ConstOpnd.isNullValue()) + return nullptr; + + if (ConstOpnd.isAllOnesValue()) return Opnd; - } - return nullptr; + + Instruction *I = BinaryOperator::CreateAnd( + Opnd, ConstantInt::get(Opnd->getType(), ConstOpnd), "and.ra", + InsertBefore); + I->setDebugLoc(InsertBefore->getDebugLoc()); + return I; } // Helper function of OptimizeXor(). It tries to simplify "Opnd1 ^ ConstOpnd" @@ -1163,24 +1164,24 @@ bool ReassociatePass::CombineXorOpnd(Instruction *I, XorOpnd *Opnd1, // = ((x | c1) ^ c1) ^ (c1 ^ c2) // = (x & ~c1) ^ (c1 ^ c2) // It is useful only when c1 == c2. - if (Opnd1->isOrExpr() && Opnd1->getConstPart() != 0) { - if (!Opnd1->getValue()->hasOneUse()) - return false; + if (!Opnd1->isOrExpr() || Opnd1->getConstPart().isNullValue()) + return false; - const APInt &C1 = Opnd1->getConstPart(); - if (C1 != ConstOpnd) - return false; + if (!Opnd1->getValue()->hasOneUse()) + return false; - Value *X = Opnd1->getSymbolicPart(); - Res = createAndInstr(I, X, ~C1); - // ConstOpnd was C2, now C1 ^ C2. - ConstOpnd ^= C1; + const APInt &C1 = Opnd1->getConstPart(); + if (C1 != ConstOpnd) + return false; - if (Instruction *T = dyn_cast(Opnd1->getValue())) - RedoInsts.insert(T); - return true; - } - return false; + Value *X = Opnd1->getSymbolicPart(); + Res = createAndInstr(I, X, ~C1); + // ConstOpnd was C2, now C1 ^ C2. + ConstOpnd ^= C1; + + if (Instruction *T = dyn_cast(Opnd1->getValue())) + RedoInsts.insert(T); + return true; } @@ -1221,8 +1222,8 @@ bool ReassociatePass::CombineXorOpnd(Instruction *I, XorOpnd *Opnd1, APInt C3((~C1) ^ C2); // Do not increase code size! - if (C3 != 0 && !C3.isAllOnesValue()) { - int NewInstNum = ConstOpnd != 0 ? 1 : 2; + if (!C3.isNullValue() && !C3.isAllOnesValue()) { + int NewInstNum = ConstOpnd.getBoolValue() ? 1 : 2; if (NewInstNum > DeadInstNum) return false; } @@ -1238,8 +1239,8 @@ bool ReassociatePass::CombineXorOpnd(Instruction *I, XorOpnd *Opnd1, APInt C3 = C1 ^ C2; // Do not increase code size - if (C3 != 0 && !C3.isAllOnesValue()) { - int NewInstNum = ConstOpnd != 0 ? 1 : 2; + if (!C3.isNullValue() && !C3.isAllOnesValue()) { + int NewInstNum = ConstOpnd.getBoolValue() ? 1 : 2; if (NewInstNum > DeadInstNum) return false; } @@ -1279,17 +1280,20 @@ Value *ReassociatePass::OptimizeXor(Instruction *I, SmallVector Opnds; SmallVector OpndPtrs; Type *Ty = Ops[0].Op->getType(); - APInt ConstOpnd(Ty->getIntegerBitWidth(), 0); + APInt ConstOpnd(Ty->getScalarSizeInBits(), 0); // Step 1: Convert ValueEntry to XorOpnd for (unsigned i = 0, e = Ops.size(); i != e; ++i) { Value *V = Ops[i].Op; - if (!isa(V)) { + const APInt *C; + // TODO: Support non-splat vectors. + if (match(V, PatternMatch::m_APInt(C))) { + ConstOpnd ^= *C; + } else { XorOpnd O(V); O.setSymbolicRank(getRank(O.getSymbolicPart())); Opnds.push_back(O); - } else - ConstOpnd ^= cast(V)->getValue(); + } } // NOTE: From this point on, do *NOT* add/delete element to/from "Opnds". @@ -1327,7 +1331,8 @@ Value *ReassociatePass::OptimizeXor(Instruction *I, Value *CV; // Step 3.1: Try simplifying "CurrOpnd ^ ConstOpnd" - if (ConstOpnd != 0 && CombineXorOpnd(I, CurrOpnd, ConstOpnd, CV)) { + if (!ConstOpnd.isNullValue() && + CombineXorOpnd(I, CurrOpnd, ConstOpnd, CV)) { Changed = true; if (CV) *CurrOpnd = XorOpnd(CV); @@ -1369,17 +1374,17 @@ Value *ReassociatePass::OptimizeXor(Instruction *I, ValueEntry VE(getRank(O.getValue()), O.getValue()); Ops.push_back(VE); } - if (ConstOpnd != 0) { - Value *C = ConstantInt::get(Ty->getContext(), ConstOpnd); + if (!ConstOpnd.isNullValue()) { + Value *C = ConstantInt::get(Ty, ConstOpnd); ValueEntry VE(getRank(C), C); Ops.push_back(VE); } - int Sz = Ops.size(); + unsigned Sz = Ops.size(); if (Sz == 1) return Ops.back().Op; - else if (Sz == 0) { - assert(ConstOpnd == 0); - return ConstantInt::get(Ty->getContext(), ConstOpnd); + if (Sz == 0) { + assert(ConstOpnd.isNullValue()); + return ConstantInt::get(Ty, ConstOpnd); } } @@ -1627,8 +1632,8 @@ Value *ReassociatePass::OptimizeAdd(Instruction *I, /// ((((x*y)*x)*y)*x) -> [(x, 3), (y, 2)] /// /// \returns Whether any factors have a power greater than one. -bool ReassociatePass::collectMultiplyFactors(SmallVectorImpl &Ops, - SmallVectorImpl &Factors) { +static bool collectMultiplyFactors(SmallVectorImpl &Ops, + SmallVectorImpl &Factors) { // FIXME: Have Ops be (ValueEntry, Multiplicity) pairs, simplifying this. // Compute the sum of powers of simplifiable factors. unsigned FactorPowerSum = 0; @@ -1999,11 +2004,6 @@ void ReassociatePass::OptimizeInst(Instruction *I) { if (I->isCommutative()) canonicalizeOperands(I); - // TODO: We should optimize vector Xor instructions, but they are - // currently unsupported. - if (I->getType()->isVectorTy() && I->getOpcode() == Instruction::Xor) - return; - // Don't optimize floating point instructions that don't have unsafe algebra. if (I->getType()->isFPOrFPVectorTy() && !I->hasUnsafeAlgebra()) return; diff --git a/contrib/llvm/lib/Transforms/Scalar/SCCP.cpp b/contrib/llvm/lib/Transforms/Scalar/SCCP.cpp index c6929c33b3e9..7a6fa1711411 100644 --- a/contrib/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -536,9 +536,10 @@ class SCCPSolver : public InstVisitor { void visitUnreachableInst(TerminatorInst &I) { /*returns void*/ } void visitFenceInst (FenceInst &I) { /*returns void*/ } void visitInstruction(Instruction &I) { - // If a new instruction is added to LLVM that we don't handle. + // All the instructions we don't do any special handling for just + // go to overdefined. DEBUG(dbgs() << "SCCP: Don't know how to handle: " << I << '\n'); - markOverdefined(&I); // Just in case + markOverdefined(&I); } }; @@ -1814,15 +1815,11 @@ static bool runIPSCCP(Module &M, const DataLayout &DL, if (F.isDeclaration()) continue; - if (Solver.isBlockExecutable(&F.front())) { + if (Solver.isBlockExecutable(&F.front())) for (Function::arg_iterator AI = F.arg_begin(), E = F.arg_end(); AI != E; - ++AI) { - if (AI->use_empty()) - continue; - if (tryToReplaceWithConstant(Solver, &*AI)) + ++AI) + if (!AI->use_empty() && tryToReplaceWithConstant(Solver, &*AI)) ++IPNumArgsElimed; - } - } for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) { if (!Solver.isBlockExecutable(&*BB)) { diff --git a/contrib/llvm/lib/Transforms/Scalar/SROA.cpp b/contrib/llvm/lib/Transforms/Scalar/SROA.cpp index 1527f15f18a3..80fbbeb6829b 100644 --- a/contrib/llvm/lib/Transforms/Scalar/SROA.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/SROA.cpp @@ -1252,7 +1252,7 @@ static bool isSafeSelectToSpeculate(SelectInst &SI) { if (!LI || !LI->isSimple()) return false; - // Both operands to the select need to be dereferencable, either + // Both operands to the select need to be dereferenceable, either // absolutely (e.g. allocas) or at this point because we can see other // accesses to it. if (!isSafeToLoadUnconditionally(TValue, LI->getAlignment(), DL, LI)) @@ -1637,8 +1637,17 @@ static bool canConvertValue(const DataLayout &DL, Type *OldTy, Type *NewTy) { return cast(NewTy)->getPointerAddressSpace() == cast(OldTy)->getPointerAddressSpace(); } - if (NewTy->isIntegerTy() || OldTy->isIntegerTy()) - return true; + + // We can convert integers to integral pointers, but not to non-integral + // pointers. + if (OldTy->isIntegerTy()) + return !DL.isNonIntegralPointerType(NewTy); + + // We can convert integral pointers to integers, but non-integral pointers + // need to remain pointers. + if (!DL.isNonIntegralPointerType(OldTy)) + return NewTy->isIntegerTy(); + return false; } diff --git a/contrib/llvm/lib/Transforms/Scalar/Scalar.cpp b/contrib/llvm/lib/Transforms/Scalar/Scalar.cpp index 850a01114eeb..ce6f93eb0c15 100644 --- a/contrib/llvm/lib/Transforms/Scalar/Scalar.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/Scalar.cpp @@ -91,7 +91,6 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) { initializeSeparateConstOffsetFromGEPPass(Registry); initializeSpeculativeExecutionLegacyPassPass(Registry); initializeStraightLineStrengthReducePass(Registry); - initializeLoadCombinePass(Registry); initializePlaceBackedgeSafepointsImplPass(Registry); initializePlaceSafepointsPass(Registry); initializeFloat2IntLegacyPassPass(Registry); diff --git a/contrib/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp b/contrib/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp index 3e5993618c4c..9397b87cdf56 100644 --- a/contrib/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ b/contrib/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -321,7 +321,7 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls) { /// instruction from after the call to before the call, assuming that all /// instructions between the call and this instruction are movable. /// -static bool canMoveAboveCall(Instruction *I, CallInst *CI) { +static bool canMoveAboveCall(Instruction *I, CallInst *CI, AliasAnalysis *AA) { // FIXME: We can move load/store/call/free instructions above the call if the // call does not mod/ref the memory location being processed. if (I->mayHaveSideEffects()) // This also handles volatile loads. @@ -332,10 +332,10 @@ static bool canMoveAboveCall(Instruction *I, CallInst *CI) { if (CI->mayHaveSideEffects()) { // Non-volatile loads may be moved above a call with side effects if it // does not write to memory and the load provably won't trap. - // FIXME: Writes to memory only matter if they may alias the pointer + // Writes to memory only matter if they may alias the pointer // being loaded from. const DataLayout &DL = L->getModule()->getDataLayout(); - if (CI->mayWriteToMemory() || + if ((AA->getModRefInfo(CI, MemoryLocation::get(L)) & MRI_Mod) || !isSafeToLoadUnconditionally(L->getPointerOperand(), L->getAlignment(), DL, L)) return false; @@ -492,10 +492,11 @@ static CallInst *findTRECandidate(Instruction *TI, return CI; } -static bool -eliminateRecursiveTailCall(CallInst *CI, ReturnInst *Ret, BasicBlock *&OldEntry, - bool &TailCallsAreMarkedTail, - SmallVectorImpl &ArgumentPHIs) { +static bool eliminateRecursiveTailCall(CallInst *CI, ReturnInst *Ret, + BasicBlock *&OldEntry, + bool &TailCallsAreMarkedTail, + SmallVectorImpl &ArgumentPHIs, + AliasAnalysis *AA) { // If we are introducing accumulator recursion to eliminate operations after // the call instruction that are both associative and commutative, the initial // value for the accumulator is placed in this variable. If this value is set @@ -515,7 +516,8 @@ eliminateRecursiveTailCall(CallInst *CI, ReturnInst *Ret, BasicBlock *&OldEntry, // Check that this is the case now. BasicBlock::iterator BBI(CI); for (++BBI; &*BBI != Ret; ++BBI) { - if (canMoveAboveCall(&*BBI, CI)) continue; + if (canMoveAboveCall(&*BBI, CI, AA)) + continue; // If we can't move the instruction above the call, it might be because it // is an associative and commutative operation that could be transformed @@ -674,12 +676,17 @@ static bool foldReturnAndProcessPred(BasicBlock *BB, ReturnInst *Ret, bool &TailCallsAreMarkedTail, SmallVectorImpl &ArgumentPHIs, bool CannotTailCallElimCallsMarkedTail, - const TargetTransformInfo *TTI) { + const TargetTransformInfo *TTI, + AliasAnalysis *AA) { bool Change = false; + // Make sure this block is a trivial return block. + assert(BB->getFirstNonPHIOrDbg() == Ret && + "Trying to fold non-trivial return block"); + // If the return block contains nothing but the return and PHI's, // there might be an opportunity to duplicate the return in its - // predecessors and perform TRC there. Look for predecessors that end + // predecessors and perform TRE there. Look for predecessors that end // in unconditional branch and recursive call(s). SmallVector UncondBranchPreds; for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { @@ -706,7 +713,7 @@ static bool foldReturnAndProcessPred(BasicBlock *BB, ReturnInst *Ret, BB->eraseFromParent(); eliminateRecursiveTailCall(CI, RI, OldEntry, TailCallsAreMarkedTail, - ArgumentPHIs); + ArgumentPHIs, AA); ++NumRetDuped; Change = true; } @@ -719,16 +726,18 @@ static bool processReturningBlock(ReturnInst *Ret, BasicBlock *&OldEntry, bool &TailCallsAreMarkedTail, SmallVectorImpl &ArgumentPHIs, bool CannotTailCallElimCallsMarkedTail, - const TargetTransformInfo *TTI) { + const TargetTransformInfo *TTI, + AliasAnalysis *AA) { CallInst *CI = findTRECandidate(Ret, CannotTailCallElimCallsMarkedTail, TTI); if (!CI) return false; return eliminateRecursiveTailCall(CI, Ret, OldEntry, TailCallsAreMarkedTail, - ArgumentPHIs); + ArgumentPHIs, AA); } -static bool eliminateTailRecursion(Function &F, const TargetTransformInfo *TTI) { +static bool eliminateTailRecursion(Function &F, const TargetTransformInfo *TTI, + AliasAnalysis *AA) { if (F.getFnAttribute("disable-tail-calls").getValueAsString() == "true") return false; @@ -763,11 +772,11 @@ static bool eliminateTailRecursion(Function &F, const TargetTransformInfo *TTI) if (ReturnInst *Ret = dyn_cast(BB->getTerminator())) { bool Change = processReturningBlock(Ret, OldEntry, TailCallsAreMarkedTail, - ArgumentPHIs, !CanTRETailMarkedCall, TTI); + ArgumentPHIs, !CanTRETailMarkedCall, TTI, AA); if (!Change && BB->getFirstNonPHIOrDbg() == Ret) - Change = - foldReturnAndProcessPred(BB, Ret, OldEntry, TailCallsAreMarkedTail, - ArgumentPHIs, !CanTRETailMarkedCall, TTI); + Change = foldReturnAndProcessPred(BB, Ret, OldEntry, + TailCallsAreMarkedTail, ArgumentPHIs, + !CanTRETailMarkedCall, TTI, AA); MadeChange |= Change; } } @@ -797,6 +806,7 @@ struct TailCallElim : public FunctionPass { void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); + AU.addRequired(); AU.addPreserved(); } @@ -805,7 +815,8 @@ struct TailCallElim : public FunctionPass { return false; return eliminateTailRecursion( - F, &getAnalysis().getTTI(F)); + F, &getAnalysis().getTTI(F), + &getAnalysis().getAAResults()); } }; } @@ -826,8 +837,9 @@ PreservedAnalyses TailCallElimPass::run(Function &F, FunctionAnalysisManager &AM) { TargetTransformInfo &TTI = AM.getResult(F); + AliasAnalysis &AA = AM.getResult(F); - bool Changed = eliminateTailRecursion(F, &TTI); + bool Changed = eliminateTailRecursion(F, &TTI, &AA); if (!Changed) return PreservedAnalyses::all(); diff --git a/contrib/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/contrib/llvm/lib/Transforms/Utils/BuildLibCalls.cpp index ebde1f9a17dd..b60dfb4f3541 100644 --- a/contrib/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/contrib/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -116,6 +116,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_wcslen: Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_strchr: diff --git a/contrib/llvm/lib/Transforms/Utils/Local.cpp b/contrib/llvm/lib/Transforms/Utils/Local.cpp index 2af671636cbd..5127eba3f9ae 100644 --- a/contrib/llvm/lib/Transforms/Utils/Local.cpp +++ b/contrib/llvm/lib/Transforms/Utils/Local.cpp @@ -26,6 +26,7 @@ #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/DataLayout.h" @@ -1081,7 +1082,7 @@ static bool LdStHasDebugValue(DILocalVariable *DIVar, DIExpression *DIExpr, } /// See if there is a dbg.value intrinsic for DIVar for the PHI node. -static bool PhiHasDebugValue(DILocalVariable *DIVar, +static bool PhiHasDebugValue(DILocalVariable *DIVar, DIExpression *DIExpr, PHINode *APN) { // Since we can't guarantee that the original dbg.declare instrinsic @@ -1159,7 +1160,7 @@ void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI, DbgValue->insertAfter(LI); } -/// Inserts a llvm.dbg.value intrinsic after a phi +/// Inserts a llvm.dbg.value intrinsic after a phi /// that has an associated llvm.dbg.decl intrinsic. void llvm::ConvertDebugDeclareToDebugValue(DbgDeclareInst *DDI, PHINode *APN, DIBuilder &Builder) { @@ -1742,12 +1743,12 @@ void llvm::combineMetadata(Instruction *K, const Instruction *J, // Preserve !invariant.group in K. break; case LLVMContext::MD_align: - K->setMetadata(Kind, + K->setMetadata(Kind, MDNode::getMostGenericAlignmentOrDereferenceable(JMD, KMD)); break; case LLVMContext::MD_dereferenceable: case LLVMContext::MD_dereferenceable_or_null: - K->setMetadata(Kind, + K->setMetadata(Kind, MDNode::getMostGenericAlignmentOrDereferenceable(JMD, KMD)); break; } @@ -1847,6 +1848,49 @@ bool llvm::callsGCLeafFunction(ImmutableCallSite CS) { return false; } +void llvm::copyNonnullMetadata(const LoadInst &OldLI, MDNode *N, + LoadInst &NewLI) { + auto *NewTy = NewLI.getType(); + + // This only directly applies if the new type is also a pointer. + if (NewTy->isPointerTy()) { + NewLI.setMetadata(LLVMContext::MD_nonnull, N); + return; + } + + // The only other translation we can do is to integral loads with !range + // metadata. + if (!NewTy->isIntegerTy()) + return; + + MDBuilder MDB(NewLI.getContext()); + const Value *Ptr = OldLI.getPointerOperand(); + auto *ITy = cast(NewTy); + auto *NullInt = ConstantExpr::getPtrToInt( + ConstantPointerNull::get(cast(Ptr->getType())), ITy); + auto *NonNullInt = ConstantExpr::getAdd(NullInt, ConstantInt::get(ITy, 1)); + NewLI.setMetadata(LLVMContext::MD_range, + MDB.createRange(NonNullInt, NullInt)); +} + +void llvm::copyRangeMetadata(const DataLayout &DL, const LoadInst &OldLI, + MDNode *N, LoadInst &NewLI) { + auto *NewTy = NewLI.getType(); + + // Give up unless it is converted to a pointer where there is a single very + // valuable mapping we can do reliably. + // FIXME: It would be nice to propagate this in more ways, but the type + // conversions make it hard. + if (!NewTy->isPointerTy()) + return; + + unsigned BitWidth = DL.getTypeSizeInBits(NewTy); + if (!getConstantRangeFromMetadata(*N).contains(APInt(BitWidth, 0))) { + MDNode *NN = MDNode::get(OldLI.getContext(), None); + NewLI.setMetadata(LLVMContext::MD_nonnull, NN); + } +} + namespace { /// A potential constituent of a bitreverse or bswap expression. See /// collectBitParts for a fuller explanation. @@ -1968,7 +2012,7 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals, unsigned NumMaskedBits = AndMask.countPopulation(); if (!MatchBitReversals && NumMaskedBits % 8 != 0) return Result; - + auto &Res = collectBitParts(I->getOperand(0), MatchBSwaps, MatchBitReversals, BPS); if (!Res) diff --git a/contrib/llvm/lib/Transforms/Utils/LoopSimplify.cpp b/contrib/llvm/lib/Transforms/Utils/LoopSimplify.cpp index f3db278ef1e4..e21e34df8ded 100644 --- a/contrib/llvm/lib/Transforms/Utils/LoopSimplify.cpp +++ b/contrib/llvm/lib/Transforms/Utils/LoopSimplify.cpp @@ -72,7 +72,6 @@ using namespace llvm; #define DEBUG_TYPE "loop-simplify" -STATISTIC(NumInserted, "Number of pre-header or exit blocks inserted"); STATISTIC(NumNested , "Number of nested loops split out"); // If the block isn't already, move the new block to right after some 'outside @@ -152,37 +151,6 @@ BasicBlock *llvm::InsertPreheaderForLoop(Loop *L, DominatorTree *DT, return PreheaderBB; } -/// \brief Ensure that the loop preheader dominates all exit blocks. -/// -/// This method is used to split exit blocks that have predecessors outside of -/// the loop. -static BasicBlock *rewriteLoopExitBlock(Loop *L, BasicBlock *Exit, - DominatorTree *DT, LoopInfo *LI, - bool PreserveLCSSA) { - SmallVector LoopBlocks; - for (pred_iterator I = pred_begin(Exit), E = pred_end(Exit); I != E; ++I) { - BasicBlock *P = *I; - if (L->contains(P)) { - // Don't do this if the loop is exited via an indirect branch. - if (isa(P->getTerminator())) return nullptr; - - LoopBlocks.push_back(P); - } - } - - assert(!LoopBlocks.empty() && "No edges coming in from outside the loop?"); - BasicBlock *NewExitBB = nullptr; - - NewExitBB = SplitBlockPredecessors(Exit, LoopBlocks, ".loopexit", DT, LI, - PreserveLCSSA); - if (!NewExitBB) - return nullptr; - - DEBUG(dbgs() << "LoopSimplify: Creating dedicated exit block " - << NewExitBB->getName() << "\n"); - return NewExitBB; -} - /// Add the specified block, and all of its predecessors, to the specified set, /// if it's not already in there. Stop predecessor traversal when we reach /// StopBlock. @@ -346,16 +314,7 @@ static Loop *separateNestedLoop(Loop *L, BasicBlock *Preheader, // Split edges to exit blocks from the inner loop, if they emerged in the // process of separating the outer one. - SmallVector ExitBlocks; - L->getExitBlocks(ExitBlocks); - SmallSetVector ExitBlockSet(ExitBlocks.begin(), - ExitBlocks.end()); - for (BasicBlock *ExitBlock : ExitBlockSet) { - if (any_of(predecessors(ExitBlock), - [L](BasicBlock *BB) { return !L->contains(BB); })) { - rewriteLoopExitBlock(L, ExitBlock, DT, LI, PreserveLCSSA); - } - } + formDedicatedExitBlocks(L, DT, LI, PreserveLCSSA); if (PreserveLCSSA) { // Fix LCSSA form for L. Some values, which previously were only used inside @@ -563,29 +522,16 @@ static bool simplifyOneLoop(Loop *L, SmallVectorImpl &Worklist, BasicBlock *Preheader = L->getLoopPreheader(); if (!Preheader) { Preheader = InsertPreheaderForLoop(L, DT, LI, PreserveLCSSA); - if (Preheader) { - ++NumInserted; + if (Preheader) Changed = true; - } } // Next, check to make sure that all exit nodes of the loop only have // predecessors that are inside of the loop. This check guarantees that the // loop preheader/header will dominate the exit blocks. If the exit block has // predecessors from outside of the loop, split the edge now. - SmallVector ExitBlocks; - L->getExitBlocks(ExitBlocks); - - SmallSetVector ExitBlockSet(ExitBlocks.begin(), - ExitBlocks.end()); - for (BasicBlock *ExitBlock : ExitBlockSet) { - if (any_of(predecessors(ExitBlock), - [L](BasicBlock *BB) { return !L->contains(BB); })) { - rewriteLoopExitBlock(L, ExitBlock, DT, LI, PreserveLCSSA); - ++NumInserted; - Changed = true; - } - } + if (formDedicatedExitBlocks(L, DT, LI, PreserveLCSSA)) + Changed = true; // If the header has more than two predecessors at this point (from the // preheader and from multiple backedges), we must adjust the loop. @@ -614,10 +560,8 @@ static bool simplifyOneLoop(Loop *L, SmallVectorImpl &Worklist, // insert a new block that all backedges target, then make it jump to the // loop header. LoopLatch = insertUniqueBackedgeBlock(L, Preheader, DT, LI); - if (LoopLatch) { - ++NumInserted; + if (LoopLatch) Changed = true; - } } const DataLayout &DL = L->getHeader()->getModule()->getDataLayout(); @@ -645,7 +589,22 @@ static bool simplifyOneLoop(Loop *L, SmallVectorImpl &Worklist, // loop-invariant instructions out of the way to open up more // opportunities, and the disadvantage of having the responsibility // to preserve dominator information. - if (ExitBlockSet.size() == 1) { + auto HasUniqueExitBlock = [&]() { + BasicBlock *UniqueExit = nullptr; + for (auto *ExitingBB : ExitingBlocks) + for (auto *SuccBB : successors(ExitingBB)) { + if (L->contains(SuccBB)) + continue; + + if (!UniqueExit) + UniqueExit = SuccBB; + else if (UniqueExit != SuccBB) + return false; + } + + return true; + }; + if (HasUniqueExitBlock()) { for (unsigned i = 0, e = ExitingBlocks.size(); i != e; ++i) { BasicBlock *ExitingBlock = ExitingBlocks[i]; if (!ExitingBlock->getSinglePredecessor()) continue; diff --git a/contrib/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp b/contrib/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp index a920cd86a26a..5f85e17927fa 100644 --- a/contrib/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp +++ b/contrib/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp @@ -472,10 +472,22 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, // exit block only. if (!L->isLoopSimplifyForm()) return false; - BasicBlock *Exit = L->getUniqueExitBlock(); // successor out of loop - if (!Exit) - return false; + // Guaranteed by LoopSimplifyForm. + BasicBlock *Latch = L->getLoopLatch(); + + BasicBlock *LatchExit = L->getUniqueExitBlock(); // successor out of loop + if (!LatchExit) + return false; + // Cloning the loop basic blocks (`CloneLoopBlocks`) requires that one of the + // targets of the Latch be the single exit block out of the loop. This needs + // to be guaranteed by the callers of UnrollRuntimeLoopRemainder. + BranchInst *LatchBR = cast(Latch->getTerminator()); + assert((LatchBR->getSuccessor(0) == LatchExit || + LatchBR->getSuccessor(1) == LatchExit) && + "one of the loop latch successors should be " + "the exit block!"); + (void)LatchBR; // Use Scalar Evolution to compute the trip count. This allows more loops to // be unrolled than relying on induction var simplification. if (!SE) @@ -510,25 +522,13 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, if (Log2_32(Count) > BEWidth) return false; - BasicBlock *Latch = L->getLoopLatch(); - - // Cloning the loop basic blocks (`CloneLoopBlocks`) requires that one of the - // targets of the Latch be the single exit block out of the loop. This needs - // to be guaranteed by the callers of UnrollRuntimeLoopRemainder. - BranchInst *LatchBR = cast(Latch->getTerminator()); - assert( - (LatchBR->getSuccessor(0) == Exit || LatchBR->getSuccessor(1) == Exit) && - "one of the loop latch successors should be " - "the exit block!"); - // Avoid warning of unused `LatchBR` variable in release builds. - (void)LatchBR; // Loop structure is the following: // // PreHeader // Header // ... // Latch - // Exit + // LatchExit BasicBlock *NewPreHeader; BasicBlock *NewExit = nullptr; @@ -541,9 +541,9 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, // Split PreHeader to insert a branch around loop for unrolling. NewPreHeader = SplitBlock(PreHeader, PreHeader->getTerminator(), DT, LI); NewPreHeader->setName(PreHeader->getName() + ".new"); - // Split Exit to create phi nodes from branch above. - SmallVector Preds(predecessors(Exit)); - NewExit = SplitBlockPredecessors(Exit, Preds, ".unr-lcssa", + // Split LatchExit to create phi nodes from branch above. + SmallVector Preds(predecessors(LatchExit)); + NewExit = SplitBlockPredecessors(LatchExit, Preds, ".unr-lcssa", DT, LI, PreserveLCSSA); // Split NewExit to insert epilog remainder loop. EpilogPreHeader = SplitBlock(NewExit, NewExit->getTerminator(), DT, LI); @@ -570,7 +570,7 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, // Latch Header // *NewExit ... // *EpilogPreHeader Latch - // Exit Exit + // LatchExit LatchExit // Calculate conditions for branch around loop for unrolling // in epilog case and around prolog remainder loop in prolog case. @@ -648,7 +648,7 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, // Clone all the basic blocks in the loop. If Count is 2, we don't clone // the loop, otherwise we create a cloned loop to execute the extra // iterations. This function adds the appropriate CFG connections. - BasicBlock *InsertBot = UseEpilogRemainder ? Exit : PrologExit; + BasicBlock *InsertBot = UseEpilogRemainder ? LatchExit : PrologExit; BasicBlock *InsertTop = UseEpilogRemainder ? EpilogPreHeader : PrologPreHeader; CloneLoopBlocks(L, ModVal, CreateRemainderLoop, UseEpilogRemainder, InsertTop, InsertBot, NewPreHeader, NewBlocks, LoopBlocks, VMap, DT, LI); @@ -672,7 +672,7 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, // EpilogHeader Header // ... ... // EpilogLatch Latch - // Exit Exit + // LatchExit LatchExit // Rewrite the cloned instruction operands to use the values created when the // clone is created. @@ -686,7 +686,7 @@ bool llvm::UnrollRuntimeLoopRemainder(Loop *L, unsigned Count, if (UseEpilogRemainder) { // Connect the epilog code to the original loop and update the // PHI functions. - ConnectEpilog(L, ModVal, NewExit, Exit, PreHeader, + ConnectEpilog(L, ModVal, NewExit, LatchExit, PreHeader, EpilogPreHeader, NewPreHeader, VMap, DT, LI, PreserveLCSSA); diff --git a/contrib/llvm/lib/Transforms/Utils/LoopUtils.cpp b/contrib/llvm/lib/Transforms/Utils/LoopUtils.cpp index 412f6129407e..0ed33945ef40 100644 --- a/contrib/llvm/lib/Transforms/Utils/LoopUtils.cpp +++ b/contrib/llvm/lib/Transforms/Utils/LoopUtils.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/LoopUtils.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" @@ -29,6 +30,7 @@ #include "llvm/IR/ValueHandle.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" using namespace llvm; using namespace llvm::PatternMatch; @@ -87,8 +89,7 @@ RecurrenceDescriptor::lookThroughAnd(PHINode *Phi, Type *&RT, // Matches either I & 2^x-1 or 2^x-1 & I. If we find a match, we update RT // with a new integer type of the corresponding bit width. - if (match(J, m_CombineOr(m_And(m_Instruction(I), m_APInt(M)), - m_And(m_APInt(M), m_Instruction(I))))) { + if (match(J, m_c_And(m_Instruction(I), m_APInt(M)))) { int32_t Bits = (*M + 1).exactLogBase2(); if (Bits > 0) { RT = IntegerType::get(Phi->getContext(), Bits); @@ -923,6 +924,69 @@ bool InductionDescriptor::isInductionPHI(PHINode *Phi, const Loop *TheLoop, return true; } +bool llvm::formDedicatedExitBlocks(Loop *L, DominatorTree *DT, LoopInfo *LI, + bool PreserveLCSSA) { + bool Changed = false; + + // We re-use a vector for the in-loop predecesosrs. + SmallVector InLoopPredecessors; + + auto RewriteExit = [&](BasicBlock *BB) { + assert(InLoopPredecessors.empty() && + "Must start with an empty predecessors list!"); + auto Cleanup = make_scope_exit([&] { InLoopPredecessors.clear(); }); + + // See if there are any non-loop predecessors of this exit block and + // keep track of the in-loop predecessors. + bool IsDedicatedExit = true; + for (auto *PredBB : predecessors(BB)) + if (L->contains(PredBB)) { + if (isa(PredBB->getTerminator())) + // We cannot rewrite exiting edges from an indirectbr. + return false; + + InLoopPredecessors.push_back(PredBB); + } else { + IsDedicatedExit = false; + } + + assert(!InLoopPredecessors.empty() && "Must have *some* loop predecessor!"); + + // Nothing to do if this is already a dedicated exit. + if (IsDedicatedExit) + return false; + + auto *NewExitBB = SplitBlockPredecessors( + BB, InLoopPredecessors, ".loopexit", DT, LI, PreserveLCSSA); + + if (!NewExitBB) + DEBUG(dbgs() << "WARNING: Can't create a dedicated exit block for loop: " + << *L << "\n"); + else + DEBUG(dbgs() << "LoopSimplify: Creating dedicated exit block " + << NewExitBB->getName() << "\n"); + return true; + }; + + // Walk the exit blocks directly rather than building up a data structure for + // them, but only visit each one once. + SmallPtrSet Visited; + for (auto *BB : L->blocks()) + for (auto *SuccBB : successors(BB)) { + // We're looking for exit blocks so skip in-loop successors. + if (L->contains(SuccBB)) + continue; + + // Visit each exit block exactly once. + if (!Visited.insert(SuccBB).second) + continue; + + Changed |= RewriteExit(SuccBB); + } + + return Changed; +} + /// \brief Returns the instructions that use values defined in the loop. SmallVector llvm::findDefsUsedOutsideOfLoop(Loop *L) { SmallVector UsedOutside; diff --git a/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 1abdb2484850..eac2867233bc 100644 --- a/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/contrib/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -5702,14 +5702,14 @@ bool LoopVectorizationLegality::memoryInstructionCanBeWidened(Instruction *I, void LoopVectorizationCostModel::collectLoopUniforms(unsigned VF) { // We should not collect Uniforms more than once per VF. Right now, - // this function is called from collectUniformsAndScalars(), which + // this function is called from collectUniformsAndScalars(), which // already does this check. Collecting Uniforms for VF=1 does not make any // sense. assert(VF >= 2 && !Uniforms.count(VF) && "This function should not be visited twice for the same VF"); - // Visit the list of Uniforms. If we'll not find any uniform value, we'll + // Visit the list of Uniforms. If we'll not find any uniform value, we'll // not analyze again. Uniforms.count(VF) will return 1. Uniforms[VF].clear(); @@ -5988,10 +5988,10 @@ void InterleavedAccessInfo::collectConstStrideAccesses( continue; Value *Ptr = getPointerOperand(&I); - // We don't check wrapping here because we don't know yet if Ptr will be - // part of a full group or a group with gaps. Checking wrapping for all + // We don't check wrapping here because we don't know yet if Ptr will be + // part of a full group or a group with gaps. Checking wrapping for all // pointers (even those that end up in groups with no gaps) will be overly - // conservative. For full groups, wrapping should be ok since if we would + // conservative. For full groups, wrapping should be ok since if we would // wrap around the address space we would do a memory access at nullptr // even without the transformation. The wrapping checks are therefore // deferred until after we've formed the interleaved groups. @@ -6244,7 +6244,7 @@ void InterleavedAccessInfo::analyzeInterleaving( Instruction *LastMember = Group->getMember(Group->getFactor() - 1); if (LastMember) { Value *LastMemberPtr = getPointerOperand(LastMember); - if (!getPtrStride(PSE, LastMemberPtr, TheLoop, Strides, /*Assume=*/false, + if (!getPtrStride(PSE, LastMemberPtr, TheLoop, Strides, /*Assume=*/false, /*ShouldCheckWrap=*/true)) { DEBUG(dbgs() << "LV: Invalidate candidate interleaved group due to " "last group member potentially pointer-wrapping.\n"); @@ -6252,9 +6252,9 @@ void InterleavedAccessInfo::analyzeInterleaving( } } else { // Case 3: A non-reversed interleaved load group with gaps: We need - // to execute at least one scalar epilogue iteration. This will ensure + // to execute at least one scalar epilogue iteration. This will ensure // we don't speculatively access memory out-of-bounds. We only need - // to look for a member at index factor - 1, since every group must have + // to look for a member at index factor - 1, since every group must have // a member at index zero. if (Group->isReverse()) { releaseGroup(Group); @@ -7789,8 +7789,18 @@ bool LoopVectorizePass::processLoop(Loop *L) { // Check the loop for a trip count threshold: // do not vectorize loops with a tiny trip count. - const unsigned MaxTC = SE->getSmallConstantMaxTripCount(L); - if (MaxTC > 0u && MaxTC < TinyTripCountVectorThreshold) { + unsigned ExpectedTC = SE->getSmallConstantMaxTripCount(L); + bool HasExpectedTC = (ExpectedTC > 0); + + if (!HasExpectedTC && LoopVectorizeWithBlockFrequency) { + auto EstimatedTC = getLoopEstimatedTripCount(L); + if (EstimatedTC) { + ExpectedTC = *EstimatedTC; + HasExpectedTC = true; + } + } + + if (HasExpectedTC && ExpectedTC < TinyTripCountVectorThreshold) { DEBUG(dbgs() << "LV: Found a loop with a very small trip count. " << "This loop is not worth vectorizing."); if (Hints.getForce() == LoopVectorizeHints::FK_Enabled) @@ -7822,18 +7832,6 @@ bool LoopVectorizePass::processLoop(Loop *L) { bool OptForSize = Hints.getForce() != LoopVectorizeHints::FK_Enabled && F->optForSize(); - // Compute the weighted frequency of this loop being executed and see if it - // is less than 20% of the function entry baseline frequency. Note that we - // always have a canonical loop here because we think we *can* vectorize. - // FIXME: This is hidden behind a flag due to pervasive problems with - // exactly what block frequency models. - if (LoopVectorizeWithBlockFrequency) { - BlockFrequency LoopEntryFreq = BFI->getBlockFreq(L->getLoopPreheader()); - if (Hints.getForce() != LoopVectorizeHints::FK_Enabled && - LoopEntryFreq < ColdEntryFreq) - OptForSize = true; - } - // Check the function attributes to see if implicit floats are allowed. // FIXME: This check doesn't seem possibly correct -- what if the loop is // an integer loop and the vector instructions selected are purely integer @@ -8015,11 +8013,6 @@ bool LoopVectorizePass::runImpl( DB = &DB_; ORE = &ORE_; - // Compute some weights outside of the loop over the loops. Compute this - // using a BranchProbability to re-use its scaling math. - const BranchProbability ColdProb(1, 5); // 20% - ColdEntryFreq = BlockFrequency(BFI->getEntryFreq()) * ColdProb; - // Don't attempt if // 1. the target claims to have no vector registers, and // 2. interleaving won't help ILP. diff --git a/contrib/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/contrib/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index d1349535f298..b267230d3185 100644 --- a/contrib/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/contrib/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -3327,12 +3327,10 @@ void BoUpSLP::BlockScheduling::calculateDependencies(ScheduleData *SD, if (UseSD && isInSchedulingRegion(UseSD->FirstInBundle)) { BundleMember->Dependencies++; ScheduleData *DestBundle = UseSD->FirstInBundle; - if (!DestBundle->IsScheduled) { + if (!DestBundle->IsScheduled) BundleMember->incrementUnscheduledDeps(1); - } - if (!DestBundle->hasValidDependencies()) { + if (!DestBundle->hasValidDependencies()) WorkList.push_back(DestBundle); - } } } else { // I'm not sure if this can ever happen. But we need to be safe. diff --git a/contrib/llvm/tools/bugpoint/bugpoint.cpp b/contrib/llvm/tools/bugpoint/bugpoint.cpp index 85c1ddd8277d..4ddea8dbec19 100644 --- a/contrib/llvm/tools/bugpoint/bugpoint.cpp +++ b/contrib/llvm/tools/bugpoint/bugpoint.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/Valgrind.h" #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" @@ -138,6 +139,13 @@ int main(int argc, char **argv) { polly::initializePollyPasses(Registry); #endif + if (std::getenv("bar") == (char*) -1) { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + } + cl::ParseCommandLineOptions(argc, argv, "LLVM automatic testcase reducer. See\nhttp://" "llvm.org/cmds/bugpoint.html" diff --git a/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h b/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h index 9359abfebfe0..29f89e52a6e3 100644 --- a/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h +++ b/contrib/llvm/tools/clang/include/clang-c/CXCompilationDatabase.h @@ -7,7 +7,7 @@ |* *| |*===----------------------------------------------------------------------===*| |* *| -|* This header provides a public inferface to use CompilationDatabase without *| +|* This header provides a public interface to use CompilationDatabase without *| |* the full Clang C++ API. *| |* *| \*===----------------------------------------------------------------------===*/ diff --git a/contrib/llvm/tools/clang/include/clang-c/Index.h b/contrib/llvm/tools/clang/include/clang-c/Index.h index 417ac9fd369a..4241e43a9697 100644 --- a/contrib/llvm/tools/clang/include/clang-c/Index.h +++ b/contrib/llvm/tools/clang/include/clang-c/Index.h @@ -7,7 +7,7 @@ |* *| |*===----------------------------------------------------------------------===*| |* *| -|* This header provides a public inferface to a Clang library for extracting *| +|* This header provides a public interface to a Clang library for extracting *| |* high-level symbol information from source files without exposing the full *| |* Clang C++ API. *| |* *| diff --git a/contrib/llvm/tools/clang/include/clang/AST/Decl.h b/contrib/llvm/tools/clang/include/clang/AST/Decl.h index 9d49bac26a86..30552be9b381 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/Decl.h +++ b/contrib/llvm/tools/clang/include/clang/AST/Decl.h @@ -1656,6 +1656,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext, unsigned HasImplicitReturnZero : 1; unsigned IsLateTemplateParsed : 1; unsigned IsConstexpr : 1; + unsigned InstantiationIsPending:1; /// \brief Indicates if the function uses __try. unsigned UsesSEHTry : 1; @@ -1751,6 +1752,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext, IsDeleted(false), IsTrivial(false), IsDefaulted(false), IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), + InstantiationIsPending(false), UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false), EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), DNLoc(NameInfo.getInfo()) {} @@ -1872,7 +1874,7 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext, /// bool isThisDeclarationADefinition() const { return IsDeleted || IsDefaulted || Body || IsLateTemplateParsed || - hasDefiningAttr(); + WillHaveBody || hasDefiningAttr(); } /// doesThisDeclarationHaveABody - Returns whether this specific @@ -1943,6 +1945,15 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext, bool isConstexpr() const { return IsConstexpr; } void setConstexpr(bool IC) { IsConstexpr = IC; } + /// \brief Whether the instantiation of this function is pending. + /// This bit is set when the decision to instantiate this function is made + /// and unset if and when the function body is created. That leaves out + /// cases where instantiation did not happen because the template definition + /// was not seen in this TU. This bit remains set in those cases, under the + /// assumption that the instantiation will happen in some other TU. + bool instantiationIsPending() const { return InstantiationIsPending; } + void setInstantiationIsPending(bool IC) { InstantiationIsPending = IC; } + /// \brief Indicates the function uses __try. bool usesSEHTry() const { return UsesSEHTry; } void setUsesSEHTry(bool UST) { UsesSEHTry = UST; } diff --git a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h index c26e2d7bde95..0f1f481ae49b 100644 --- a/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h +++ b/contrib/llvm/tools/clang/include/clang/AST/DeclBase.h @@ -202,26 +202,33 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { OBJC_TQ_CSNullability = 0x40 }; -protected: - // Enumeration values used in the bits stored in NextInContextAndBits. - enum { - /// \brief Whether this declaration is a top-level declaration (function, - /// global variable, etc.) that is lexically inside an objc container - /// definition. - TopLevelDeclInObjCContainerFlag = 0x01, - - /// \brief Whether this declaration is private to the module in which it was - /// defined. - ModulePrivateFlag = 0x02 + /// The kind of ownership a declaration has, for visibility purposes. + /// This enumeration is designed such that higher values represent higher + /// levels of name hiding. + enum class ModuleOwnershipKind : unsigned { + /// This declaration is not owned by a module. + Unowned, + /// This declaration has an owning module, but is globally visible + /// (typically because its owning module is visible and we know that + /// modules cannot later become hidden in this compilation). + /// After serialization and deserialization, this will be converted + /// to VisibleWhenImported. + Visible, + /// This declaration has an owning module, and is visible when that + /// module is imported. + VisibleWhenImported, + /// This declaration has an owning module, but is only visible to + /// lookups that occur within that module. + ModulePrivate }; - + +protected: /// \brief The next declaration within the same lexical /// DeclContext. These pointers form the linked list that is /// traversed via DeclContext's decls_begin()/decls_end(). /// - /// The extra two bits are used for the TopLevelDeclInObjCContainer and - /// ModulePrivate bits. - llvm::PointerIntPair NextInContextAndBits; + /// The extra two bits are used for the ModuleOwnershipKind. + llvm::PointerIntPair NextInContextAndBits; private: friend class DeclContext; @@ -282,6 +289,11 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { /// are regarded as "referenced" but not "used". unsigned Referenced : 1; + /// \brief Whether this declaration is a top-level declaration (function, + /// global variable, etc.) that is lexically inside an objc container + /// definition. + unsigned TopLevelDeclInObjCContainer : 1; + /// \brief Whether statistic collection is enabled. static bool StatisticsEnabled; @@ -294,11 +306,6 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { /// \brief Whether this declaration was loaded from an AST file. unsigned FromASTFile : 1; - /// \brief Whether this declaration is hidden from normal name lookup, e.g., - /// because it is was loaded from an AST file is either module-private or - /// because its submodule has not been made visible. - unsigned Hidden : 1; - /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. unsigned IdentifierNamespace : 13; @@ -332,26 +339,38 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { private: bool AccessDeclContextSanity() const; + /// Get the module ownership kind to use for a local lexical child of \p DC, + /// which may be either a local or (rarely) an imported declaration. + static ModuleOwnershipKind getModuleOwnershipKindForChildOf(DeclContext *DC) { + if (DC) { + auto *D = cast(DC); + auto MOK = D->getModuleOwnershipKind(); + if (MOK != ModuleOwnershipKind::Unowned && + (!D->isFromASTFile() || D->hasLocalOwningModuleStorage())) + return MOK; + // If D is not local and we have no local module storage, then we don't + // need to track module ownership at all. + } + return ModuleOwnershipKind::Unowned; + } + protected: Decl(Kind DK, DeclContext *DC, SourceLocation L) - : NextInContextAndBits(), DeclCtx(DC), Loc(L), DeclKind(DK), - InvalidDecl(0), HasAttrs(false), Implicit(false), Used(false), - Referenced(false), Access(AS_none), FromASTFile(0), - Hidden(DC && cast(DC)->Hidden && - (!cast(DC)->isFromASTFile() || - hasLocalOwningModuleStorage())), + : NextInContextAndBits(nullptr, getModuleOwnershipKindForChildOf(DC)), + DeclCtx(DC), Loc(L), DeclKind(DK), InvalidDecl(0), HasAttrs(false), + Implicit(false), Used(false), Referenced(false), + TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), IdentifierNamespace(getIdentifierNamespaceForKind(DK)), CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } Decl(Kind DK, EmptyShell Empty) - : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), - HasAttrs(false), Implicit(false), Used(false), Referenced(false), - Access(AS_none), FromASTFile(0), Hidden(0), - IdentifierNamespace(getIdentifierNamespaceForKind(DK)), - CacheValidAndLinkage(0) - { + : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), HasAttrs(false), + Implicit(false), Used(false), Referenced(false), + TopLevelDeclInObjCContainer(false), Access(AS_none), FromASTFile(0), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + CacheValidAndLinkage(0) { if (StatisticsEnabled) add(DK); } @@ -551,16 +570,11 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { /// global variable, etc.) that is lexically inside an objc container /// definition. bool isTopLevelDeclInObjCContainer() const { - return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag; + return TopLevelDeclInObjCContainer; } void setTopLevelDeclInObjCContainer(bool V = true) { - unsigned Bits = NextInContextAndBits.getInt(); - if (V) - Bits |= TopLevelDeclInObjCContainerFlag; - else - Bits &= ~TopLevelDeclInObjCContainerFlag; - NextInContextAndBits.setInt(Bits); + TopLevelDeclInObjCContainer = V; } /// \brief Looks on this and related declarations for an applicable @@ -570,7 +584,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { /// \brief Whether this declaration was marked as being private to the /// module in which it was defined. bool isModulePrivate() const { - return NextInContextAndBits.getInt() & ModulePrivateFlag; + return getModuleOwnershipKind() == ModuleOwnershipKind::ModulePrivate; } /// \brief Whether this declaration is exported (by virtue of being lexically @@ -585,15 +599,14 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { const Attr *getDefiningAttr() const; protected: - /// \brief Specify whether this declaration was marked as being private + /// \brief Specify that this declaration was marked as being private /// to the module in which it was defined. - void setModulePrivate(bool MP = true) { - unsigned Bits = NextInContextAndBits.getInt(); - if (MP) - Bits |= ModulePrivateFlag; - else - Bits &= ~ModulePrivateFlag; - NextInContextAndBits.setInt(Bits); + void setModulePrivate() { + // The module-private specifier has no effect on unowned declarations. + // FIXME: We should track this in some way for source fidelity. + if (getModuleOwnershipKind() == ModuleOwnershipKind::Unowned) + return; + setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate); } /// \brief Set the owning module ID. @@ -692,7 +705,7 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { /// \brief Get the imported owning module, if this decl is from an imported /// (non-local) module. Module *getImportedOwningModule() const { - if (!isFromASTFile()) + if (!isFromASTFile() || !hasOwningModule()) return nullptr; return getOwningModuleSlow(); @@ -701,31 +714,57 @@ class LLVM_ALIGNAS(/*alignof(uint64_t)*/ 8) Decl { /// \brief Get the local owning module, if known. Returns nullptr if owner is /// not yet known or declaration is not from a module. Module *getLocalOwningModule() const { - if (isFromASTFile() || !Hidden) + if (isFromASTFile() || !hasOwningModule()) return nullptr; assert(hasLocalOwningModuleStorage() && - "hidden local decl but no local module storage"); + "owned local decl but no local module storage"); return reinterpret_cast(this)[-1]; } void setLocalOwningModule(Module *M) { - assert(!isFromASTFile() && Hidden && hasLocalOwningModuleStorage() && + assert(!isFromASTFile() && hasOwningModule() && + hasLocalOwningModuleStorage() && "should not have a cached owning module"); reinterpret_cast(this)[-1] = M; } + /// Is this declaration owned by some module? + bool hasOwningModule() const { + return getModuleOwnershipKind() != ModuleOwnershipKind::Unowned; + } + + /// Get the module that owns this declaration. Module *getOwningModule() const { return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule(); } - /// \brief Determine whether this declaration is hidden from name lookup. - bool isHidden() const { return Hidden; } + /// \brief Determine whether this declaration might be hidden from name + /// lookup. Note that the declaration might be visible even if this returns + /// \c false, if the owning module is visible within the query context. + // FIXME: Rename this to make it clearer what it does. + bool isHidden() const { + return (int)getModuleOwnershipKind() > (int)ModuleOwnershipKind::Visible; + } + + /// Set that this declaration is globally visible, even if it came from a + /// module that is not visible. + void setVisibleDespiteOwningModule() { + if (hasOwningModule()) + setModuleOwnershipKind(ModuleOwnershipKind::Visible); + } + + /// \brief Get the kind of module ownership for this declaration. + ModuleOwnershipKind getModuleOwnershipKind() const { + return NextInContextAndBits.getInt(); + } /// \brief Set whether this declaration is hidden from name lookup. - void setHidden(bool Hide) { - assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) && - "declaration with no owning module can't be hidden"); - Hidden = Hide; + void setModuleOwnershipKind(ModuleOwnershipKind MOK) { + assert(!(getModuleOwnershipKind() == ModuleOwnershipKind::Unowned && + MOK != ModuleOwnershipKind::Unowned && !isFromASTFile() && + !hasLocalOwningModuleStorage()) && + "no storage available for owning module for this declaration"); + NextInContextAndBits.setInt(MOK); } unsigned getIdentifierNamespace() const { diff --git a/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h b/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h index 3b8173558408..1ca3514e69b0 100644 --- a/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h +++ b/contrib/llvm/tools/clang/include/clang/Analysis/CloneDetection.h @@ -17,6 +17,8 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Regex.h" #include namespace clang { @@ -319,6 +321,26 @@ struct OnlyLargestCloneConstraint { void constrain(std::vector &Result); }; +struct FilenamePatternConstraint { + StringRef IgnoredFilesPattern; + std::shared_ptr IgnoredFilesRegex; + + FilenamePatternConstraint(StringRef IgnoredFilesPattern) + : IgnoredFilesPattern(IgnoredFilesPattern) { + IgnoredFilesRegex = std::make_shared("^(" + + IgnoredFilesPattern.str() + "$)"); + } + + bool isAutoGenerated(const CloneDetector::CloneGroup &Group); + + void constrain(std::vector &CloneGroups) { + CloneConstraint::filterGroups( + CloneGroups, [this](const CloneDetector::CloneGroup &Group) { + return isAutoGenerated(Group); + }); + } +}; + /// Analyzes the pattern of the referenced variables in a statement. class VariablePattern { diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def index a9ec172422ab..75781dc7491d 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/Builtins.def @@ -52,6 +52,7 @@ // LL -> long long // LLL -> __int128_t (e.g. LLLi) // W -> int64_t +// N -> 'int' size if target is LP64, 'L' otherwise. // S -> signed // U -> unsigned // I -> Required to constant fold to an integer constant expression. @@ -718,11 +719,11 @@ BUILTIN(__builtin_rindex, "c*cC*i", "Fn") LANGBUILTIN(_alloca, "v*z", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__assume, "vb", "n", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_ushort, "UsUs", "fnc", "stdlib.h", ALL_MS_LANGUAGES) -LIBBUILTIN(_byteswap_ulong, "ULiULi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) +LIBBUILTIN(_byteswap_ulong, "UNiUNi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) LIBBUILTIN(_byteswap_uint64, "ULLiULLi", "fnc", "stdlib.h", ALL_MS_LANGUAGES) LANGBUILTIN(__debugbreak, "v", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(__exception_code, "ULi", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_exception_code, "ULi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(__exception_code, "UNi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_exception_code, "UNi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__exception_info, "v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_exception_info, "v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__abnormal_termination, "i", "n", ALL_MS_LANGUAGES) @@ -730,33 +731,33 @@ LANGBUILTIN(_abnormal_termination, "i", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__GetExceptionInfo, "v*.", "ntu", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedAnd8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedAnd16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedAnd, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedAnd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange8, "ccD*cc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange16, "ssD*ss", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedCompareExchange, "LiLiD*LiLi", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedCompareExchange, "NiNiD*NiNi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchange64, "LLiLLiD*LLiLLi", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedCompareExchangePointer, "v*v*D*v*v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedDecrement16, "ssD*", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedDecrement, "LiLiD*", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedExchange, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedDecrement, "NiNiD*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchange, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchange8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchange16, "ssD*s", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeAdd8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeAdd16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedExchangeAdd, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchangeAdd, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangePointer, "v*v*D*v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeSub8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedExchangeSub16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedExchangeSub, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedExchangeSub, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedIncrement16, "ssD*", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedIncrement, "LiLiD*", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedIncrement, "NiNiD*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedOr8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedOr16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedOr, "LiLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedOr, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedXor8, "ccD*c", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_InterlockedXor16, "ssD*s", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_InterlockedXor, "LiLiD*Li", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_interlockedbittestandset, "UcLiD*Li", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_InterlockedXor, "NiNiD*Ni", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_interlockedbittestandset, "UcNiD*Ni", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__noop, "i.", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__popcnt16, "UsUs", "nc", ALL_MS_LANGUAGES) LANGBUILTIN(__popcnt, "UiUi", "nc", ALL_MS_LANGUAGES) @@ -765,12 +766,12 @@ LANGBUILTIN(_ReturnAddress, "v*", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl8, "UcUcUc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl16, "UsUsUc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl, "UiUii", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_lrotl, "ULiULii", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_lrotl, "UNiUNii", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotl64, "ULLiULLii", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotr8, "UcUcUc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotr16, "UsUsUc", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotr, "UiUii", "n", ALL_MS_LANGUAGES) -LANGBUILTIN(_lrotr, "ULiULii", "n", ALL_MS_LANGUAGES) +LANGBUILTIN(_lrotr, "UNiUNii", "n", ALL_MS_LANGUAGES) LANGBUILTIN(_rotr64, "ULLiULLii", "n", ALL_MS_LANGUAGES) LANGBUILTIN(__va_start, "vc**.", "nt", ALL_MS_LANGUAGES) LANGBUILTIN(__fastfail, "vUi", "nr", ALL_MS_LANGUAGES) diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def index e8db347d4be5..4e277f8a5a6b 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsARM.def @@ -215,10 +215,10 @@ LANGBUILTIN(_MoveFromCoprocessor2, "UiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) LANGBUILTIN(_MoveToCoprocessor, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) LANGBUILTIN(_MoveToCoprocessor2, "vUiIUiIUiIUiIUiIUi", "", ALL_MS_LANGUAGES) -TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", "intrin.h", ALL_MS_LANGUAGES, "") diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def index a98c8f0a53db..4cd3f1d46473 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86.def @@ -1822,8 +1822,8 @@ TARGET_BUILTIN(__builtin_ia32_mwaitx, "vUiUiUi", "", "mwaitx") TARGET_BUILTIN(__builtin_ia32_clzero, "vv*", "", "clzero") // MSVC -TARGET_HEADER_BUILTIN(_BitScanForward, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanReverse, "UcULi*ULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_ReadWriteBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_ReadBarrier, "v", "nh", "intrin.h", ALL_MS_LANGUAGES, "") @@ -1838,15 +1838,15 @@ TARGET_HEADER_BUILTIN(__stosb, "vUc*Ucz", "nh", "intrin.h", ALL_MS_LANGUAGES, "" TARGET_HEADER_BUILTIN(__int2c, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__ud2, "v", "nr", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__readfsbyte, "UcULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__readfsword, "UsULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__readfsdword, "ULiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__readfsqword, "ULLiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readfsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readfsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readfsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readfsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__readgsbyte, "UcULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__readgsword, "UsULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__readgsdword, "ULiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(__readgsqword, "ULLiULi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readgsbyte, "UcUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readgsword, "UsUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readgsdword, "UNiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__readgsqword, "ULLiUNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") #undef BUILTIN #undef TARGET_BUILTIN diff --git a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def index 2851184c2c84..4cde153d8372 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def +++ b/contrib/llvm/tools/clang/include/clang/Basic/BuiltinsX86_64.def @@ -22,8 +22,8 @@ # define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS) #endif -TARGET_HEADER_BUILTIN(_BitScanForward64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") -TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcULi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__mulh, "LLiLLiLLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nch", "intrin.h", ALL_MS_LANGUAGES, "") diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td index 3833f0f28f05..eb6dd37c148d 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -226,6 +226,9 @@ def warn_drv_enabling_rtti_with_exceptions : Warning< def warn_drv_disabling_vptr_no_rtti_default : Warning< "implicitly disabling vptr sanitizer because rtti wasn't enabled">, InGroup>; +def warn_drv_object_size_disabled_O0 : Warning< + "the object size sanitizer has no effect at -O0, but is explicitly enabled: %0">, + InGroup; def note_drv_command_failed_diag_msg : Note< "diagnostic msg: %0">; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td index cf404768472f..464c2425a1f1 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticGroups.td @@ -98,7 +98,9 @@ def CXX11CompatDeprecatedWritableStr : def DeprecatedAttributes : DiagGroup<"deprecated-attributes">; def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; def UnavailableDeclarations : DiagGroup<"unavailable-declarations">; -def UnguardedAvailability : DiagGroup<"unguarded-availability">; +def UnguardedAvailabilityNew : DiagGroup<"unguarded-availability-new">; +def UnguardedAvailability : DiagGroup<"unguarded-availability", + [UnguardedAvailabilityNew]>; // partial-availability is an alias of unguarded-availability. def : DiagGroup<"partial-availability", [UnguardedAvailability]>; def DeprecatedDynamicExceptionSpec @@ -149,6 +151,7 @@ def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">; def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">; def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; +def CXX1zCompatMangling : DiagGroup<"c++1z-compat-mangling">; // Warnings for C++1y code which is not compatible with prior C++ standards. def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">; @@ -211,7 +214,8 @@ def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", [CXXPre1zCompatPedantic]>; def CXX1zCompat : DiagGroup<"c++1z-compat", [DeprecatedRegister, - DeprecatedIncrementBool]>; + DeprecatedIncrementBool, + CXX1zCompatMangling]>; def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index aa73a6934518..cba9b251215a 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -507,7 +507,7 @@ def warn_deprecated_copy_operation : Warning< InGroup, DefaultIgnore; def warn_cxx1z_compat_exception_spec_in_signature : Warning< "mangled name of %0 will change in C++17 due to non-throwing exception " - "specification in function signature">, InGroup; + "specification in function signature">, InGroup; def warn_global_constructor : Warning< "declaration requires a global constructor">, @@ -2870,8 +2870,13 @@ def note_protocol_method : Note< def warn_unguarded_availability : Warning<"%0 is only available on %1 %2 or newer">, InGroup, DefaultIgnore; +def warn_unguarded_availability_new : + Warning, + InGroup; def warn_partial_availability : Warning<"%0 is only available conditionally">, InGroup, DefaultIgnore; +def warn_partial_availability_new : Warning, + InGroup; def note_partial_availability_silence : Note< "explicitly redeclare %0 to silence this warning">; def note_unguarded_available_silence : Note< @@ -2879,9 +2884,14 @@ def note_unguarded_available_silence : Note< " this warning">; def warn_partial_message : Warning<"%0 is partial: %1">, InGroup, DefaultIgnore; +def warn_partial_message_new : Warning, + InGroup; def warn_partial_fwdclass_message : Warning< "%0 may be partial because the receiver type is unknown">, InGroup, DefaultIgnore; +def warn_partial_fwdclass_message_new : + Warning, + InGroup; def warn_at_available_unchecked_use : Warning< "%select{@available|__builtin_available}0 does not guard availability here; " "use if (%select{@available|__builtin_available}0) instead">, @@ -6341,6 +6351,15 @@ def err_exceptions_disabled : Error< "cannot use '%0' with exceptions disabled">; def err_objc_exceptions_disabled : Error< "cannot use '%0' with Objective-C exceptions disabled">; +def warn_throw_in_noexcept_func + : Warning<"%0 has a non-throwing exception specification but can still " + "throw, resulting in unexpected program termination">, + InGroup; +def note_throw_in_dtor + : Note<"destructor or deallocator has a (possibly implicit) non-throwing " + "excepton specification">; +def note_throw_in_function + : Note<"non-throwing function declare here">; def err_seh_try_outside_functions : Error< "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; def err_mixing_cxx_try_seh_try : Error< @@ -8311,6 +8330,9 @@ def err_opencl_ext_vector_component_invalid_length : Error< "vector component access has invalid length %0. Supported: 1,2,3,4,8,16.">; def err_opencl_function_variable : Error< "%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">; +def err_opencl_addrspace_scope : Error< + "variables in the %0 address space can only be declared in the outermost " + "scope of a kernel function">; def err_static_function_scope : Error< "variables in function scope cannot be declared static">; def err_opencl_bitfields : Error< diff --git a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 0a59a633232c..3c64ebb9c7f4 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -112,8 +112,13 @@ def note_module_odr_violation_possible_decl : Note< def err_module_odr_violation_different_definitions : Error< "%q0 has different definitions in different modules; " "%select{definition in module '%2' is here|defined here}1">; +def note_first_module_difference : Note< + "in first definition, possible difference is here">; def note_module_odr_violation_different_definitions : Note< "definition in module '%0' is here">; +def note_second_module_difference : Note< + "in second definition, possible difference is here">; + def err_module_odr_violation_different_instantiations : Error< "instantiation of %q0 is different in different modules">; diff --git a/contrib/llvm/tools/clang/include/clang/Basic/Module.h b/contrib/llvm/tools/clang/include/clang/Basic/Module.h index 1e52b29367b2..177175eae965 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/Module.h +++ b/contrib/llvm/tools/clang/include/clang/Basic/Module.h @@ -393,7 +393,9 @@ class Module { /// \brief Retrieve the full name of this module, including the path from /// its top-level module. - std::string getFullModuleName() const; + /// \param AllowStringLiterals If \c true, components that might not be + /// lexically valid as identifiers will be emitted as string literals. + std::string getFullModuleName(bool AllowStringLiterals = false) const; /// \brief Whether the full name of this module is equal to joining /// \p nameParts with "."s. diff --git a/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td b/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td index ad8d679a1664..d5c16a91a34f 100644 --- a/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td +++ b/contrib/llvm/tools/clang/include/clang/Basic/arm_neon.td @@ -227,6 +227,7 @@ def OP_UNAVAILABLE : Operation { // u: unsigned integer (int/float args) // f: float (int args) // F: double (int args) +// H: half (int args) // d: default // g: default, ignore 'Q' size modifier. // j: default, force 'Q' size modifier. @@ -345,6 +346,7 @@ def OP_MLSLHi : Op<(call "vmlsl", $p0, (call "vget_high", $p1), (call "vget_high", $p2))>; def OP_MLSLHi_N : Op<(call "vmlsl_n", $p0, (call "vget_high", $p1), $p2)>; def OP_MUL_N : Op<(op "*", $p0, (dup $p1))>; +def OP_MULX_N : Op<(call "vmulx", $p0, (dup $p1))>; def OP_MLA_N : Op<(op "+", $p0, (op "*", $p1, (dup $p2)))>; def OP_MLS_N : Op<(op "-", $p0, (op "*", $p1, (dup $p2)))>; def OP_FMLA_N : Op<(call "vfma", $p0, $p1, (dup $p2))>; @@ -1661,3 +1663,186 @@ def SCALAR_SQRDMLSH_LANEQ : SOpInst<"vqrdmlsh_laneq", "sssji", "SsSi", OP_SCALAR def SCALAR_VDUP_LANE : IInst<"vdup_lane", "sdi", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">; def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "sji", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">; } + +// ARMv8.2-A FP16 intrinsics. +let ArchGuard = "defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(__aarch64__)" in { + + // ARMv8.2-A FP16 one-operand vector intrinsics. + + // Comparison + def CMEQH : SInst<"vceqz", "ud", "hQh">; + def CMGEH : SInst<"vcgez", "ud", "hQh">; + def CMGTH : SInst<"vcgtz", "ud", "hQh">; + def CMLEH : SInst<"vclez", "ud", "hQh">; + def CMLTH : SInst<"vcltz", "ud", "hQh">; + + // Vector conversion + def VCVT_F16 : SInst<"vcvt_f16", "Hd", "sUsQsQUs">; + def VCVT_S16 : SInst<"vcvt_s16", "xd", "hQh">; + def VCVT_U16 : SInst<"vcvt_u16", "ud", "hQh">; + def VCVTA_S16 : SInst<"vcvta_s16", "xd", "hQh">; + def VCVTA_U16 : SInst<"vcvta_u16", "ud", "hQh">; + def VCVTM_S16 : SInst<"vcvtm_s16", "xd", "hQh">; + def VCVTM_U16 : SInst<"vcvtm_u16", "ud", "hQh">; + def VCVTN_S16 : SInst<"vcvtn_s16", "xd", "hQh">; + def VCVTN_U16 : SInst<"vcvtn_u16", "ud", "hQh">; + def VCVTP_S16 : SInst<"vcvtp_s16", "xd", "hQh">; + def VCVTP_U16 : SInst<"vcvtp_u16", "ud", "hQh">; + + // Vector rounding + def FRINTZH : SInst<"vrnd", "dd", "hQh">; + def FRINTNH : SInst<"vrndn", "dd", "hQh">; + def FRINTAH : SInst<"vrnda", "dd", "hQh">; + def FRINTPH : SInst<"vrndp", "dd", "hQh">; + def FRINTMH : SInst<"vrndm", "dd", "hQh">; + def FRINTXH : SInst<"vrndx", "dd", "hQh">; + def FRINTIH : SInst<"vrndi", "dd", "hQh">; + + // Misc. + def VABSH : SInst<"vabs", "dd", "hQh">; + def VNEGH : SOpInst<"vneg", "dd", "hQh", OP_NEG>; + def VRECPEH : SInst<"vrecpe", "dd", "hQh">; + def FRSQRTEH : SInst<"vrsqrte", "dd", "hQh">; + def FSQRTH : SInst<"vsqrt", "dd", "hQh">; + + // ARMv8.2-A FP16 two-operands vector intrinsics. + + // Misc. + def VADDH : SOpInst<"vadd", "ddd", "hQh", OP_ADD>; + def VABDH : SInst<"vabd", "ddd", "hQh">; + def VSUBH : SOpInst<"vsub", "ddd", "hQh", OP_SUB>; + + // Comparison + let InstName = "vacge" in { + def VCAGEH : SInst<"vcage", "udd", "hQh">; + def VCALEH : SInst<"vcale", "udd", "hQh">; + } + let InstName = "vacgt" in { + def VCAGTH : SInst<"vcagt", "udd", "hQh">; + def VCALTH : SInst<"vcalt", "udd", "hQh">; + } + def VCEQH : SOpInst<"vceq", "udd", "hQh", OP_EQ>; + def VCGEH : SOpInst<"vcge", "udd", "hQh", OP_GE>; + def VCGTH : SOpInst<"vcgt", "udd", "hQh", OP_GT>; + let InstName = "vcge" in + def VCLEH : SOpInst<"vcle", "udd", "hQh", OP_LE>; + let InstName = "vcgt" in + def VCLTH : SOpInst<"vclt", "udd", "hQh", OP_LT>; + + // Vector conversion + let isVCVT_N = 1 in { + def VCVT_N_F16 : SInst<"vcvt_n_f16", "Hdi", "sUsQsQUs">; + def VCVT_N_S16 : SInst<"vcvt_n_s16", "xdi", "hQh">; + def VCVT_N_U16 : SInst<"vcvt_n_u16", "udi", "hQh">; + } + + // Max/Min + def VMAXH : SInst<"vmax", "ddd", "hQh">; + def VMINH : SInst<"vmin", "ddd", "hQh">; + def FMAXNMH : SInst<"vmaxnm", "ddd", "hQh">; + def FMINNMH : SInst<"vminnm", "ddd", "hQh">; + + // Multiplication/Division + def VMULH : SOpInst<"vmul", "ddd", "hQh", OP_MUL>; + def MULXH : SInst<"vmulx", "ddd", "hQh">; + def FDIVH : IOpInst<"vdiv", "ddd", "hQh", OP_DIV>; + + // Pairwise addition + def VPADDH : SInst<"vpadd", "ddd", "hQh">; + + // Pairwise Max/Min + def VPMAXH : SInst<"vpmax", "ddd", "hQh">; + def VPMINH : SInst<"vpmin", "ddd", "hQh">; + // Pairwise MaxNum/MinNum + def FMAXNMPH : SInst<"vpmaxnm", "ddd", "hQh">; + def FMINNMPH : SInst<"vpminnm", "ddd", "hQh">; + + // Reciprocal/Sqrt + def VRECPSH : SInst<"vrecps", "ddd", "hQh">; + def VRSQRTSH : SInst<"vrsqrts", "ddd", "hQh">; + + // ARMv8.2-A FP16 three-operands vector intrinsics. + + // Vector fused multiply-add operations + def VFMAH : SInst<"vfma", "dddd", "hQh">; + def VFMSH : SOpInst<"vfms", "dddd", "hQh", OP_FMLS>; + + // ARMv8.2-A FP16 lane vector intrinsics. + + // FMA lane + def VFMA_LANEH : IInst<"vfma_lane", "dddgi", "hQh">; + def VFMA_LANEQH : IInst<"vfma_laneq", "dddji", "hQh">; + + // FMA lane with scalar argument + def FMLA_NH : SOpInst<"vfma_n", "ddds", "hQh", OP_FMLA_N>; + // Scalar floating point fused multiply-add (scalar, by element) + def SCALAR_FMLA_LANEH : IInst<"vfma_lane", "sssdi", "Sh">; + def SCALAR_FMLA_LANEQH : IInst<"vfma_laneq", "sssji", "Sh">; + + // FMS lane + def VFMS_LANEH : IOpInst<"vfms_lane", "dddgi", "hQh", OP_FMS_LN>; + def VFMS_LANEQH : IOpInst<"vfms_laneq", "dddji", "hQh", OP_FMS_LNQ>; + // FMS lane with scalar argument + def FMLS_NH : SOpInst<"vfms_n", "ddds", "hQh", OP_FMLS_N>; + // Scalar floating foint fused multiply-subtract (scalar, by element) + def SCALAR_FMLS_LANEH : IOpInst<"vfms_lane", "sssdi", "Sh", OP_FMS_LN>; + def SCALAR_FMLS_LANEQH : IOpInst<"vfms_laneq", "sssji", "Sh", OP_FMS_LNQ>; + + // Mul lane + def VMUL_LANEH : IOpInst<"vmul_lane", "ddgi", "hQh", OP_MUL_LN>; + def VMUL_LANEQH : IOpInst<"vmul_laneq", "ddji", "hQh", OP_MUL_LN>; + def VMUL_NH : IOpInst<"vmul_n", "dds", "hQh", OP_MUL_N>; + // Scalar floating point multiply (scalar, by element) + def SCALAR_FMUL_LANEH : IOpInst<"vmul_lane", "ssdi", "Sh", OP_SCALAR_MUL_LN>; + def SCALAR_FMUL_LANEQH : IOpInst<"vmul_laneq", "ssji", "Sh", OP_SCALAR_MUL_LN>; + + // Mulx lane + def VMULX_LANEH : IOpInst<"vmulx_lane", "ddgi", "hQh", OP_MULX_LN>; + def VMULX_LANEQH : IOpInst<"vmulx_laneq", "ddji", "hQh", OP_MULX_LN>; + def VMULX_NH : IOpInst<"vmulx_n", "dds", "hQh", OP_MULX_N>; + // TODO: Scalar floating point multiply extended (scalar, by element) + // Below ones are commented out because they need vmulx_f16(float16_t, float16_t) + // which will be implemented later with fp16 scalar intrinsic (arm_fp16.h) + //def SCALAR_FMULX_LANEH : IOpInst<"vmulx_lane", "ssdi", "Sh", OP_SCALAR_MUL_LN>; + //def SCALAR_FMULX_LANEQH : IOpInst<"vmulx_laneq", "ssji", "Sh", OP_SCALAR_MUL_LN>; + + // ARMv8.2-A FP16 reduction vector intrinsics. + def VMAXVH : SInst<"vmaxv", "sd", "hQh">; + def VMINVH : SInst<"vminv", "sd", "hQh">; + def FMAXNMVH : SInst<"vmaxnmv", "sd", "hQh">; + def FMINNMVH : SInst<"vminnmv", "sd", "hQh">; + + // Data processing intrinsics - section 5 + + // Logical operations + let isHiddenLInst = 1 in + def VBSLH : SInst<"vbsl", "dudd", "hQh">; + + // Transposition operations + def VZIPH : WInst<"vzip", "2dd", "hQh">; + def VUZPH : WInst<"vuzp", "2dd", "hQh">; + def VTRNH : WInst<"vtrn", "2dd", "hQh">; + + // Set all lanes to same value. + /* Already implemented prior to ARMv8.2-A. + def VMOV_NH : WOpInst<"vmov_n", "ds", "hQh", OP_DUP>; + def VDUP_NH : WOpInst<"vdup_n", "ds", "hQh", OP_DUP>; + def VDUP_LANE1H : WOpInst<"vdup_lane", "dgi", "hQh", OP_DUP_LN>;*/ + + // Vector Extract + def VEXTH : WInst<"vext", "dddi", "hQh">; + + // Reverse vector elements + def VREV64H : WOpInst<"vrev64", "dd", "hQh", OP_REV64>; + + // Permutation + def VTRN1H : SOpInst<"vtrn1", "ddd", "hQh", OP_TRN1>; + def VZIP1H : SOpInst<"vzip1", "ddd", "hQh", OP_ZIP1>; + def VUZP1H : SOpInst<"vuzp1", "ddd", "hQh", OP_UZP1>; + def VTRN2H : SOpInst<"vtrn2", "ddd", "hQh", OP_TRN2>; + def VZIP2H : SOpInst<"vzip2", "ddd", "hQh", OP_ZIP2>; + def VUZP2H : SOpInst<"vuzp2", "ddd", "hQh", OP_UZP2>; + + def SCALAR_VDUP_LANEH : IInst<"vdup_lane", "sdi", "Sh">; + def SCALAR_VDUP_LANEQH : IInst<"vdup_laneq", "sji", "Sh">; +} diff --git a/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td index 1132d1345f60..c478cfc7833e 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td +++ b/contrib/llvm/tools/clang/include/clang/Driver/CC1Options.td @@ -134,7 +134,6 @@ def migrator_no_finalize_removal : Flag<["-"], "no-finalize-removal">, //===----------------------------------------------------------------------===// let Flags = [CC1Option, CC1AsOption, NoDriverOption] in { - def debug_info_kind_EQ : Joined<["-"], "debug-info-kind=">; def debug_info_macro : Flag<["-"], "debug-info-macro">, HelpText<"Emit macro debug information">; @@ -144,20 +143,22 @@ def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">, HelpText<"The compilation directory to embed in the debug info.">; def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">, HelpText<"The string to embed in the Dwarf debug flags record.">; +def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">, + HelpText<"DWARF debug sections compression">; +def compress_debug_sections_EQ : Flag<["-"], "compress-debug-sections=">, + HelpText<"DWARF debug sections compression type">; def mno_exec_stack : Flag<["-"], "mnoexecstack">, HelpText<"Mark the file as not needing an executable stack">; def massembler_fatal_warnings : Flag<["-"], "massembler-fatal-warnings">, HelpText<"Make assembler warnings fatal">; def mrelax_relocations : Flag<["--"], "mrelax-relocations">, HelpText<"Use relaxable elf relocations">; -def compress_debug_sections : Flag<["-"], "compress-debug-sections">, - HelpText<"Compress DWARF debug sections using zlib">; def msave_temp_labels : Flag<["-"], "msave-temp-labels">, HelpText<"Save temporary labels in the symbol table. " "Note this may change .s semantics and shouldn't generally be used " "on compiler-generated code.">; def mrelocation_model : Separate<["-"], "mrelocation-model">, - HelpText<"The relocation model to use">; + HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">; def fno_math_builtin : Flag<["-"], "fno-math-builtin">, HelpText<"Disable implicit builtin knowledge of math functions">; } @@ -228,7 +229,7 @@ def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">, def masm_verbose : Flag<["-"], "masm-verbose">, HelpText<"Generate verbose assembly output">; def mcode_model : Separate<["-"], "mcode-model">, - HelpText<"The code model to use">; + HelpText<"The code model to use">, Values<"small,kernel,medium,large">; def mdebug_pass : Separate<["-"], "mdebug-pass">, HelpText<"Enable additional debug output">; def mdisable_fp_elim : Flag<["-"], "mdisable-fp-elim">, @@ -307,7 +308,7 @@ def fsanitize_coverage_no_prune HelpText<"Disable coverage pruning (i.e. instrument all blocks/edges)">; def fprofile_instrument_EQ : Joined<["-"], "fprofile-instrument=">, HelpText<"Enable PGO instrumentation. The accepted value is clang, llvm, " - "or none">; + "or none">, Values<"none,clang,llvm">; def fprofile_instrument_path_EQ : Joined<["-"], "fprofile-instrument-path=">, HelpText<"Generate instrumented code to collect execution counts into " " (overridden by LLVM_PROFILE_FILE env var)">; @@ -347,9 +348,9 @@ def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">, HelpText<"File for serializing diagnostics in a binary format">; def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">, - HelpText<"Change diagnostic formatting to match IDE and command line tools">; + HelpText<"Change diagnostic formatting to match IDE and command line tools">, Values<"clang,msvc,msvc-fallback,vi">; def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">, - HelpText<"Print diagnostic category">; + HelpText<"Print diagnostic category">, Values<"none,id,name">; def fno_diagnostics_use_presumed_location : Flag<["-"], "fno-diagnostics-use-presumed-location">, HelpText<"Ignore #line directives when displaying diagnostic locations">; def ftabstop : Separate<["-"], "ftabstop">, MetaVarName<"">, @@ -594,11 +595,11 @@ def fconstant_string_class : Separate<["-"], "fconstant-string-class">, MetaVarName<"">, HelpText<"Specify the class to use for constant Objective-C string objects.">; def fobjc_arc_cxxlib_EQ : Joined<["-"], "fobjc-arc-cxxlib=">, - HelpText<"Objective-C++ Automatic Reference Counting standard library kind">; + HelpText<"Objective-C++ Automatic Reference Counting standard library kind">, Values<"libc++,libstdc++,none">; def fobjc_runtime_has_weak : Flag<["-"], "fobjc-runtime-has-weak">, HelpText<"The target Objective-C runtime supports ARC weak operations">; def fobjc_dispatch_method_EQ : Joined<["-"], "fobjc-dispatch-method=">, - HelpText<"Objective-C dispatch method to use">; + HelpText<"Objective-C dispatch method to use">, Values<"legacy,non-legacy,mixed">; def disable_objc_default_synthesize_properties : Flag<["-"], "disable-objc-default-synthesize-properties">, HelpText<"disable the default synthesis of Objective-C properties">; def fencode_extended_block_signature : Flag<["-"], "fencode-extended-block-signature">, @@ -672,7 +673,7 @@ def fnative_half_arguments_and_returns : Flag<["-"], "fnative-half-arguments-and def fallow_half_arguments_and_returns : Flag<["-"], "fallow-half-arguments-and-returns">, HelpText<"Allow function arguments and returns of type half">; def fdefault_calling_conv_EQ : Joined<["-"], "fdefault-calling-conv=">, - HelpText<"Set default MS calling convention">; + HelpText<"Set default MS calling convention">, Values<"cdecl,fastcall,stdcall,vectorcall">; def finclude_default_header : Flag<["-"], "finclude-default-header">, HelpText<"Include the default header file for OpenCL">; def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">, diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Options.h b/contrib/llvm/tools/clang/include/clang/Driver/Options.h index 57e4452f3e8c..2da3cb4828c8 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/Options.h +++ b/contrib/llvm/tools/clang/include/clang/Driver/Options.h @@ -39,8 +39,9 @@ enum ClangFlags { enum ID { OPT_INVALID = 0, // This is not an option ID. -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) OPT_##ID, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, #include "clang/Driver/Options.inc" LastOption #undef OPTION diff --git a/contrib/llvm/tools/clang/include/clang/Driver/Options.td b/contrib/llvm/tools/clang/include/clang/Driver/Options.td index 6c51976e98fe..68b331fed2bd 100644 --- a/contrib/llvm/tools/clang/include/clang/Driver/Options.td +++ b/contrib/llvm/tools/clang/include/clang/Driver/Options.td @@ -493,7 +493,7 @@ def cl_mad_enable : Flag<["-"], "cl-mad-enable">, Group, Flags<[CC def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group, Flags<[CC1Option]>, HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">; def cl_std_EQ : Joined<["-"], "cl-std=">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL language standard to compile for.">; + HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0">; def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group, Flags<[CC1Option]>, HelpText<"OpenCL only. Allow denormals to be flushed to zero.">; def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group, Flags<[CC1Option]>, @@ -804,7 +804,7 @@ def fno_sanitize_coverage : CommaJoined<["-"], "fno-sanitize-coverage=">, Group, Flags<[CoreOption, DriverOption]>, HelpText<"Disable specified features of coverage instrumentation for " - "Sanitizers">; + "Sanitizers">, Values<"func,bb,edge,indirect-calls,trace-bb,trace-cmp,trace-div,trace-gep,8bit-counters,trace-pc,trace-pc-guard,no-prune,inline-8bit-counters">; def fsanitize_memory_track_origins_EQ : Joined<["-"], "fsanitize-memory-track-origins=">, Group, HelpText<"Enable origins tracking in MemorySanitizer">; @@ -923,7 +923,7 @@ def ftrapping_math : Flag<["-"], "ftrapping-math">, Group, Flags<[CC1Op def fno_trapping_math : Flag<["-"], "fno-trapping-math">, Group, Flags<[CC1Option]>; def ffp_contract : Joined<["-"], "ffp-contract=">, Group, Flags<[CC1Option]>, HelpText<"Form fused FP ops (e.g. FMAs): fast (everywhere)" - " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">; + " | on (according to FP_CONTRACT pragma, default) | off (never fuse)">, Values<"fast,on,off">; def ffor_scope : Flag<["-"], "ffor-scope">, Group; def fno_for_scope : Flag<["-"], "fno-for-scope">, Group; @@ -1000,7 +1000,7 @@ def flat__namespace : Flag<["-"], "flat_namespace">; def flax_vector_conversions : Flag<["-"], "flax-vector-conversions">, Group; def flimited_precision_EQ : Joined<["-"], "flimited-precision=">, Group; def flto_EQ : Joined<["-"], "flto=">, Flags<[CoreOption, CC1Option]>, Group, - HelpText<"Set LTO mode to either 'full' or 'thin'">; + HelpText<"Set LTO mode to either 'full' or 'thin'">, Values<"thin,full">; def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group, HelpText<"Enable LTO in 'full' mode">; def fno_lto : Flag<["-"], "fno-lto">, Group, @@ -1158,7 +1158,7 @@ def fno_experimental_new_pass_manager : Flag<["-"], "fno-experimental-new-pass-m Group, Flags<[CC1Option]>, HelpText<"Disables an experimental new pass manager in LLVM.">; def fveclib : Joined<["-"], "fveclib=">, Group, Flags<[CC1Option]>, - HelpText<"Use the given vector functions library">; + HelpText<"Use the given vector functions library">, Values<"Accelerate,SVML,none">; def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group, HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">, Flags<[CC1Option]>; def fno_merge_all_constants : Flag<["-"], "fno-merge-all-constants">, Group, @@ -1342,7 +1342,7 @@ def fno_short_wchar : Flag<["-"], "fno-short-wchar">, Group, Flags<[CC1 HelpText<"Force wchar_t to be an unsigned int">; def fshow_overloads_EQ : Joined<["-"], "fshow-overloads=">, Group, Flags<[CC1Option]>, HelpText<"Which overload candidates to show when overload resolution fails: " - "best|all; defaults to all">; + "best|all; defaults to all">, Values<"best,all">; def fshow_column : Flag<["-"], "fshow-column">, Group, Flags<[CC1Option]>; def fshow_source_location : Flag<["-"], "fshow-source-location">, Group; def fspell_checking : Flag<["-"], "fspell-checking">, Group; @@ -1456,7 +1456,7 @@ def fuse_init_array : Flag<["-"], "fuse-init-array">, Group, Flags<[CC1 def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group; def fverbose_asm : Flag<["-"], "fverbose-asm">, Group; def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group, - HelpText<"Set the default symbol visibility for all global declarations">; + HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">; def fvisibility_inlines_hidden : Flag<["-"], "fvisibility-inlines-hidden">, Group, HelpText<"Give inline C++ member functions default visibility by default">, Flags<[CC1Option]>; @@ -1563,6 +1563,10 @@ def gdwarf_aranges : Flag<["-"], "gdwarf-aranges">, Group; def gmodules : Flag <["-"], "gmodules">, Group, HelpText<"Generate debug info with external references to clang modules" " or precompiled headers">; +def gz : Flag<["-"], "gz">, Group, + HelpText<"DWARF debug sections compression type">; +def gz_EQ : Joined<["-"], "gz=">, Group, + HelpText<"DWARF debug sections compression type">; def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">; def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption]>, HelpText<"Display available options">; @@ -1677,7 +1681,7 @@ def minline_all_stringops : Flag<["-"], "minline-all-stringops">, Group, Group; def malign_double : Flag<["-"], "malign-double">, Group, Flags<[CC1Option]>, HelpText<"Align doubles to two words in structs (x86 only)">; -def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group; +def mfloat_abi_EQ : Joined<["-"], "mfloat-abi=">, Group, Values<"soft,softfp,hard">; def mfpmath_EQ : Joined<["-"], "mfpmath=">, Group; def mfpu_EQ : Joined<["-"], "mfpu=">, Group; def mhwdiv_EQ : Joined<["-"], "mhwdiv=">, Group; @@ -1709,9 +1713,9 @@ def mstack_alignment : Joined<["-"], "mstack-alignment=">, Group, Flags def mstack_probe_size : Joined<["-"], "mstack-probe-size=">, Group, Flags<[CC1Option]>, HelpText<"Set the stack probe size">; def mthread_model : Separate<["-"], "mthread-model">, Group, Flags<[CC1Option]>, - HelpText<"The thread model to use, e.g. posix, single (posix by default)">; + HelpText<"The thread model to use, e.g. posix, single (posix by default)">, Values<"posix,single">; def meabi : Separate<["-"], "meabi">, Group, Flags<[CC1Option]>, - HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">; + HelpText<"Set EABI type, e.g. 4, 5 or gnu (default depends on triple)">, Values<"default,4,5,gnu">; def mmmx : Flag<["-"], "mmmx">, Group; def mno_3dnowa : Flag<["-"], "mno-3dnowa">, Group; @@ -2205,7 +2209,7 @@ def std_default_EQ : Joined<["-"], "std-default=">; def std_EQ : Joined<["-", "--"], "std=">, Flags<[CC1Option]>, Group, HelpText<"Language standard to compile for">; def stdlib_EQ : Joined<["-", "--"], "stdlib=">, Flags<[CC1Option]>, - HelpText<"C++ standard library to use">; + HelpText<"C++ standard library to use">, Values<"libc++,libstdc++,platform">; def sub__library : JoinedOrSeparate<["-"], "sub_library">; def sub__umbrella : JoinedOrSeparate<["-"], "sub_umbrella">; def system_header_prefix : Joined<["--"], "system-header-prefix=">, diff --git a/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h index 970791420734..d95a0c2be805 100644 --- a/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h +++ b/contrib/llvm/tools/clang/include/clang/Edit/EditedSource.h @@ -17,6 +17,7 @@ #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/Allocator.h" #include +#include namespace clang { class LangOptions; @@ -41,10 +42,20 @@ class EditedSource { typedef std::map FileEditsTy; FileEditsTy FileEdits; - // Location of argument use inside the macro body - typedef std::pair MacroArgUse; - llvm::DenseMap> - ExpansionToArgMap; + struct MacroArgUse { + IdentifierInfo *Identifier; + SourceLocation ImmediateExpansionLoc; + // Location of argument use inside the top-level macro + SourceLocation UseLoc; + + bool operator==(const MacroArgUse &Other) const { + return std::tie(Identifier, ImmediateExpansionLoc, UseLoc) == + std::tie(Other.Identifier, Other.ImmediateExpansionLoc, + Other.UseLoc); + } + }; + + llvm::DenseMap> ExpansionToArgMap; SmallVector, 2> CurrCommitMacroArgExps; diff --git a/contrib/llvm/tools/clang/include/clang/Format/Format.h b/contrib/llvm/tools/clang/include/clang/Format/Format.h index 1891c06eba51..c1b62477ed1c 100644 --- a/contrib/llvm/tools/clang/include/clang/Format/Format.h +++ b/contrib/llvm/tools/clang/include/clang/Format/Format.h @@ -184,9 +184,23 @@ struct FormatStyle { enum ShortFunctionStyle { /// \brief Never merge functions into a single line. SFS_None, + /// \brief Only merge functions defined inside a class. Same as "inline", + /// except it does not implies "empty": i.e. top level empty functions + /// are not merged either. + /// \code + /// class Foo { + /// void f() { foo(); } + /// }; + /// void f() { + /// foo(); + /// } + /// void f() { + /// } + /// \endcode + SFS_InlineOnly, /// \brief Only merge empty functions. /// \code - /// void f() { bar(); } + /// void f() {} /// void f2() { /// bar2(); /// } @@ -197,6 +211,10 @@ struct FormatStyle { /// class Foo { /// void f() { foo(); } /// }; + /// void f() { + /// foo(); + /// } + /// void f() {} /// \endcode SFS_Inline, /// \brief Merge all functions fitting on a single line. @@ -634,12 +652,12 @@ struct FormatStyle { /// struct foo /// { /// int x; - /// } + /// }; /// /// false: /// struct foo { /// int x; - /// } + /// }; /// \endcode bool AfterStruct; /// \brief Wrap union definitions. @@ -715,7 +733,7 @@ struct FormatStyle { /// ? firstValue /// : SecondValueVeryVeryVeryVeryLong; /// - /// true: + /// false: /// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongDescription ? /// firstValue : /// SecondValueVeryVeryVeryVeryLong; @@ -723,8 +741,7 @@ struct FormatStyle { bool BreakBeforeTernaryOperators; /// \brief Different ways to break initializers. - enum BreakConstructorInitializersStyle - { + enum BreakConstructorInitializersStyle { /// Break constructor initializers before the colon and after the commas. /// \code /// Constructor() @@ -749,7 +766,7 @@ struct FormatStyle { BCIS_AfterColon }; - /// \brief The constructor initializers style to use.. + /// \brief The constructor initializers style to use. BreakConstructorInitializersStyle BreakConstructorInitializers; /// \brief Break after each annotation on a field in Java files. @@ -1253,6 +1270,14 @@ struct FormatStyle { /// \endcode bool SortIncludes; + /// \brief If ``true``, clang-format will sort using declarations. + /// \code + /// false: true: + /// using std::cout; vs. using std::cin; + /// using std::cin; using std::cout; + /// \endcode + bool SortUsingDeclarations; + /// \brief If ``true``, a space is inserted after C style casts. /// \code /// true: false: @@ -1641,6 +1666,16 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, ArrayRef Ranges, StringRef FileName = ""); +/// \brief Sort consecutive using declarations in the given \p Ranges in +/// \p Code. +/// +/// Returns the ``Replacements`` that sort the using declarations in all +/// \p Ranges in \p Code. +tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, + StringRef Code, + ArrayRef Ranges, + StringRef FileName = ""); + /// \brief Returns the ``LangOpts`` that the formatter expects you to set. /// /// \param Style determines specific settings for lexing mode. diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h index ae54d4151415..2950c31c2d3d 100644 --- a/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h +++ b/contrib/llvm/tools/clang/include/clang/Frontend/ASTUnit.h @@ -25,6 +25,7 @@ #include "clang/Lex/PreprocessingRecord.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Serialization/ASTBitCodes.h" +#include "clang/Frontend/PrecompiledPreamble.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" @@ -199,103 +200,15 @@ class ASTUnit { /// of that loading. It must be cleared when preamble is recreated. llvm::StringMap PreambleSrcLocCache; -public: - class PreambleData { - const FileEntry *File; - std::vector Buffer; - mutable unsigned NumLines; - - public: - PreambleData() : File(nullptr), NumLines(0) { } - - void assign(const FileEntry *F, const char *begin, const char *end) { - File = F; - Buffer.assign(begin, end); - NumLines = 0; - } - - void clear() { Buffer.clear(); File = nullptr; NumLines = 0; } - - size_t size() const { return Buffer.size(); } - bool empty() const { return Buffer.empty(); } - - const char *getBufferStart() const { return &Buffer[0]; } - - unsigned getNumLines() const { - if (NumLines) - return NumLines; - countLines(); - return NumLines; - } - - SourceRange getSourceRange(const SourceManager &SM) const { - SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID()); - return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1)); - } - - private: - void countLines() const; - }; - - const PreambleData &getPreambleData() const { - return Preamble; - } - - /// Data used to determine if a file used in the preamble has been changed. - struct PreambleFileHash { - /// All files have size set. - off_t Size; - - /// Modification time is set for files that are on disk. For memory - /// buffers it is zero. - time_t ModTime; - - /// Memory buffers have MD5 instead of modification time. We don't - /// compute MD5 for on-disk files because we hope that modification time is - /// enough to tell if the file was changed. - llvm::MD5::MD5Result MD5; - - static PreambleFileHash createForFile(off_t Size, time_t ModTime); - static PreambleFileHash - createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); - - friend bool operator==(const PreambleFileHash &LHS, - const PreambleFileHash &RHS); - - friend bool operator!=(const PreambleFileHash &LHS, - const PreambleFileHash &RHS) { - return !(LHS == RHS); - } - }; - private: - /// \brief The contents of the preamble that has been precompiled to - /// \c PreambleFile. - PreambleData Preamble; - - /// \brief Whether the preamble ends at the start of a new line. - /// - /// Used to inform the lexer as to whether it's starting at the beginning of - /// a line after skipping the preamble. - bool PreambleEndsAtStartOfLine; - - /// \brief Keeps track of the files that were used when computing the - /// preamble, with both their buffer size and their modification time. - /// - /// If any of the files have changed from one compile to the next, - /// the preamble must be thrown away. - llvm::StringMap FilesInPreamble; + /// The contents of the preamble. + llvm::Optional Preamble; /// \brief When non-NULL, this is the buffer used to store the contents of /// the main file when it has been padded for use with the precompiled /// preamble. std::unique_ptr SavedMainFileBuffer; - /// \brief When non-NULL, this is the buffer used to store the - /// contents of the preamble when it has been padded to build the - /// precompiled preamble. - std::unique_ptr PreambleBuffer; - /// \brief The number of warnings that occurred while parsing the preamble. /// /// This value will be used to restore the state of the \c DiagnosticsEngine @@ -438,21 +351,6 @@ class ASTUnit { std::unique_ptr OverrideMainBuffer, IntrusiveRefCntPtr VFS); - struct ComputedPreamble { - llvm::MemoryBuffer *Buffer; - std::unique_ptr Owner; - unsigned Size; - bool PreambleEndsAtStartOfLine; - ComputedPreamble(llvm::MemoryBuffer *Buffer, - std::unique_ptr Owner, unsigned Size, - bool PreambleEndsAtStartOfLine) - : Buffer(Buffer), Owner(std::move(Owner)), Size(Size), - PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} - }; - ComputedPreamble ComputePreamble(CompilerInvocation &Invocation, - unsigned MaxLines, - IntrusiveRefCntPtr VFS); - std::unique_ptr getMainBufferWithPrecompiledPreamble( std::shared_ptr PCHContainerOps, const CompilerInvocation &PreambleInvocationIn, @@ -607,12 +505,6 @@ class ASTUnit { void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length, SmallVectorImpl &Decls); - /// \brief Add a new top-level declaration, identified by its ID in - /// the precompiled preamble. - void addTopLevelDeclFromPreamble(serialization::DeclID D) { - TopLevelDeclsInPreamble.push_back(D); - } - /// \brief Retrieve a reference to the current top-level name hash value. /// /// Note: This is used internally by the top-level tracking action diff --git a/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h b/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h new file mode 100644 index 000000000000..8307392e7feb --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/Frontend/PrecompiledPreamble.h @@ -0,0 +1,248 @@ +//===--- PrecompiledPreamble.h - Build precompiled preambles ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Helper class to build precompiled preamble. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H +#define LLVM_CLANG_FRONTEND_PRECOMPILED_PREAMBLE_H + +#include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/Support/MD5.h" +#include +#include +#include + +namespace llvm { +class MemoryBuffer; +} + +namespace clang { +namespace vfs { +class FileSystem; +} + +class CompilerInstance; +class CompilerInvocation; +class DeclGroupRef; +class PCHContainerOperations; + +/// A size of the preamble and a flag required by +/// PreprocessorOptions::PrecompiledPreambleBytes. +struct PreambleBounds { + PreambleBounds(unsigned Size, bool PreambleEndsAtStartOfLine) + : Size(Size), PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} + + /// \brief Size of the preamble in bytes. + unsigned Size; + /// \brief Whether the preamble ends at the start of a new line. + /// + /// Used to inform the lexer as to whether it's starting at the beginning of + /// a line after skipping the preamble. + bool PreambleEndsAtStartOfLine; +}; + +/// \brief Runs lexer to compute suggested preamble bounds. +PreambleBounds ComputePreambleBounds(const LangOptions &LangOpts, + llvm::MemoryBuffer *Buffer, + unsigned MaxLines); + +class PreambleCallbacks; + +/// A class holding a PCH and all information to check whether it is valid to +/// reuse the PCH for the subsequent runs. Use BuildPreamble to create PCH and +/// CanReusePreamble + AddImplicitPreamble to make use of it. +class PrecompiledPreamble { + class TempPCHFile; + struct PreambleFileHash; + +public: + /// \brief Try to build PrecompiledPreamble for \p Invocation. See + /// BuildPreambleError for possible error codes. + /// + /// \param Invocation Original CompilerInvocation with options to compile the + /// file. + /// + /// \param MainFileBuffer Buffer with the contents of the main file. + /// + /// \param Bounds Bounds of the preamble, result of calling + /// ComputePreambleBounds. + /// + /// \param Diagnostics Diagnostics engine to be used while building the + /// preamble. + /// + /// \param VFS An instance of vfs::FileSystem to be used for file + /// accesses. + /// + /// \param PCHContainerOps An instance of PCHContainerOperations. + /// + /// \param Callbacks A set of callbacks to be executed when building + /// the preamble. + static llvm::ErrorOr + Build(const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, + DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr VFS, + std::shared_ptr PCHContainerOps, + PreambleCallbacks &Callbacks); + + PrecompiledPreamble(PrecompiledPreamble &&) = default; + PrecompiledPreamble &operator=(PrecompiledPreamble &&) = default; + + /// PreambleBounds used to build the preamble + PreambleBounds getBounds() const; + + /// Check whether PrecompiledPreamble can be reused for the new contents(\p + /// MainFileBuffer) of the main file. + bool CanReuse(const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, + vfs::FileSystem *VFS) const; + + /// Changes options inside \p CI to use PCH from this preamble. Also remaps + /// main file to \p MainFileBuffer. + void AddImplicitPreamble(CompilerInvocation &CI, + llvm::MemoryBuffer *MainFileBuffer) const; + +private: + PrecompiledPreamble(TempPCHFile PCHFile, std::vector PreambleBytes, + bool PreambleEndsAtStartOfLine, + llvm::StringMap FilesInPreamble); + + /// A temp file that would be deleted on destructor call. If destructor is not + /// called for any reason, the file will be deleted at static objects' + /// destruction. + /// An assertion will fire if two TempPCHFiles are created with the same name, + /// so it's not intended to be used outside preamble-handling. + class TempPCHFile { + public: + // A main method used to construct TempPCHFile. + static llvm::ErrorOr CreateNewPreamblePCHFile(); + + /// Call llvm::sys::fs::createTemporaryFile to create a new temporary file. + static llvm::ErrorOr createInSystemTempDir(const Twine &Prefix, + StringRef Suffix); + /// Create a new instance of TemporaryFile for file at \p Path. Use with + /// extreme caution, there's an assertion checking that there's only a + /// single instance of TempPCHFile alive for each path. + static llvm::ErrorOr createFromCustomPath(const Twine &Path); + + private: + TempPCHFile(std::string FilePath); + + public: + TempPCHFile(TempPCHFile &&Other); + TempPCHFile &operator=(TempPCHFile &&Other); + + TempPCHFile(const TempPCHFile &) = delete; + ~TempPCHFile(); + + /// A path where temporary file is stored. + llvm::StringRef getFilePath() const; + + private: + void RemoveFileIfPresent(); + + private: + llvm::Optional FilePath; + }; + + /// Data used to determine if a file used in the preamble has been changed. + struct PreambleFileHash { + /// All files have size set. + off_t Size = 0; + + /// Modification time is set for files that are on disk. For memory + /// buffers it is zero. + time_t ModTime = 0; + + /// Memory buffers have MD5 instead of modification time. We don't + /// compute MD5 for on-disk files because we hope that modification time is + /// enough to tell if the file was changed. + llvm::MD5::MD5Result MD5 = {}; + + static PreambleFileHash createForFile(off_t Size, time_t ModTime); + static PreambleFileHash + createForMemoryBuffer(const llvm::MemoryBuffer *Buffer); + + friend bool operator==(const PreambleFileHash &LHS, + const PreambleFileHash &RHS) { + return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && + LHS.MD5 == RHS.MD5; + } + friend bool operator!=(const PreambleFileHash &LHS, + const PreambleFileHash &RHS) { + return !(LHS == RHS); + } + }; + + /// Manages the lifetime of temporary file that stores a PCH. + TempPCHFile PCHFile; + /// Keeps track of the files that were used when computing the + /// preamble, with both their buffer size and their modification time. + /// + /// If any of the files have changed from one compile to the next, + /// the preamble must be thrown away. + llvm::StringMap FilesInPreamble; + /// The contents of the file that was used to precompile the preamble. Only + /// contains first PreambleBounds::Size bytes. Used to compare if the relevant + /// part of the file has not changed, so that preamble can be reused. + std::vector PreambleBytes; + /// See PreambleBounds::PreambleEndsAtStartOfLine + bool PreambleEndsAtStartOfLine; +}; + +/// A set of callbacks to gather useful information while building a preamble. +class PreambleCallbacks { +public: + virtual ~PreambleCallbacks() = default; + + /// Called after FrontendAction::Execute(), but before + /// FrontendAction::EndSourceFile(). Can be used to transfer ownership of + /// various CompilerInstance fields before they are destroyed. + virtual void AfterExecute(CompilerInstance &CI); + /// Called after PCH has been emitted. \p Writer may be used to retrieve + /// information about AST, serialized in PCH. + virtual void AfterPCHEmitted(ASTWriter &Writer); + /// Called for each TopLevelDecl. + /// NOTE: To allow more flexibility a custom ASTConsumer could probably be + /// used instead, but having only this method allows a simpler API. + virtual void HandleTopLevelDecl(DeclGroupRef DG); + /// Called for each macro defined in the Preamble. + /// NOTE: To allow more flexibility a custom PPCallbacks could probably be + /// used instead, but having only this method allows a simpler API. + virtual void HandleMacroDefined(const Token &MacroNameTok, + const MacroDirective *MD); +}; + +enum class BuildPreambleError { + PreambleIsEmpty = 1, + CouldntCreateTempFile, + CouldntCreateTargetInfo, + CouldntCreateVFSOverlay, + BeginSourceFileFailed, + CouldntEmitPCH +}; + +class BuildPreambleErrorCategory final : public std::error_category { +public: + const char *name() const noexcept override; + std::string message(int condition) const override; +}; + +std::error_code make_error_code(BuildPreambleError Error); +} // namespace clang + +namespace std { +template <> +struct is_error_code_enum : std::true_type {}; +} // namespace std + +#endif diff --git a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h index 302d006ea16c..712e1ab9fbf5 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/Preprocessor.h @@ -1835,11 +1835,20 @@ class Preprocessor { /// \brief A fast PTH version of SkipExcludedConditionalBlock. void PTHSkipExcludedConditionalBlock(); + /// Information about the result for evaluating an expression for a + /// preprocessor directive. + struct DirectiveEvalResult { + /// Whether the expression was evaluated as true or not. + bool Conditional; + /// True if the expression contained identifiers that were undefined. + bool IncludedUndefinedIds; + }; + /// \brief Evaluate an integer constant expression that may occur after a - /// \#if or \#elif directive and return it as a bool. + /// \#if or \#elif directive and return a \p DirectiveEvalResult object. /// /// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro. - bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); + DirectiveEvalResult EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); /// \brief Install the standard preprocessor pragmas: /// \#pragma GCC poison/system_header/dependency and \#pragma once. diff --git a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h index f536be8d8e69..d91c665cf1dd 100644 --- a/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h +++ b/contrib/llvm/tools/clang/include/clang/Lex/PreprocessorOptions.h @@ -96,8 +96,15 @@ class PreprocessorOptions { std::string TokenCache; /// When enabled, preprocessor is in a mode for parsing a single file only. + /// + /// Disables #includes of other files and if there are unresolved identifiers + /// in preprocessor directive conditions it causes all blocks to be parsed so + /// that the client can get the maximum amount of information from the parser. bool SingleFileParseMode = false; + /// When enabled, the preprocessor will construct editor placeholder tokens. + bool LexEditorPlaceholders = true; + /// \brief True if the SourceManager should report the original file name for /// contents of files that were remapped to other files. Defaults to true. bool RemappedFilesKeepOriginalName; @@ -185,6 +192,7 @@ class PreprocessorOptions { ImplicitPTHInclude.clear(); TokenCache.clear(); SingleFileParseMode = false; + LexEditorPlaceholders = true; RetainRemappedFileBuffers = true; PrecompiledPreambleBytes.first = 0; PrecompiledPreambleBytes.second = 0; diff --git a/contrib/llvm/tools/clang/include/clang/Parse/Parser.h b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h index a51d3a51d435..21d699ec402e 100644 --- a/contrib/llvm/tools/clang/include/clang/Parse/Parser.h +++ b/contrib/llvm/tools/clang/include/clang/Parse/Parser.h @@ -604,7 +604,7 @@ class Parser : public CodeCompletionHandler { } /// getTypeAnnotation - Read a parsed type out of an annotation token. - static ParsedType getTypeAnnotation(Token &Tok) { + static ParsedType getTypeAnnotation(const Token &Tok) { return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue()); } @@ -615,7 +615,7 @@ class Parser : public CodeCompletionHandler { /// \brief Read an already-translated primary expression out of an annotation /// token. - static ExprResult getExprAnnotation(Token &Tok) { + static ExprResult getExprAnnotation(const Token &Tok) { return ExprResult::getFromOpaquePointer(Tok.getAnnotationValue()); } @@ -1852,6 +1852,7 @@ class Parser : public CodeCompletionHandler { DSC_trailing, // C++11 trailing-type-specifier in a trailing return type DSC_alias_declaration, // C++11 type-specifier-seq in an alias-declaration DSC_top_level, // top-level/namespace declaration context + DSC_template_param, // template parameter context DSC_template_type_arg, // template type argument context DSC_objc_method_result, // ObjC method result context, enables 'instancetype' DSC_condition // condition declaration context @@ -1862,6 +1863,7 @@ class Parser : public CodeCompletionHandler { static bool isTypeSpecifier(DeclSpecContext DSC) { switch (DSC) { case DSC_normal: + case DSC_template_param: case DSC_class: case DSC_top_level: case DSC_objc_method_result: @@ -1882,6 +1884,7 @@ class Parser : public CodeCompletionHandler { static bool isClassTemplateDeductionContext(DeclSpecContext DSC) { switch (DSC) { case DSC_normal: + case DSC_template_param: case DSC_class: case DSC_top_level: case DSC_condition: diff --git a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h index 1dedf4ba24ce..02c133d1c4fc 100644 --- a/contrib/llvm/tools/clang/include/clang/Sema/Sema.h +++ b/contrib/llvm/tools/clang/include/clang/Sema/Sema.h @@ -2153,7 +2153,8 @@ class Sema { bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, - bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr); + bool IsTypeSpecifier, bool IsTemplateParamOrArg, + SkipBodyInfo *SkipBody = nullptr); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index fb427f618575..b8ec2aa6ae8d 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -180,6 +180,11 @@ class BasicValueFactory { return getValue(X); } + inline const llvm::APSInt& getZeroWithTypeSize(QualType T) { + assert(T->isScalarType()); + return getValue(0, Ctx.getTypeSize(T), true); + } + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); } diff --git a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index 14aa3af37620..d58d0a690c88 100644 --- a/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -315,6 +315,13 @@ class SValBuilder { return nonloc::ConcreteInt(BasicVals.getTruthValue(b)); } + /// Create NULL pointer, with proper pointer bit-width for given address + /// space. + /// \param type pointer type. + Loc makeNullWithType(QualType type) { + return loc::ConcreteInt(BasicVals.getZeroWithTypeSize(type)); + } + Loc makeNull() { return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth()); } diff --git a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp index 2300801c1a9c..fabfdc9ef7e5 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp @@ -894,7 +894,7 @@ void ASTContext::mergeDefinitionIntoModule(NamedDecl *ND, Module *M, if (getLangOpts().ModulesLocalVisibility) MergedDefModules[ND].push_back(M); else - ND->setHidden(false); + ND->setVisibleDespiteOwningModule(); } void ASTContext::deduplicateMergedDefinitonsFor(NamedDecl *ND) { @@ -8513,7 +8513,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, RequiresICE = false; // Read the prefixed modifiers first. - bool Done = false; + bool Done = false, IsSpecialLong = false; while (!Done) { switch (*Str++) { default: Done = true; --Str; break; @@ -8531,12 +8531,24 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, Unsigned = true; break; case 'L': + assert(!IsSpecialLong && "Can't use 'L' with 'W' or 'N' modifiers"); assert(HowLong <= 2 && "Can't have LLLL modifier"); ++HowLong; break; + case 'N': { + // 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise. + assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); + assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!"); + IsSpecialLong = true; + if (Context.getTargetInfo().getLongWidth() == 32) + ++HowLong; + break; + } case 'W': // This modifier represents int64 type. + assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!"); + IsSpecialLong = true; switch (Context.getTargetInfo().getInt64Type()) { default: llvm_unreachable("Unexpected integer type"); diff --git a/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp index d89be0d9e6fa..4758109fbcf7 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTDumper.cpp @@ -1184,6 +1184,31 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { I != E; ++I) dumpCXXCtorInitializer(*I); + if (const CXXMethodDecl *MD = dyn_cast(D)) + if (MD->size_overridden_methods() != 0) { + auto dumpOverride = + [=](const CXXMethodDecl *D) { + SplitQualType T_split = D->getType().split(); + OS << D << " " << D->getParent()->getName() << "::"; + if (isa(D)) + OS << "~" << D->getParent()->getName(); + else + OS << D->getName(); + OS << " '" << QualType::getAsString(T_split) << "'"; + }; + + dumpChild([=] { + auto FirstOverrideItr = MD->begin_overridden_methods(); + OS << "Overrides: [ "; + dumpOverride(*FirstOverrideItr); + for (const auto *Override : + llvm::make_range(FirstOverrideItr + 1, + MD->end_overridden_methods())) + dumpOverride(Override); + OS << " ]"; + }); + } + if (D->doesThisDeclarationHaveABody()) dumpStmt(D->getBody()); } diff --git a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp index 493cb6df8b83..6e33b98d2f18 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp @@ -319,6 +319,9 @@ namespace clang { bool ImportArrayChecked(const InContainerTy &InContainer, OIter Obegin) { return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin); } + + // Importing overrides. + void ImportOverrides(CXXMethodDecl *ToMethod, CXXMethodDecl *FromMethod); }; } @@ -2025,6 +2028,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Add this function to the lexical context. LexicalDC->addDeclInternal(ToFunction); + if (auto *FromCXXMethod = dyn_cast(D)) + ImportOverrides(cast(ToFunction), FromCXXMethod); + return ToFunction; } @@ -5499,6 +5505,14 @@ Expr *ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr( Replacement); } +void ASTNodeImporter::ImportOverrides(CXXMethodDecl *ToMethod, + CXXMethodDecl *FromMethod) { + for (auto *FromOverriddenMethod : FromMethod->overridden_methods()) + ToMethod->addOverriddenMethod( + cast(Importer.Import(const_cast( + FromOverriddenMethod)))); +} + ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport) diff --git a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp index 032a20afa834..a0594a020362 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp +++ b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp @@ -278,12 +278,12 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { // FIXME: We shouldn't be changing the lexical context of declarations // imported from AST files. if (!isFromASTFile()) { - Hidden = cast(DC)->Hidden && hasLocalOwningModuleStorage(); - if (Hidden) + setModuleOwnershipKind(getModuleOwnershipKindForChildOf(DC)); + if (hasOwningModule()) setLocalOwningModule(cast(DC)->getOwningModule()); } - assert((!Hidden || getOwningModule()) && + assert((!hasOwningModule() || getOwningModule()) && "hidden declaration has no owning module"); } @@ -1352,7 +1352,7 @@ void DeclContext::removeDecl(Decl *D) { // Remove only decls that have a name if (!ND->getDeclName()) return; - auto *DC = this; + auto *DC = D->getDeclContext(); do { StoredDeclsMap *Map = DC->getPrimaryContext()->LookupPtr; if (Map) { diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp index 1dc472a5f753..b746edaf6439 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp +++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTMerger.cpp @@ -41,6 +41,7 @@ class LazyASTImporter : public ASTImporter { Decl *Imported(Decl *From, Decl *To) override { if (auto ToTag = dyn_cast(To)) { ToTag->setHasExternalLexicalStorage(); + ToTag->setMustBuildLookupTable(); } else if (auto ToNamespace = dyn_cast(To)) { ToNamespace->setHasExternalVisibleStorage(); } diff --git a/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp b/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp index 5bbcbe4e5722..ee848ac711d6 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/CloneDetection.cpp @@ -18,9 +18,9 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/Lexer.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Path.h" using namespace clang; @@ -366,6 +366,23 @@ void OnlyLargestCloneConstraint::constrain( } } +bool FilenamePatternConstraint::isAutoGenerated(const CloneDetector::CloneGroup &Group) { + std::string Error; + if (IgnoredFilesPattern.empty() || Group.empty() || + !IgnoredFilesRegex->isValid(Error)) + return false; + + for (const StmtSequence &S : Group) { + const SourceManager &SM = S.getASTContext().getSourceManager(); + StringRef Filename = llvm::sys::path::filename(SM.getFilename( + S.getContainingDecl()->getLocation())); + if (IgnoredFilesRegex->match(Filename)) + return true; + } + + return false; +} + static size_t createHash(llvm::MD5 &Hash) { size_t HashCode; @@ -618,8 +635,7 @@ void CloneConstraint::splitCloneGroups( if (Indexes[j]) continue; - // If a following StmtSequence belongs to our CloneGroup, we add it to - // it. + // If a following StmtSequence belongs to our CloneGroup, we add it. const StmtSequence &Candidate = HashGroup[j]; if (!Compare(Prototype, Candidate)) diff --git a/contrib/llvm/tools/clang/lib/Basic/Module.cpp b/contrib/llvm/tools/clang/lib/Basic/Module.cpp index 83c524877ab0..1d96afd476ef 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Module.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Module.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Module.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" @@ -125,7 +126,36 @@ const Module *Module::getTopLevelModule() const { return Result; } -std::string Module::getFullModuleName() const { +static StringRef getModuleNameFromComponent( + const std::pair &IdComponent) { + return IdComponent.first; +} +static StringRef getModuleNameFromComponent(StringRef R) { return R; } + +template +static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End, + bool AllowStringLiterals = true) { + for (InputIter It = Begin; It != End; ++It) { + if (It != Begin) + OS << "."; + + StringRef Name = getModuleNameFromComponent(*It); + if (!AllowStringLiterals || isValidIdentifier(Name)) + OS << Name; + else { + OS << '"'; + OS.write_escaped(Name); + OS << '"'; + } + } +} + +template +static void printModuleId(raw_ostream &OS, const Container &C) { + return printModuleId(OS, C.begin(), C.end()); +} + +std::string Module::getFullModuleName(bool AllowStringLiterals) const { SmallVector Names; // Build up the set of module names (from innermost to outermost). @@ -133,15 +163,11 @@ std::string Module::getFullModuleName() const { Names.push_back(M->Name); std::string Result; - for (SmallVectorImpl::reverse_iterator I = Names.rbegin(), - IEnd = Names.rend(); - I != IEnd; ++I) { - if (!Result.empty()) - Result += '.'; - - Result += *I; - } - + + llvm::raw_string_ostream Out(Result); + printModuleId(Out, Names.rbegin(), Names.rend(), AllowStringLiterals); + Out.flush(); + return Result; } @@ -240,14 +266,6 @@ Module *Module::findSubmodule(StringRef Name) const { return SubModules[Pos->getValue()]; } -static void printModuleId(raw_ostream &OS, const ModuleId &Id) { - for (unsigned I = 0, N = Id.size(); I != N; ++I) { - if (I) - OS << "."; - OS << Id[I].first; - } -} - void Module::getExportedModules(SmallVectorImpl &Exported) const { // All non-explicit submodules are exported. for (std::vector::const_iterator I = SubModules.begin(), @@ -334,7 +352,8 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS << "framework "; if (IsExplicit) OS << "explicit "; - OS << "module " << Name; + OS << "module "; + printModuleId(OS, &Name, &Name + 1); if (IsSystem || IsExternC) { OS.indent(Indent + 2); @@ -434,7 +453,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS.indent(Indent + 2); OS << "export "; if (Module *Restriction = Exports[I].getPointer()) { - OS << Restriction->getFullModuleName(); + OS << Restriction->getFullModuleName(true); if (Exports[I].getInt()) OS << ".*"; } else { @@ -455,7 +474,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { for (unsigned I = 0, N = DirectUses.size(); I != N; ++I) { OS.indent(Indent + 2); OS << "use "; - OS << DirectUses[I]->getFullModuleName(); + OS << DirectUses[I]->getFullModuleName(true); OS << "\n"; } @@ -488,7 +507,7 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { for (unsigned I = 0, N = Conflicts.size(); I != N; ++I) { OS.indent(Indent + 2); OS << "conflict "; - OS << Conflicts[I].Other->getFullModuleName(); + OS << Conflicts[I].Other->getFullModuleName(true); OS << ", \""; OS.write_escaped(Conflicts[I].Message); OS << "\"\n"; diff --git a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp index fc4c6d303801..3936afab21a4 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp @@ -359,15 +359,6 @@ void SourceManager::initializeForReplay(const SourceManager &Old) { return Clone; }; - // Set up our main file ID as a copy of the old source manager's main file. - const SLocEntry &OldMainFile = Old.getSLocEntry(Old.getMainFileID()); - assert(OldMainFile.isFile() && "main file is macro expansion?"); - auto *MainCC = CloneContentCache(OldMainFile.getFile().getContentCache()); - MemBufferInfos.push_back(MainCC); - setMainFileID(createFileID(MainCC, SourceLocation(), - OldMainFile.getFile().getFileCharacteristic(), - 0, 0)); - // Ensure all SLocEntries are loaded from the external source. for (unsigned I = 0, N = Old.LoadedSLocEntryTable.size(); I != N; ++I) if (!Old.SLocEntryLoaded[I]) diff --git a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp index 8cfd8bde9cbb..4bcebadf458f 100644 --- a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp @@ -507,6 +507,11 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { case '?': // Disparage slightly code. case '!': // Disparage severely. case '*': // Ignore for choosing register preferences. + case 'i': // Ignore i,n,E,F as output constraints (match from the other + // chars) + case 'n': + case 'E': + case 'F': break; // Pass them. } diff --git a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp index a3b8330707b9..c5af99e4b6af 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp @@ -111,6 +111,21 @@ class CloudABITargetInfo : public OSTargetInfo { : OSTargetInfo(Triple, Opts) {} }; +// Ananas target +template +class AnanasTargetInfo : public OSTargetInfo { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + // Ananas defines + Builder.defineMacro("__Ananas__"); + Builder.defineMacro("__ELF__"); + } +public: + AnanasTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo(Triple, Opts) {} +}; + static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, const llvm::Triple &Triple, StringRef &PlatformName, @@ -6172,6 +6187,8 @@ class AArch64TargetInfo : public TargetInfo { unsigned Crypto; unsigned Unaligned; unsigned V8_1A; + unsigned V8_2A; + unsigned HasFullFP16; static const Builtin::Info BuiltinInfo[]; @@ -6303,6 +6320,8 @@ class AArch64TargetInfo : public TargetInfo { if (V8_1A) Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); + if (V8_2A && FPU == NeonMode && HasFullFP16) + Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); @@ -6330,6 +6349,8 @@ class AArch64TargetInfo : public TargetInfo { Crypto = 0; Unaligned = 1; V8_1A = 0; + V8_2A = 0; + HasFullFP16 = 0; for (const auto &Feature : Features) { if (Feature == "+neon") @@ -6342,6 +6363,10 @@ class AArch64TargetInfo : public TargetInfo { Unaligned = 0; if (Feature == "+v8.1a") V8_1A = 1; + if (Feature == "+v8.2a") + V8_2A = 1; + if (Feature == "+fullfp16") + HasFullFP16 = 1; } setDataLayout(); @@ -7493,7 +7518,7 @@ class MSP430TargetInfo : public TargetInfo { IntPtrType = SignedInt; PtrDiffType = SignedInt; SigAtomicType = SignedLong; - resetDataLayout("e-m:e-p:16:16-i32:16:32-a:16-n8:16"); + resetDataLayout("e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { @@ -9520,6 +9545,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new DarwinI386TargetInfo(Triple, Opts); switch (os) { + case llvm::Triple::Ananas: + return new AnanasTargetInfo(Triple, Opts); case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple, Opts); case llvm::Triple::Linux: { @@ -9575,6 +9602,8 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple, return new DarwinX86_64TargetInfo(Triple, Opts); switch (os) { + case llvm::Triple::Ananas: + return new AnanasTargetInfo(Triple, Opts); case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple, Opts); case llvm::Triple::Linux: { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp index 8f0c22d1f7ef..a6451b7fc3c1 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp @@ -2956,8 +2956,9 @@ static llvm::VectorType *GetNeonType(CodeGenFunction *CGF, return llvm::VectorType::get(CGF->Int8Ty, V1Ty ? 1 : (8 << IsQuad)); case NeonTypeFlags::Int16: case NeonTypeFlags::Poly16: - case NeonTypeFlags::Float16: return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad)); + case NeonTypeFlags::Float16: + return llvm::VectorType::get(CGF->HalfTy, V1Ty ? 1 : (4 << IsQuad)); case NeonTypeFlags::Int32: return llvm::VectorType::get(CGF->Int32Ty, V1Ty ? 1 : (2 << IsQuad)); case NeonTypeFlags::Int64: @@ -2980,6 +2981,8 @@ static llvm::VectorType *GetFloatNeonType(CodeGenFunction *CGF, NeonTypeFlags IntTypeFlags) { int IsQuad = IntTypeFlags.isQuad(); switch (IntTypeFlags.getEltType()) { + case NeonTypeFlags::Int16: + return llvm::VectorType::get(CGF->HalfTy, (4 << IsQuad)); case NeonTypeFlags::Int32: return llvm::VectorType::get(CGF->FloatTy, (2 << IsQuad)); case NeonTypeFlags::Int64: @@ -3127,55 +3130,80 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = { NEONMAP1(vcvt_f16_f32, arm_neon_vcvtfp2hf, 0), NEONMAP1(vcvt_f32_f16, arm_neon_vcvthf2fp, 0), NEONMAP0(vcvt_f32_v), + NEONMAP2(vcvt_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), + NEONMAP1(vcvt_n_s16_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s32_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s64_v, arm_neon_vcvtfp2fxs, 0), + NEONMAP1(vcvt_n_u16_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u32_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u64_v, arm_neon_vcvtfp2fxu, 0), + NEONMAP0(vcvt_s16_v), NEONMAP0(vcvt_s32_v), NEONMAP0(vcvt_s64_v), + NEONMAP0(vcvt_u16_v), NEONMAP0(vcvt_u32_v), NEONMAP0(vcvt_u64_v), + NEONMAP1(vcvta_s16_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_s32_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_s64_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_u32_v, arm_neon_vcvtau, 0), NEONMAP1(vcvta_u64_v, arm_neon_vcvtau, 0), + NEONMAP1(vcvtaq_s16_v, arm_neon_vcvtas, 0), NEONMAP1(vcvtaq_s32_v, arm_neon_vcvtas, 0), NEONMAP1(vcvtaq_s64_v, arm_neon_vcvtas, 0), + NEONMAP1(vcvtaq_u16_v, arm_neon_vcvtau, 0), NEONMAP1(vcvtaq_u32_v, arm_neon_vcvtau, 0), NEONMAP1(vcvtaq_u64_v, arm_neon_vcvtau, 0), + NEONMAP1(vcvtm_s16_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtm_s32_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtm_s64_v, arm_neon_vcvtms, 0), + NEONMAP1(vcvtm_u16_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtm_u32_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtm_u64_v, arm_neon_vcvtmu, 0), + NEONMAP1(vcvtmq_s16_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtmq_s32_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtmq_s64_v, arm_neon_vcvtms, 0), + NEONMAP1(vcvtmq_u16_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtmq_u32_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtmq_u64_v, arm_neon_vcvtmu, 0), + NEONMAP1(vcvtn_s16_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtn_s32_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtn_s64_v, arm_neon_vcvtns, 0), + NEONMAP1(vcvtn_u16_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtn_u32_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtn_u64_v, arm_neon_vcvtnu, 0), + NEONMAP1(vcvtnq_s16_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtnq_s32_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtnq_s64_v, arm_neon_vcvtns, 0), + NEONMAP1(vcvtnq_u16_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtnq_u32_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtnq_u64_v, arm_neon_vcvtnu, 0), + NEONMAP1(vcvtp_s16_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtp_s32_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtp_s64_v, arm_neon_vcvtps, 0), + NEONMAP1(vcvtp_u16_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtp_u32_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtp_u64_v, arm_neon_vcvtpu, 0), + NEONMAP1(vcvtpq_s16_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtpq_s32_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtpq_s64_v, arm_neon_vcvtps, 0), + NEONMAP1(vcvtpq_u16_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtpq_u32_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtpq_u64_v, arm_neon_vcvtpu, 0), NEONMAP0(vcvtq_f32_v), + NEONMAP2(vcvtq_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), + NEONMAP1(vcvtq_n_s16_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s32_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s64_v, arm_neon_vcvtfp2fxs, 0), + NEONMAP1(vcvtq_n_u16_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u32_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u64_v, arm_neon_vcvtfp2fxu, 0), + NEONMAP0(vcvtq_s16_v), NEONMAP0(vcvtq_s32_v), NEONMAP0(vcvtq_s64_v), + NEONMAP0(vcvtq_u16_v), NEONMAP0(vcvtq_u32_v), NEONMAP0(vcvtq_u64_v), NEONMAP0(vext_v), @@ -3338,19 +3366,27 @@ static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = { NEONMAP1(vcnt_v, ctpop, Add1ArgType), NEONMAP1(vcntq_v, ctpop, Add1ArgType), NEONMAP1(vcvt_f16_f32, aarch64_neon_vcvtfp2hf, 0), + NEONMAP0(vcvt_f16_v), NEONMAP1(vcvt_f32_f16, aarch64_neon_vcvthf2fp, 0), NEONMAP0(vcvt_f32_v), + NEONMAP2(vcvt_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), + NEONMAP1(vcvt_n_s16_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s32_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s64_v, aarch64_neon_vcvtfp2fxs, 0), + NEONMAP1(vcvt_n_u16_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u32_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u64_v, aarch64_neon_vcvtfp2fxu, 0), + NEONMAP0(vcvtq_f16_v), NEONMAP0(vcvtq_f32_v), + NEONMAP2(vcvtq_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), + NEONMAP1(vcvtq_n_s16_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s32_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s64_v, aarch64_neon_vcvtfp2fxs, 0), + NEONMAP1(vcvtq_n_u16_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u32_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u64_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtx_f32_v, aarch64_neon_fcvtxn, AddRetType | Add1ArgType), @@ -3819,9 +3855,20 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( case NEON::BI__builtin_neon_vcageq_v: case NEON::BI__builtin_neon_vcagt_v: case NEON::BI__builtin_neon_vcagtq_v: { - llvm::Type *VecFlt = llvm::VectorType::get( - VTy->getScalarSizeInBits() == 32 ? FloatTy : DoubleTy, - VTy->getNumElements()); + llvm::Type *Ty; + switch (VTy->getScalarSizeInBits()) { + default: llvm_unreachable("unexpected type"); + case 32: + Ty = FloatTy; + break; + case 64: + Ty = DoubleTy; + break; + case 16: + Ty = HalfTy; + break; + } + llvm::Type *VecFlt = llvm::VectorType::get(Ty, VTy->getNumElements()); llvm::Type *Tys[] = { VTy, VecFlt }; Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys); return EmitNeonCall(F, Ops, NameHint); @@ -3838,8 +3885,16 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, Quad)); return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt") : Builder.CreateSIToFP(Ops[0], Ty, "vcvt"); + case NEON::BI__builtin_neon_vcvt_f16_v: + case NEON::BI__builtin_neon_vcvtq_f16_v: + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float16, false, Quad)); + return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt") + : Builder.CreateSIToFP(Ops[0], Ty, "vcvt"); + case NEON::BI__builtin_neon_vcvt_n_f16_v: case NEON::BI__builtin_neon_vcvt_n_f32_v: case NEON::BI__builtin_neon_vcvt_n_f64_v: + case NEON::BI__builtin_neon_vcvtq_n_f16_v: case NEON::BI__builtin_neon_vcvtq_n_f32_v: case NEON::BI__builtin_neon_vcvtq_n_f64_v: { llvm::Type *Tys[2] = { GetFloatNeonType(this, Type), Ty }; @@ -3847,11 +3902,15 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( Function *F = CGM.getIntrinsic(Int, Tys); return EmitNeonCall(F, Ops, "vcvt_n"); } + case NEON::BI__builtin_neon_vcvt_n_s16_v: case NEON::BI__builtin_neon_vcvt_n_s32_v: + case NEON::BI__builtin_neon_vcvt_n_u16_v: case NEON::BI__builtin_neon_vcvt_n_u32_v: case NEON::BI__builtin_neon_vcvt_n_s64_v: case NEON::BI__builtin_neon_vcvt_n_u64_v: + case NEON::BI__builtin_neon_vcvtq_n_s16_v: case NEON::BI__builtin_neon_vcvtq_n_s32_v: + case NEON::BI__builtin_neon_vcvtq_n_u16_v: case NEON::BI__builtin_neon_vcvtq_n_u32_v: case NEON::BI__builtin_neon_vcvtq_n_s64_v: case NEON::BI__builtin_neon_vcvtq_n_u64_v: { @@ -3863,44 +3922,63 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( case NEON::BI__builtin_neon_vcvt_u32_v: case NEON::BI__builtin_neon_vcvt_s64_v: case NEON::BI__builtin_neon_vcvt_u64_v: + case NEON::BI__builtin_neon_vcvt_s16_v: + case NEON::BI__builtin_neon_vcvt_u16_v: case NEON::BI__builtin_neon_vcvtq_s32_v: case NEON::BI__builtin_neon_vcvtq_u32_v: case NEON::BI__builtin_neon_vcvtq_s64_v: - case NEON::BI__builtin_neon_vcvtq_u64_v: { + case NEON::BI__builtin_neon_vcvtq_u64_v: + case NEON::BI__builtin_neon_vcvtq_s16_v: + case NEON::BI__builtin_neon_vcvtq_u16_v: { Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type)); return Usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt") : Builder.CreateFPToSI(Ops[0], Ty, "vcvt"); } + case NEON::BI__builtin_neon_vcvta_s16_v: case NEON::BI__builtin_neon_vcvta_s32_v: case NEON::BI__builtin_neon_vcvta_s64_v: case NEON::BI__builtin_neon_vcvta_u32_v: case NEON::BI__builtin_neon_vcvta_u64_v: + case NEON::BI__builtin_neon_vcvtaq_s16_v: case NEON::BI__builtin_neon_vcvtaq_s32_v: case NEON::BI__builtin_neon_vcvtaq_s64_v: + case NEON::BI__builtin_neon_vcvtaq_u16_v: case NEON::BI__builtin_neon_vcvtaq_u32_v: case NEON::BI__builtin_neon_vcvtaq_u64_v: + case NEON::BI__builtin_neon_vcvtn_s16_v: case NEON::BI__builtin_neon_vcvtn_s32_v: case NEON::BI__builtin_neon_vcvtn_s64_v: + case NEON::BI__builtin_neon_vcvtn_u16_v: case NEON::BI__builtin_neon_vcvtn_u32_v: case NEON::BI__builtin_neon_vcvtn_u64_v: + case NEON::BI__builtin_neon_vcvtnq_s16_v: case NEON::BI__builtin_neon_vcvtnq_s32_v: case NEON::BI__builtin_neon_vcvtnq_s64_v: + case NEON::BI__builtin_neon_vcvtnq_u16_v: case NEON::BI__builtin_neon_vcvtnq_u32_v: case NEON::BI__builtin_neon_vcvtnq_u64_v: + case NEON::BI__builtin_neon_vcvtp_s16_v: case NEON::BI__builtin_neon_vcvtp_s32_v: case NEON::BI__builtin_neon_vcvtp_s64_v: + case NEON::BI__builtin_neon_vcvtp_u16_v: case NEON::BI__builtin_neon_vcvtp_u32_v: case NEON::BI__builtin_neon_vcvtp_u64_v: + case NEON::BI__builtin_neon_vcvtpq_s16_v: case NEON::BI__builtin_neon_vcvtpq_s32_v: case NEON::BI__builtin_neon_vcvtpq_s64_v: + case NEON::BI__builtin_neon_vcvtpq_u16_v: case NEON::BI__builtin_neon_vcvtpq_u32_v: case NEON::BI__builtin_neon_vcvtpq_u64_v: + case NEON::BI__builtin_neon_vcvtm_s16_v: case NEON::BI__builtin_neon_vcvtm_s32_v: case NEON::BI__builtin_neon_vcvtm_s64_v: + case NEON::BI__builtin_neon_vcvtm_u16_v: case NEON::BI__builtin_neon_vcvtm_u32_v: case NEON::BI__builtin_neon_vcvtm_u64_v: + case NEON::BI__builtin_neon_vcvtmq_s16_v: case NEON::BI__builtin_neon_vcvtmq_s32_v: case NEON::BI__builtin_neon_vcvtmq_s64_v: + case NEON::BI__builtin_neon_vcvtmq_u16_v: case NEON::BI__builtin_neon_vcvtmq_u32_v: case NEON::BI__builtin_neon_vcvtmq_u64_v: { llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; @@ -6110,7 +6188,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[2] = EmitNeonSplat(Ops[2], cast(Ops[3])); return Builder.CreateCall(F, {Ops[2], Ops[1], Ops[0]}); } + case NEON::BI__builtin_neon_vfmah_lane_f16: case NEON::BI__builtin_neon_vfmas_lane_f32: + case NEON::BI__builtin_neon_vfmah_laneq_f16: case NEON::BI__builtin_neon_vfmas_laneq_f32: case NEON::BI__builtin_neon_vfmad_lane_f64: case NEON::BI__builtin_neon_vfmad_laneq_f64: { @@ -6285,18 +6365,25 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, case NEON::BI__builtin_neon_vcvt_u32_v: case NEON::BI__builtin_neon_vcvt_s64_v: case NEON::BI__builtin_neon_vcvt_u64_v: + case NEON::BI__builtin_neon_vcvt_s16_v: + case NEON::BI__builtin_neon_vcvt_u16_v: case NEON::BI__builtin_neon_vcvtq_s32_v: case NEON::BI__builtin_neon_vcvtq_u32_v: case NEON::BI__builtin_neon_vcvtq_s64_v: - case NEON::BI__builtin_neon_vcvtq_u64_v: { + case NEON::BI__builtin_neon_vcvtq_u64_v: + case NEON::BI__builtin_neon_vcvtq_s16_v: + case NEON::BI__builtin_neon_vcvtq_u16_v: { Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type)); if (usgn) return Builder.CreateFPToUI(Ops[0], Ty); return Builder.CreateFPToSI(Ops[0], Ty); } + case NEON::BI__builtin_neon_vcvta_s16_v: case NEON::BI__builtin_neon_vcvta_s32_v: + case NEON::BI__builtin_neon_vcvtaq_s16_v: case NEON::BI__builtin_neon_vcvtaq_s32_v: case NEON::BI__builtin_neon_vcvta_u32_v: + case NEON::BI__builtin_neon_vcvtaq_u16_v: case NEON::BI__builtin_neon_vcvtaq_u32_v: case NEON::BI__builtin_neon_vcvta_s64_v: case NEON::BI__builtin_neon_vcvtaq_s64_v: @@ -6306,9 +6393,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvta"); } + case NEON::BI__builtin_neon_vcvtm_s16_v: case NEON::BI__builtin_neon_vcvtm_s32_v: + case NEON::BI__builtin_neon_vcvtmq_s16_v: case NEON::BI__builtin_neon_vcvtmq_s32_v: + case NEON::BI__builtin_neon_vcvtm_u16_v: case NEON::BI__builtin_neon_vcvtm_u32_v: + case NEON::BI__builtin_neon_vcvtmq_u16_v: case NEON::BI__builtin_neon_vcvtmq_u32_v: case NEON::BI__builtin_neon_vcvtm_s64_v: case NEON::BI__builtin_neon_vcvtmq_s64_v: @@ -6318,9 +6409,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtm"); } + case NEON::BI__builtin_neon_vcvtn_s16_v: case NEON::BI__builtin_neon_vcvtn_s32_v: + case NEON::BI__builtin_neon_vcvtnq_s16_v: case NEON::BI__builtin_neon_vcvtnq_s32_v: + case NEON::BI__builtin_neon_vcvtn_u16_v: case NEON::BI__builtin_neon_vcvtn_u32_v: + case NEON::BI__builtin_neon_vcvtnq_u16_v: case NEON::BI__builtin_neon_vcvtnq_u32_v: case NEON::BI__builtin_neon_vcvtn_s64_v: case NEON::BI__builtin_neon_vcvtnq_s64_v: @@ -6330,9 +6425,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtn"); } + case NEON::BI__builtin_neon_vcvtp_s16_v: case NEON::BI__builtin_neon_vcvtp_s32_v: + case NEON::BI__builtin_neon_vcvtpq_s16_v: case NEON::BI__builtin_neon_vcvtpq_s32_v: + case NEON::BI__builtin_neon_vcvtp_u16_v: case NEON::BI__builtin_neon_vcvtp_u32_v: + case NEON::BI__builtin_neon_vcvtpq_u16_v: case NEON::BI__builtin_neon_vcvtpq_u32_v: case NEON::BI__builtin_neon_vcvtp_s64_v: case NEON::BI__builtin_neon_vcvtpq_s64_v: @@ -6505,6 +6604,24 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); return Builder.CreateTrunc(Ops[0], Int16Ty); } + case NEON::BI__builtin_neon_vmaxv_f16: { + Int = Intrinsic::aarch64_neon_fmaxv; + Ty = HalfTy; + VTy = llvm::VectorType::get(HalfTy, 4); + llvm::Type *Tys[2] = { Ty, VTy }; + Ops.push_back(EmitScalarExpr(E->getArg(0))); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); + return Builder.CreateTrunc(Ops[0], HalfTy); + } + case NEON::BI__builtin_neon_vmaxvq_f16: { + Int = Intrinsic::aarch64_neon_fmaxv; + Ty = HalfTy; + VTy = llvm::VectorType::get(HalfTy, 8); + llvm::Type *Tys[2] = { Ty, VTy }; + Ops.push_back(EmitScalarExpr(E->getArg(0))); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); + return Builder.CreateTrunc(Ops[0], HalfTy); + } case NEON::BI__builtin_neon_vminv_u8: { Int = Intrinsic::aarch64_neon_uminv; Ty = Int32Ty; @@ -6577,6 +6694,60 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); return Builder.CreateTrunc(Ops[0], Int16Ty); } + case NEON::BI__builtin_neon_vminv_f16: { + Int = Intrinsic::aarch64_neon_fminv; + Ty = HalfTy; + VTy = llvm::VectorType::get(HalfTy, 4); + llvm::Type *Tys[2] = { Ty, VTy }; + Ops.push_back(EmitScalarExpr(E->getArg(0))); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); + return Builder.CreateTrunc(Ops[0], HalfTy); + } + case NEON::BI__builtin_neon_vminvq_f16: { + Int = Intrinsic::aarch64_neon_fminv; + Ty = HalfTy; + VTy = llvm::VectorType::get(HalfTy, 8); + llvm::Type *Tys[2] = { Ty, VTy }; + Ops.push_back(EmitScalarExpr(E->getArg(0))); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); + return Builder.CreateTrunc(Ops[0], HalfTy); + } + case NEON::BI__builtin_neon_vmaxnmv_f16: { + Int = Intrinsic::aarch64_neon_fmaxnmv; + Ty = HalfTy; + VTy = llvm::VectorType::get(HalfTy, 4); + llvm::Type *Tys[2] = { Ty, VTy }; + Ops.push_back(EmitScalarExpr(E->getArg(0))); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv"); + return Builder.CreateTrunc(Ops[0], HalfTy); + } + case NEON::BI__builtin_neon_vmaxnmvq_f16: { + Int = Intrinsic::aarch64_neon_fmaxnmv; + Ty = HalfTy; + VTy = llvm::VectorType::get(HalfTy, 8); + llvm::Type *Tys[2] = { Ty, VTy }; + Ops.push_back(EmitScalarExpr(E->getArg(0))); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv"); + return Builder.CreateTrunc(Ops[0], HalfTy); + } + case NEON::BI__builtin_neon_vminnmv_f16: { + Int = Intrinsic::aarch64_neon_fminnmv; + Ty = HalfTy; + VTy = llvm::VectorType::get(HalfTy, 4); + llvm::Type *Tys[2] = { Ty, VTy }; + Ops.push_back(EmitScalarExpr(E->getArg(0))); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv"); + return Builder.CreateTrunc(Ops[0], HalfTy); + } + case NEON::BI__builtin_neon_vminnmvq_f16: { + Int = Intrinsic::aarch64_neon_fminnmv; + Ty = HalfTy; + VTy = llvm::VectorType::get(HalfTy, 8); + llvm::Type *Tys[2] = { Ty, VTy }; + Ops.push_back(EmitScalarExpr(E->getArg(0))); + Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv"); + return Builder.CreateTrunc(Ops[0], HalfTy); + } case NEON::BI__builtin_neon_vmul_n_f64: { Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy); Value *RHS = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)), DoubleTy); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp index c65dc18be306..38d520a2beb0 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp @@ -2906,7 +2906,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, llvm::Instruction *Ret; if (RV) { - EmitReturnValueCheck(RV, EndLoc); + EmitReturnValueCheck(RV); Ret = Builder.CreateRet(RV); } else { Ret = Builder.CreateRetVoid(); @@ -2916,8 +2916,7 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, Ret->setDebugLoc(std::move(RetDbgLoc)); } -void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV, - SourceLocation EndLoc) { +void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) { // A current decl may not be available when emitting vtable thunks. if (!CurCodeDecl) return; @@ -2950,27 +2949,30 @@ void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV, SanitizerScope SanScope(this); - llvm::BasicBlock *Check = nullptr; - llvm::BasicBlock *NoCheck = nullptr; - if (requiresReturnValueNullabilityCheck()) { - // Before doing the nullability check, make sure that the preconditions for - // the check are met. - Check = createBasicBlock("nullcheck"); - NoCheck = createBasicBlock("no.nullcheck"); - Builder.CreateCondBr(RetValNullabilityPrecondition, Check, NoCheck); - EmitBlock(Check); - } - - // Now do the null check. If the returns_nonnull attribute is present, this - // is done unconditionally. - llvm::Value *Cond = Builder.CreateIsNotNull(RV); - llvm::Constant *StaticData[] = { - EmitCheckSourceLocation(EndLoc), EmitCheckSourceLocation(AttrLoc), - }; - EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, None); - + // Make sure the "return" source location is valid. If we're checking a + // nullability annotation, make sure the preconditions for the check are met. + llvm::BasicBlock *Check = createBasicBlock("nullcheck"); + llvm::BasicBlock *NoCheck = createBasicBlock("no.nullcheck"); + llvm::Value *SLocPtr = Builder.CreateLoad(ReturnLocation, "return.sloc.load"); + llvm::Value *CanNullCheck = Builder.CreateIsNotNull(SLocPtr); if (requiresReturnValueNullabilityCheck()) - EmitBlock(NoCheck); + CanNullCheck = + Builder.CreateAnd(CanNullCheck, RetValNullabilityPrecondition); + Builder.CreateCondBr(CanNullCheck, Check, NoCheck); + EmitBlock(Check); + + // Now do the null check. + llvm::Value *Cond = Builder.CreateIsNotNull(RV); + llvm::Constant *StaticData[] = {EmitCheckSourceLocation(AttrLoc)}; + llvm::Value *DynamicData[] = {SLocPtr}; + EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, DynamicData); + + EmitBlock(NoCheck); + +#ifndef NDEBUG + // The return location should not be used after the check has been emitted. + ReturnLocation = Address::invalid(); +#endif } static bool isInAllocaArgument(CGCXXABI &ABI, QualType type) { @@ -3813,7 +3815,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(NumIRArgs == 1); if (RV.isScalar() || RV.isComplex()) { // Make a temporary alloca to pass the argument. - Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign()); + Address Addr = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(), + "indirect-arg-temp", false); IRCallArgs[FirstIRArg] = Addr.getPointer(); LValue argLV = MakeAddrLValue(Addr, I->Ty); @@ -3842,7 +3845,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, < Align.getQuantity()) || (ArgInfo.getIndirectByVal() && (RVAddrSpace != ArgAddrSpace))) { // Create an aligned temporary, and copy to it. - Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign()); + Address AI = CreateMemTemp(I->Ty, ArgInfo.getIndirectAlign(), + "byval-temp", false); IRCallArgs[FirstIRArg] = AI.getPointer(); EmitAggregateCopy(AI, Addr, I->Ty, RV.isVolatileQualified()); } else { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp index 5b4dc5ff0ab3..127d7df348ee 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp @@ -2770,10 +2770,19 @@ CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, // We can devirtualize calls on an object accessed by a class member access // expression, since by C++11 [basic.life]p6 we know that it can't refer to - // a derived class object constructed in the same location. + // a derived class object constructed in the same location. However, we avoid + // devirtualizing a call to a template function that we could instantiate + // implicitly, but have not decided to do so. This is needed because if this + // function does not get instantiated, the devirtualization will create a + // direct call to a function whose body may not exist. In contrast, calls to + // template functions that are not defined in this TU are allowed to be + // devirtualized under assumption that it is user responsibility to + // instantiate them in some other TU. if (const MemberExpr *ME = dyn_cast(Base)) if (const ValueDecl *VD = dyn_cast(ME->getMemberDecl())) - return VD->getType()->isRecordType(); + return VD->getType()->isRecordType() && + (MD->instantiationIsPending() || MD->isDefined() || + !MD->isImplicitlyInstantiable()); // Likewise for calls on an object accessed by a (non-reference) pointer to // member access. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp index 87bfa507a8c0..ccd3b8d513b1 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp @@ -954,6 +954,7 @@ void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) { CodeGenFunction::AutoVarEmission CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { QualType Ty = D.getType(); + assert(Ty.getAddressSpace() == LangAS::Default); AutoVarEmission emission(D); @@ -1046,8 +1047,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // Create the alloca. Note that we set the name separately from // building the instruction so that it's there even in no-asserts // builds. - address = CreateTempAlloca(allocaTy, allocaAlignment); - address.getPointer()->setName(D.getName()); + address = CreateTempAlloca(allocaTy, allocaAlignment, D.getName()); // Don't emit lifetime markers for MSVC catch parameters. The lifetime of // the catch parameter starts in the catchpad instruction, and we can't @@ -1107,27 +1107,9 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { llvm::Type *llvmTy = ConvertTypeForMem(elementType); // Allocate memory for the array. - llvm::AllocaInst *vla = Builder.CreateAlloca(llvmTy, elementCount, "vla"); - vla->setAlignment(alignment.getQuantity()); - - address = Address(vla, alignment); + address = CreateTempAlloca(llvmTy, alignment, "vla", elementCount); } - // Alloca always returns a pointer in alloca address space, which may - // be different from the type defined by the language. For example, - // in C++ the auto variables are in the default address space. Therefore - // cast alloca to the expected address space when necessary. - auto T = D.getType(); - assert(T.getAddressSpace() == LangAS::Default); - if (getASTAllocaAddressSpace() != LangAS::Default) { - auto *Addr = getTargetHooks().performAddrSpaceCast( - *this, address.getPointer(), getASTAllocaAddressSpace(), - T.getAddressSpace(), - address.getElementType()->getPointerTo( - getContext().getTargetAddressSpace(T.getAddressSpace())), - /*non-null*/ true); - address = Address(Addr, address.getAlignment()); - } setAddrOfLocalVar(&D, address); emission.Addr = address; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp index 7359006677f4..2ee1c96a6619 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp @@ -61,18 +61,36 @@ llvm::Value *CodeGenFunction::EmitCastToVoidPtr(llvm::Value *value) { /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, - const Twine &Name) { - auto Alloca = CreateTempAlloca(Ty, Name); + const Twine &Name, + llvm::Value *ArraySize, + bool CastToDefaultAddrSpace) { + auto Alloca = CreateTempAlloca(Ty, Name, ArraySize); Alloca->setAlignment(Align.getQuantity()); - return Address(Alloca, Align); + llvm::Value *V = Alloca; + // Alloca always returns a pointer in alloca address space, which may + // be different from the type defined by the language. For example, + // in C++ the auto variables are in the default address space. Therefore + // cast alloca to the default address space when necessary. + if (CastToDefaultAddrSpace && getASTAllocaAddressSpace() != LangAS::Default) { + auto DestAddrSpace = getContext().getTargetAddressSpace(LangAS::Default); + V = getTargetHooks().performAddrSpaceCast( + *this, V, getASTAllocaAddressSpace(), LangAS::Default, + Ty->getPointerTo(DestAddrSpace), /*non-null*/ true); + } + + return Address(V, Align); } -/// CreateTempAlloca - This creates a alloca and inserts it into the entry -/// block. +/// CreateTempAlloca - This creates an alloca and inserts it into the entry +/// block if \p ArraySize is nullptr, otherwise inserts it at the current +/// insertion point of the builder. llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, - const Twine &Name) { + const Twine &Name, + llvm::Value *ArraySize) { + if (ArraySize) + return Builder.CreateAlloca(Ty, ArraySize, Name); return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(), - nullptr, Name, AllocaInsertPt); + ArraySize, Name, AllocaInsertPt); } /// CreateDefaultAlignTempAlloca - This creates an alloca with the @@ -99,14 +117,18 @@ Address CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) { return CreateTempAlloca(ConvertType(Ty), Align, Name); } -Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name) { +Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name, + bool CastToDefaultAddrSpace) { // FIXME: Should we prefer the preferred type alignment here? - return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name); + return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name, + CastToDefaultAddrSpace); } Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align, - const Twine &Name) { - return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name); + const Twine &Name, + bool CastToDefaultAddrSpace) { + return CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, nullptr, + CastToDefaultAddrSpace); } /// EvaluateExprAsBool - Perform the usual unary conversions on the specified diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp index c78d3febd4cd..7976c53d9e98 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp @@ -308,7 +308,7 @@ class ObjCCommonTypesHelper { SmallVector Params; Params.push_back(Ctx.VoidPtrTy); Params.push_back(Ctx.VoidPtrTy); - Params.push_back(Ctx.LongTy); + Params.push_back(Ctx.getSizeType()); Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); llvm::FunctionType *FTy = diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp index 683f366ebe45..a13c38646164 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp @@ -1024,6 +1024,18 @@ void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { /// if the function returns void, or may be missing one if the function returns /// non-void. Fun stuff :). void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { + if (requiresReturnValueCheck()) { + llvm::Constant *SLoc = EmitCheckSourceLocation(S.getLocStart()); + auto *SLocPtr = + new llvm::GlobalVariable(CGM.getModule(), SLoc->getType(), false, + llvm::GlobalVariable::PrivateLinkage, SLoc); + SLocPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr); + assert(ReturnLocation.isValid() && "No valid return location"); + Builder.CreateStore(Builder.CreateBitCast(SLocPtr, Int8PtrTy), + ReturnLocation); + } + // Returning from an outlined SEH helper is UB, and we already warn on it. if (IsOutlinedSEHHelper) { Builder.CreateUnreachable(); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp index ac1a1334f103..93a4a3866193 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp @@ -860,6 +860,13 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, Builder.SetInsertPoint(EntryBB); + // If we're checking the return value, allocate space for a pointer to a + // precise source location of the checked return statement. + if (requiresReturnValueCheck()) { + ReturnLocation = CreateDefaultAlignTempAlloca(Int8PtrTy, "return.sloc.ptr"); + InitTempAlloca(ReturnLocation, llvm::ConstantPointerNull::get(Int8PtrTy)); + } + // Emit subprogram debug descriptor. if (CGDebugInfo *DI = getDebugInfo()) { // Reconstruct the type from the argument list so that implicit parameters, @@ -887,8 +894,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, if (CGM.getCodeGenOpts().InstrumentForProfiling) { if (CGM.getCodeGenOpts().CallFEntry) Fn->addFnAttr("fentry-call", "true"); - else - Fn->addFnAttr("counting-function", getTarget().getMCountName()); + else { + if (!CurFuncDecl || !CurFuncDecl->hasAttr()) + Fn->addFnAttr("counting-function", getTarget().getMCountName()); + } } if (RetTy->isVoidType()) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h index 831eedf9e478..6785111bd052 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h @@ -116,9 +116,9 @@ enum TypeEvaluationKind { SANITIZER_CHECK(MulOverflow, mul_overflow, 0) \ SANITIZER_CHECK(NegateOverflow, negate_overflow, 0) \ SANITIZER_CHECK(NullabilityArg, nullability_arg, 0) \ - SANITIZER_CHECK(NullabilityReturn, nullability_return, 0) \ + SANITIZER_CHECK(NullabilityReturn, nullability_return, 1) \ SANITIZER_CHECK(NonnullArg, nonnull_arg, 0) \ - SANITIZER_CHECK(NonnullReturn, nonnull_return, 0) \ + SANITIZER_CHECK(NonnullReturn, nonnull_return, 1) \ SANITIZER_CHECK(OutOfBounds, out_of_bounds, 0) \ SANITIZER_CHECK(PointerOverflow, pointer_overflow, 0) \ SANITIZER_CHECK(ShiftOutOfBounds, shift_out_of_bounds, 0) \ @@ -1407,6 +1407,17 @@ class CodeGenFunction : public CodeGenTypeCache { return RetValNullabilityPrecondition; } + /// Used to store precise source locations for return statements by the + /// runtime return value checks. + Address ReturnLocation = Address::invalid(); + + /// Check if the return value of this function requires sanitization. + bool requiresReturnValueCheck() const { + return requiresReturnValueNullabilityCheck() || + (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) && + CurCodeDecl && CurCodeDecl->getAttr()); + } + llvm::BasicBlock *TerminateLandingPad; llvm::BasicBlock *TerminateHandler; llvm::BasicBlock *TrapBB; @@ -1778,7 +1789,7 @@ class CodeGenFunction : public CodeGenTypeCache { SourceLocation EndLoc); /// Emit a test that checks if the return value \p RV is nonnull. - void EmitReturnValueCheck(llvm::Value *RV, SourceLocation EndLoc); + void EmitReturnValueCheck(llvm::Value *RV); /// EmitStartEHSpec - Emit the start of the exception spec. void EmitStartEHSpec(const Decl *D); @@ -1916,13 +1927,36 @@ class CodeGenFunction : public CodeGenTypeCache { LValueBaseInfo *BaseInfo = nullptr); LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy); - /// CreateTempAlloca - This creates a alloca and inserts it into the entry - /// block. The caller is responsible for setting an appropriate alignment on + /// CreateTempAlloca - This creates an alloca and inserts it into the entry + /// block if \p ArraySize is nullptr, otherwise inserts it at the current + /// insertion point of the builder. The caller is responsible for setting an + /// appropriate alignment on /// the alloca. - llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, - const Twine &Name = "tmp"); + /// + /// \p ArraySize is the number of array elements to be allocated if it + /// is not nullptr. + /// + /// LangAS::Default is the address space of pointers to local variables and + /// temporaries, as exposed in the source language. In certain + /// configurations, this is not the same as the alloca address space, and a + /// cast is needed to lift the pointer from the alloca AS into + /// LangAS::Default. This can happen when the target uses a restricted + /// address space for the stack but the source language requires + /// LangAS::Default to be a generic address space. The latter condition is + /// common for most programming languages; OpenCL is an exception in that + /// LangAS::Default is the private address space, which naturally maps + /// to the stack. + /// + /// Because the address of a temporary is often exposed to the program in + /// various ways, this function will perform the cast by default. The cast + /// may be avoided by passing false as \p CastToDefaultAddrSpace; this is + /// more efficient if the caller knows that the address will not be exposed. + llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp", + llvm::Value *ArraySize = nullptr); Address CreateTempAlloca(llvm::Type *Ty, CharUnits align, - const Twine &Name = "tmp"); + const Twine &Name = "tmp", + llvm::Value *ArraySize = nullptr, + bool CastToDefaultAddrSpace = true); /// CreateDefaultAlignedTempAlloca - This creates an alloca with the /// default ABI alignment of the given LLVM type. @@ -1957,9 +1991,12 @@ class CodeGenFunction : public CodeGenTypeCache { Address CreateIRTemp(QualType T, const Twine &Name = "tmp"); /// CreateMemTemp - Create a temporary memory object of the given type, with - /// appropriate alignment. - Address CreateMemTemp(QualType T, const Twine &Name = "tmp"); - Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp"); + /// appropriate alignment. Cast it to the default address space if + /// \p CastToDefaultAddrSpace is true. + Address CreateMemTemp(QualType T, const Twine &Name = "tmp", + bool CastToDefaultAddrSpace = true); + Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp", + bool CastToDefaultAddrSpace = true); /// CreateAggTemp - Create a temporary memory object for the given /// aggregate type. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp index 19a055075604..5319ccec163f 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp @@ -98,6 +98,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, Int16Ty = llvm::Type::getInt16Ty(LLVMContext); Int32Ty = llvm::Type::getInt32Ty(LLVMContext); Int64Ty = llvm::Type::getInt64Ty(LLVMContext); + HalfTy = llvm::Type::getHalfTy(LLVMContext); FloatTy = llvm::Type::getFloatTy(LLVMContext); DoubleTy = llvm::Type::getDoubleTy(LLVMContext); PointerWidthInBits = C.getTargetInfo().getPointerWidth(0); @@ -506,6 +507,26 @@ void CodeGenModule::Release() { LangOpts.CUDADeviceFlushDenormalsToZero ? 1 : 0); } + // Emit OpenCL specific module metadata: OpenCL/SPIR version. + if (LangOpts.OpenCL) { + EmitOpenCLMetadata(); + // Emit SPIR version. + if (getTriple().getArch() == llvm::Triple::spir || + getTriple().getArch() == llvm::Triple::spir64) { + // SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the + // opencl.spir.version named metadata. + llvm::Metadata *SPIRVerElts[] = { + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + Int32Ty, LangOpts.OpenCLVersion / 100)), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + Int32Ty, (LangOpts.OpenCLVersion / 100 > 1) ? 0 : 2))}; + llvm::NamedMDNode *SPIRVerMD = + TheModule.getOrInsertNamedMetadata("opencl.spir.version"); + llvm::LLVMContext &Ctx = TheModule.getContext(); + SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts)); + } + } + if (uint32_t PLevel = Context.getLangOpts().PICLevel) { assert(PLevel < 3 && "Invalid PIC Level"); getModule().setPICLevel(static_cast(PLevel)); @@ -529,6 +550,20 @@ void CodeGenModule::Release() { EmitTargetMetadata(); } +void CodeGenModule::EmitOpenCLMetadata() { + // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the + // opencl.ocl.version named metadata node. + llvm::Metadata *OCLVerElts[] = { + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + Int32Ty, LangOpts.OpenCLVersion / 100)), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + Int32Ty, (LangOpts.OpenCLVersion % 100) / 10))}; + llvm::NamedMDNode *OCLVerMD = + TheModule.getOrInsertNamedMetadata("opencl.ocl.version"); + llvm::LLVMContext &Ctx = TheModule.getContext(); + OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts)); +} + void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { // Make sure that this type is translated. Types.UpdateCompletedType(TD); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h index 59e56a6ba194..c5f1a2b409ee 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h @@ -1321,6 +1321,9 @@ class CodeGenModule : public CodeGenTypeCache { /// Emits target specific Metadata for global declarations. void EmitTargetMetadata(); + /// Emits OpenCL specific Metadata e.g. OpenCL version. + void EmitOpenCLMetadata(); + /// Emit the llvm.gcov metadata used to tell LLVM where to emit the .gcno and /// .gcda files in a way that persists in .bc files. void EmitCoverageFile(); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h index 450eab48a3b4..6910d36733dc 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypeCache.h @@ -36,7 +36,7 @@ struct CodeGenTypeCache { /// i8, i16, i32, and i64 llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty; /// float, double - llvm::Type *FloatTy, *DoubleTy; + llvm::Type *HalfTy, *FloatTy, *DoubleTy; /// int llvm::IntegerType *IntTy; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp b/contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp index 0bfe30a32c80..fc8e36d2c599 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/SwiftCallingConv.cpp @@ -57,6 +57,10 @@ static CharUnits getTypeStoreSize(CodeGenModule &CGM, llvm::Type *type) { return CharUnits::fromQuantity(CGM.getDataLayout().getTypeStoreSize(type)); } +static CharUnits getTypeAllocSize(CodeGenModule &CGM, llvm::Type *type) { + return CharUnits::fromQuantity(CGM.getDataLayout().getTypeAllocSize(type)); +} + void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) { // Deal with various aggregate types as special cases: @@ -542,7 +546,9 @@ SwiftAggLowering::getCoerceAndExpandTypes() const { packed = true; elts.push_back(entry.Type); - lastEnd = entry.End; + + lastEnd = entry.Begin + getTypeAllocSize(CGM, entry.Type); + assert(entry.End <= lastEnd); } // We don't need to adjust 'packed' to deal with possible tail padding diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp index 427ec06a2fff..8d00e055306d 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp @@ -951,8 +951,7 @@ class X86_32ABIInfo : public SwiftABIInfo { Class classify(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy, CCState &State) const; ABIArgInfo classifyArgumentType(QualType RetTy, CCState &State) const; - ABIArgInfo reclassifyHvaArgType(QualType RetTy, CCState &State, - const ABIArgInfo& current) const; + /// \brief Updates the number of available free registers, returns /// true if any registers were allocated. bool updateFreeRegs(QualType Ty, CCState &State) const; @@ -1536,27 +1535,6 @@ bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const { return true; } -ABIArgInfo -X86_32ABIInfo::reclassifyHvaArgType(QualType Ty, CCState &State, - const ABIArgInfo ¤t) const { - // Assumes vectorCall calling convention. - const Type *Base = nullptr; - uint64_t NumElts = 0; - - if (!Ty->isBuiltinType() && !Ty->isVectorType() && - isHomogeneousAggregate(Ty, Base, NumElts)) { - if (State.FreeSSERegs >= NumElts) { - // HVA types get passed directly in registers if there is room. - State.FreeSSERegs -= NumElts; - return getDirectX86Hva(); - } - // If there's no room, the HVA gets passed as normal indirect - // structure. - return getIndirectResult(Ty, /*ByVal=*/false, State); - } - return current; -} - ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State) const { // FIXME: Set alignment on indirect arguments. @@ -1575,35 +1553,20 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, } } - // vectorcall adds the concept of a homogenous vector aggregate, similar - // to other targets, regcall uses some of the HVA rules. + // Regcall uses the concept of a homogenous vector aggregate, similar + // to other targets. const Type *Base = nullptr; uint64_t NumElts = 0; - if ((State.CC == llvm::CallingConv::X86_VectorCall || - State.CC == llvm::CallingConv::X86_RegCall) && + if (State.CC == llvm::CallingConv::X86_RegCall && isHomogeneousAggregate(Ty, Base, NumElts)) { - if (State.CC == llvm::CallingConv::X86_RegCall) { - if (State.FreeSSERegs >= NumElts) { - State.FreeSSERegs -= NumElts; - if (Ty->isBuiltinType() || Ty->isVectorType()) - return ABIArgInfo::getDirect(); - return ABIArgInfo::getExpand(); - - } - return getIndirectResult(Ty, /*ByVal=*/false, State); - } else if (State.CC == llvm::CallingConv::X86_VectorCall) { - if (State.FreeSSERegs >= NumElts && (Ty->isBuiltinType() || Ty->isVectorType())) { - // Actual floating-point types get registers first time through if - // there is registers available - State.FreeSSERegs -= NumElts; + if (State.FreeSSERegs >= NumElts) { + State.FreeSSERegs -= NumElts; + if (Ty->isBuiltinType() || Ty->isVectorType()) return ABIArgInfo::getDirect(); - } else if (!Ty->isBuiltinType() && !Ty->isVectorType()) { - // HVA Types only get registers after everything else has been - // set, so it gets set as indirect for now. - return ABIArgInfo::getIndirect(getContext().getTypeAlignInChars(Ty)); - } + return ABIArgInfo::getExpand(); } + return getIndirectResult(Ty, /*ByVal=*/false, State); } if (isAggregateTypeForABI(Ty)) { @@ -1684,31 +1647,53 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, void X86_32ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, CCState &State, bool &UsedInAlloca) const { - // Vectorcall only allows the first 6 parameters to be passed in registers, - // and homogeneous vector aggregates are only put into registers as a second - // priority. - unsigned Count = 0; - CCState ZeroState = State; - ZeroState.FreeRegs = ZeroState.FreeSSERegs = 0; - // HVAs must be done as a second priority for registers, so the deferred - // items are dealt with by going through the pattern a second time. + // Vectorcall x86 works subtly different than in x64, so the format is + // a bit different than the x64 version. First, all vector types (not HVAs) + // are assigned, with the first 6 ending up in the YMM0-5 or XMM0-5 registers. + // This differs from the x64 implementation, where the first 6 by INDEX get + // registers. + // After that, integers AND HVAs are assigned Left to Right in the same pass. + // Integers are passed as ECX/EDX if one is available (in order). HVAs will + // first take up the remaining YMM/XMM registers. If insufficient registers + // remain but an integer register (ECX/EDX) is available, it will be passed + // in that, else, on the stack. for (auto &I : FI.arguments()) { - if (Count < VectorcallMaxParamNumAsReg) - I.info = classifyArgumentType(I.type, State); - else - // Parameters after the 6th cannot be passed in registers, - // so pretend there are no registers left for them. - I.info = classifyArgumentType(I.type, ZeroState); - UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca); - ++Count; + // First pass do all the vector types. + const Type *Base = nullptr; + uint64_t NumElts = 0; + const QualType& Ty = I.type; + if ((Ty->isVectorType() || Ty->isBuiltinType()) && + isHomogeneousAggregate(Ty, Base, NumElts)) { + if (State.FreeSSERegs >= NumElts) { + State.FreeSSERegs -= NumElts; + I.info = ABIArgInfo::getDirect(); + } else { + I.info = classifyArgumentType(Ty, State); + } + UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca); + } } - Count = 0; - // Go through the arguments a second time to get HVAs registers if there - // are still some available. + for (auto &I : FI.arguments()) { - if (Count < VectorcallMaxParamNumAsReg) - I.info = reclassifyHvaArgType(I.type, State, I.info); - ++Count; + // Second pass, do the rest! + const Type *Base = nullptr; + uint64_t NumElts = 0; + const QualType& Ty = I.type; + bool IsHva = isHomogeneousAggregate(Ty, Base, NumElts); + + if (IsHva && !Ty->isVectorType() && !Ty->isBuiltinType()) { + // Assign true HVAs (non vector/native FP types). + if (State.FreeSSERegs >= NumElts) { + State.FreeSSERegs -= NumElts; + I.info = getDirectX86Hva(); + } else { + I.info = getIndirectResult(Ty, /*ByVal=*/false, State); + } + } else if (!IsHva) { + // Assign all Non-HVAs, so this will exclude Vector/FP args. + I.info = classifyArgumentType(Ty, State); + UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca); + } } } @@ -3901,6 +3886,8 @@ void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, bool IsRegCall) const { unsigned Count = 0; for (auto &I : FI.arguments()) { + // Vectorcall in x64 only permits the first 6 arguments to be passed + // as XMM/YMM registers. if (Count < VectorcallMaxParamNumAsReg) I.info = classify(I.type, FreeSSERegs, false, IsVectorCall, IsRegCall); else { @@ -3913,11 +3900,8 @@ void WinX86_64ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, ++Count; } - Count = 0; for (auto &I : FI.arguments()) { - if (Count < VectorcallMaxParamNumAsReg) - I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info); - ++Count; + I.info = reclassifyHvaArgType(I.type, FreeSSERegs, I.info); } } @@ -7344,8 +7328,6 @@ class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo { }; } -static void appendOpenCLVersionMD (CodeGen::CodeGenModule &CGM); - void AMDGPUTargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, @@ -7402,8 +7384,6 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( if (NumVGPR != 0) F->addFnAttr("amdgpu-num-vgpr", llvm::utostr(NumVGPR)); } - - appendOpenCLVersionMD(M); } unsigned AMDGPUTargetCodeGenInfo::getOpenCLKernelCallingConv() const { @@ -8074,8 +8054,6 @@ class SPIRTargetCodeGenInfo : public TargetCodeGenInfo { public: SPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(new DefaultABIInfo(CGT)) {} - void emitTargetMD(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const override; unsigned getOpenCLKernelCallingConv() const override; }; @@ -8090,41 +8068,6 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { } } -/// Emit SPIR specific metadata: OpenCL and SPIR version. -void SPIRTargetCodeGenInfo::emitTargetMD(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &CGM) const { - llvm::LLVMContext &Ctx = CGM.getModule().getContext(); - llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx); - llvm::Module &M = CGM.getModule(); - // SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the - // opencl.spir.version named metadata. - llvm::Metadata *SPIRVerElts[] = { - llvm::ConstantAsMetadata::get( - llvm::ConstantInt::get(Int32Ty, CGM.getLangOpts().OpenCLVersion / 100)), - llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( - Int32Ty, (CGM.getLangOpts().OpenCLVersion / 100 > 1) ? 0 : 2))}; - llvm::NamedMDNode *SPIRVerMD = - M.getOrInsertNamedMetadata("opencl.spir.version"); - SPIRVerMD->addOperand(llvm::MDNode::get(Ctx, SPIRVerElts)); - appendOpenCLVersionMD(CGM); -} - -static void appendOpenCLVersionMD(CodeGen::CodeGenModule &CGM) { - llvm::LLVMContext &Ctx = CGM.getModule().getContext(); - llvm::Type *Int32Ty = llvm::Type::getInt32Ty(Ctx); - llvm::Module &M = CGM.getModule(); - // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the - // opencl.ocl.version named metadata node. - llvm::Metadata *OCLVerElts[] = { - llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( - Int32Ty, CGM.getLangOpts().OpenCLVersion / 100)), - llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( - Int32Ty, (CGM.getLangOpts().OpenCLVersion % 100) / 10))}; - llvm::NamedMDNode *OCLVerMD = - M.getOrInsertNamedMetadata("opencl.ocl.version"); - OCLVerMD->addOperand(llvm::MDNode::get(Ctx, OCLVerElts)); -} - unsigned SPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const { return llvm::CallingConv::SPIR_KERNEL; } diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index eb504fd4e541..f23975829eaf 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -11,6 +11,7 @@ #include "InputInfo.h" #include "ToolChains/AMDGPU.h" #include "ToolChains/AVR.h" +#include "ToolChains/Ananas.h" #include "ToolChains/Bitrig.h" #include "ToolChains/Clang.h" #include "ToolChains/CloudABI.h" @@ -1227,7 +1228,32 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { if (Arg *A = C.getArgs().getLastArg(options::OPT_autocomplete)) { // Print out all options that start with a given argument. This is used for // shell autocompletion. - llvm::outs() << llvm::join(Opts->findByPrefix(A->getValue()), " ") << '\n'; + StringRef PassedFlags = A->getValue(); + std::vector SuggestedCompletions; + + if (PassedFlags.find(',') == StringRef::npos) { + // If the flag is in the form of "--autocomplete=-foo", + // we were requested to print out all option names that start with "-foo". + // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". + SuggestedCompletions = Opts->findByPrefix(PassedFlags); + } else { + // If the flag is in the form of "--autocomplete=foo,bar", we were + // requested to print out all option values for "-foo" that start with + // "bar". For example, + // "--autocomplete=-stdlib=,l" is expanded to "libc++" and "libstdc++". + StringRef Option, Arg; + std::tie(Option, Arg) = PassedFlags.split(','); + SuggestedCompletions = Opts->suggestValueCompletions(Option, Arg); + } + + // Sort the autocomplete candidates so that shells print them out in a + // deterministic order. We could sort in any way, but we chose + // case-insensitive sorting for consistency with the -help option + // which prints out options in the case-insensitive alphabetical order. + std::sort(SuggestedCompletions.begin(), SuggestedCompletions.end(), + [](StringRef A, StringRef B) { return A.compare_lower(B) < 0; }); + + llvm::outs() << llvm::join(SuggestedCompletions, " ") << '\n'; return false; } @@ -3724,6 +3750,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::Haiku: TC = llvm::make_unique(*this, Target, Args); break; + case llvm::Triple::Ananas: + TC = llvm::make_unique(*this, Target, Args); + break; case llvm::Triple::CloudABI: TC = llvm::make_unique(*this, Target, Args); break; diff --git a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp index 6a7410901d25..ac63b96cf96d 100644 --- a/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/DriverOptions.cpp @@ -21,10 +21,10 @@ using namespace llvm::opt; #undef PREFIX static const OptTable::Info InfoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \ - FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + {PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES}, #include "clang/Driver/Options.inc" #undef OPTION }; diff --git a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp index d6a9c35eda78..3a30f2a289b0 100644 --- a/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/SanitizerArgs.cpp @@ -208,12 +208,28 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap; + // The object size sanitizer should not be enabled at -O0. + Arg *OptLevel = Args.getLastArg(options::OPT_O_Group); + bool RemoveObjectSizeAtO0 = + !OptLevel || OptLevel->getOption().matches(options::OPT_O0); + for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); I != E; ++I) { const auto *Arg = *I; if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { Arg->claim(); - SanitizerMask Add = parseArgValues(D, Arg, true); + SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true); + + if (RemoveObjectSizeAtO0) { + AllRemove |= SanitizerKind::ObjectSize; + + // The user explicitly enabled the object size sanitizer. Warn that + // that this does nothing at -O0. + if (Add & SanitizerKind::ObjectSize) + D.Diag(diag::warn_drv_object_size_disabled_O0) + << Arg->getAsString(Args); + } + AllAddedKinds |= expandSanitizerGroups(Add); // Avoid diagnosing any sanitizer which is disabled later. diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp new file mode 100644 index 000000000000..a67e1d2378f5 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.cpp @@ -0,0 +1,120 @@ +//===--- Ananas.cpp - Ananas ToolChain Implementations ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Ananas.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void ananas::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, Inputs)); +} + +void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const ToolChain &ToolChain = getToolChain(); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + // Ananas only supports static linkage for now. + CmdArgs.push_back("-Bstatic"); + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + Args.AddAllArgs(CmdArgs, + {options::OPT_T_Group, options::OPT_e, options::OPT_s, + options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + + if (D.isUsingLTO()) + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (D.CCCIsCXX()) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lc"); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, Inputs)); +} + +// Ananas - Ananas tool chain which can call as(1) and ld(1) directly. + +Ananas::Ananas(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); +} + +Tool *Ananas::buildAssembler() const { + return new tools::ananas::Assembler(*this); +} + +Tool *Ananas::buildLinker() const { return new tools::ananas::Linker(*this); } diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.h new file mode 100644 index 000000000000..2563dd2d49a9 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Ananas.h @@ -0,0 +1,67 @@ +//===--- Ananas.h - Ananas ToolChain Implementations --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// ananas -- Directly call GNU Binutils assembler and linker +namespace ananas { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: + Assembler(const ToolChain &TC) + : GnuTool("ananas::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("ananas::Linker", "linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace ananas +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Ananas : public Generic_ELF { +public: + Ananas(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ANANAS_H diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp index bd4e894d6504..292cf72b56ca 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Clang.cpp @@ -910,6 +910,37 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, } } +static void RenderDebugInfoCompressionArgs(const ArgList &Args, + ArgStringList &CmdArgs, + const Driver &D) { + const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ); + if (!A) + return; + + if (A->getOption().getID() == options::OPT_gz) { + if (llvm::zlib::isAvailable()) + CmdArgs.push_back("-compress-debug-sections"); + else + D.Diag(diag::warn_debug_compression_unavailable); + return; + } + + StringRef Value = A->getValue(); + if (Value == "none") { + CmdArgs.push_back("-compress-debug-sections=none"); + } else if (Value == "zlib" || Value == "zlib-gnu") { + if (llvm::zlib::isAvailable()) { + CmdArgs.push_back( + Args.MakeArgString("-compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::warn_debug_compression_unavailable); + } + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } +} + static const char *RelocationModelName(llvm::Reloc::Model Model) { switch (Model) { case llvm::Reloc::Static: @@ -1747,10 +1778,6 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, // arg after parsing the '-I' arg. bool TakeNextArg = false; - // When using an integrated assembler, translate -Wa, and -Xassembler - // options. - bool CompressDebugSections = false; - bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS; const char *MipsTargetFeature = nullptr; for (const Arg *A : @@ -1825,12 +1852,11 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, CmdArgs.push_back("-massembler-fatal-warnings"); } else if (Value == "--noexecstack") { CmdArgs.push_back("-mnoexecstack"); - } else if (Value == "-compress-debug-sections" || - Value == "--compress-debug-sections") { - CompressDebugSections = true; - } else if (Value == "-nocompress-debug-sections" || + } else if (Value.startswith("-compress-debug-sections") || + Value.startswith("--compress-debug-sections") || + Value == "-nocompress-debug-sections" || Value == "--nocompress-debug-sections") { - CompressDebugSections = false; + CmdArgs.push_back(Value.data()); } else if (Value == "-mrelax-relocations=yes" || Value == "--mrelax-relocations=yes") { UseRelaxRelocations = true; @@ -1883,12 +1909,6 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } } } - if (CompressDebugSections) { - if (llvm::zlib::isAvailable()) - CmdArgs.push_back("-compress-debug-sections"); - else - D.Diag(diag::warn_debug_compression_unavailable); - } if (UseRelaxRelocations) CmdArgs.push_back("--mrelax-relocations"); if (MipsTargetFeature != nullptr) { @@ -2824,6 +2844,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-generate-type-units"); } + RenderDebugInfoCompressionArgs(Args, CmdArgs, D); + bool UseSeparateSections = isUseSeparateSections(Triple); if (Args.hasFlag(options::OPT_ffunction_sections, @@ -4927,6 +4949,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const std::string &TripleStr = Triple.getTriple(); + const auto &D = getToolChain().getDriver(); // Don't warn about "clang -w -c foo.s" Args.ClaimAllArgs(options::OPT_w); @@ -5014,6 +5037,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, } RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, llvm::DebuggerKind::Default); + RenderDebugInfoCompressionArgs(Args, CmdArgs, D); + // Handle -fPIC et al -- the relocation-model affects the assembler // for some targets. diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp index d50f8e21f62f..bca5d3a3f28b 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/Gnu.cpp @@ -650,6 +650,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const auto &D = getToolChain().getDriver(); + claimNoWarnArgs(Args); ArgStringList CmdArgs; @@ -660,6 +662,23 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(getToolChain(), Args); + if (const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ)) { + if (A->getOption().getID() == options::OPT_gz) { + CmdArgs.push_back("-compress-debug-sections"); + } else { + StringRef Value = A->getValue(); + if (Value == "none") { + CmdArgs.push_back("-compress-debug-sections=none"); + } else if (Value == "zlib" || Value == "zlib-gnu") { + CmdArgs.push_back( + Args.MakeArgString("-compress-debug-sections=" + Twine(Value))); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + } + switch (getToolChain().getArch()) { default: break; @@ -2319,9 +2338,11 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const { return true; case llvm::Triple::mips64: case llvm::Triple::mips64el: - // Enabled for Debian mips64/mips64el only. Other targets are unable to - // distinguish N32 from N64. - if (getTriple().getEnvironment() == llvm::Triple::GNUABI64) + // Enabled for Debian and Android mips64/mipsel, as they can precisely + // identify the ABI in use (Debian) or only use N64 for MIPS64 (Android). + // Other targets are unable to distinguish N32 from N64. + if (getTriple().getEnvironment() == llvm::Triple::GNUABI64 || + getTriple().isAndroid()) return true; return false; default: diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp index 3471569b6884..fcb6418b2517 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -83,6 +83,8 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-allow-undefined-file"); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("wasm.syms"))); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lcompiler_rt"); } @@ -104,8 +106,7 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, getProgramPaths().push_back(getDriver().getInstalledDir()); - getFilePaths().push_back( - getDriver().SysRoot + "/lib" + (Triple.isArch32Bit() ? "32" : "64")); + getFilePaths().push_back(getDriver().SysRoot + "/lib"); } bool WebAssembly::IsMathErrnoDefault() const { return false; } diff --git a/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp index 03d45cf185c9..444d0393cccd 100644 --- a/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp +++ b/contrib/llvm/tools/clang/lib/Edit/EditedSource.cpp @@ -28,13 +28,18 @@ void EditedSource::deconstructMacroArgLoc(SourceLocation Loc, MacroArgUse &ArgUse) { assert(SourceMgr.isMacroArgExpansion(Loc)); SourceLocation DefArgLoc = SourceMgr.getImmediateExpansionRange(Loc).first; - ExpansionLoc = SourceMgr.getImmediateExpansionRange(DefArgLoc).first; + SourceLocation ImmediateExpansionLoc = + SourceMgr.getImmediateExpansionRange(DefArgLoc).first; + ExpansionLoc = ImmediateExpansionLoc; + while (SourceMgr.isMacroBodyExpansion(ExpansionLoc)) + ExpansionLoc = SourceMgr.getImmediateExpansionRange(ExpansionLoc).first; SmallString<20> Buf; StringRef ArgName = Lexer::getSpelling(SourceMgr.getSpellingLoc(DefArgLoc), Buf, SourceMgr, LangOpts); - ArgUse = {nullptr, SourceLocation()}; + ArgUse = MacroArgUse{nullptr, SourceLocation(), SourceLocation()}; if (!ArgName.empty()) - ArgUse = {&IdentTable.get(ArgName), SourceMgr.getSpellingLoc(DefArgLoc)}; + ArgUse = {&IdentTable.get(ArgName), ImmediateExpansionLoc, + SourceMgr.getSpellingLoc(DefArgLoc)}; } void EditedSource::startingCommit() {} @@ -69,10 +74,11 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) { deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse); auto I = ExpansionToArgMap.find(ExpLoc.getRawEncoding()); if (I != ExpansionToArgMap.end() && - std::find_if( - I->second.begin(), I->second.end(), [&](const MacroArgUse &U) { - return ArgUse.first == U.first && ArgUse.second != U.second; - }) != I->second.end()) { + find_if(I->second, [&](const MacroArgUse &U) { + return ArgUse.Identifier == U.Identifier && + std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) != + std::tie(U.ImmediateExpansionLoc, U.UseLoc); + }) != I->second.end()) { // Trying to write in a macro argument input that has already been // written by a previous commit for another expansion of the same macro // argument name. For example: @@ -89,7 +95,6 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) { return false; } } - return true; } @@ -102,13 +107,13 @@ bool EditedSource::commitInsert(SourceLocation OrigLoc, return true; if (SourceMgr.isMacroArgExpansion(OrigLoc)) { - SourceLocation ExpLoc; MacroArgUse ArgUse; + SourceLocation ExpLoc; deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse); - if (ArgUse.first) + if (ArgUse.Identifier) CurrCommitMacroArgExps.emplace_back(ExpLoc, ArgUse); } - + FileEdit &FA = FileEdits[Offs]; if (FA.Text.empty()) { FA.Text = copyString(text); diff --git a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp index 387923031f85..cca773cfe3cb 100644 --- a/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp +++ b/contrib/llvm/tools/clang/lib/Format/ContinuationIndenter.cpp @@ -453,7 +453,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, State.Column += Spaces; if (Current.isNot(tok::comment) && Previous.is(tok::l_paren) && Previous.Previous && - Previous.Previous->isOneOf(tok::kw_if, tok::kw_for)) { + (Previous.Previous->isOneOf(tok::kw_if, tok::kw_for) || + Previous.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) { // Treat the condition inside an if as if it was a second function // parameter, i.e. let nested calls have a continuation indent. State.Stack.back().LastSpace = State.Column; @@ -1049,7 +1050,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, (Current.is(TT_ArrayInitializerLSquare) && EndsInComma) || Current.is(TT_DictLiteral) || Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments || - (NextNoComment && NextNoComment->is(TT_DesignatedInitializerPeriod)); + (NextNoComment && + NextNoComment->isOneOf(TT_DesignatedInitializerPeriod, + TT_DesignatedInitializerLSquare)); if (Current.ParameterCount > 1) NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1); } else { diff --git a/contrib/llvm/tools/clang/lib/Format/Format.cpp b/contrib/llvm/tools/clang/lib/Format/Format.cpp index 39da87cf9988..7659d56adf25 100644 --- a/contrib/llvm/tools/clang/lib/Format/Format.cpp +++ b/contrib/llvm/tools/clang/lib/Format/Format.cpp @@ -23,6 +23,7 @@ #include "TokenAnnotator.h" #include "UnwrappedLineFormatter.h" #include "UnwrappedLineParser.h" +#include "UsingDeclarationsSorter.h" #include "WhitespaceManager.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" @@ -96,6 +97,7 @@ template <> struct ScalarEnumerationTraits { IO.enumCase(Value, "All", FormatStyle::SFS_All); IO.enumCase(Value, "true", FormatStyle::SFS_All); IO.enumCase(Value, "Inline", FormatStyle::SFS_Inline); + IO.enumCase(Value, "InlineOnly", FormatStyle::SFS_InlineOnly); IO.enumCase(Value, "Empty", FormatStyle::SFS_Empty); } }; @@ -377,6 +379,7 @@ template <> struct MappingTraits { IO.mapOptional("PointerAlignment", Style.PointerAlignment); IO.mapOptional("ReflowComments", Style.ReflowComments); IO.mapOptional("SortIncludes", Style.SortIncludes); + IO.mapOptional("SortUsingDeclarations", Style.SortUsingDeclarations); IO.mapOptional("SpaceAfterCStyleCast", Style.SpaceAfterCStyleCast); IO.mapOptional("SpaceAfterTemplateKeyword", Style.SpaceAfterTemplateKeyword); IO.mapOptional("SpaceBeforeAssignmentOperators", @@ -617,6 +620,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.DisableFormat = false; LLVMStyle.SortIncludes = true; + LLVMStyle.SortUsingDeclarations = true; return LLVMStyle; } @@ -771,6 +775,7 @@ FormatStyle getNoStyle() { FormatStyle NoStyle = getLLVMStyle(); NoStyle.DisableFormat = true; NoStyle.SortIncludes = false; + NoStyle.SortUsingDeclarations = false; return NoStyle; } @@ -1877,38 +1882,53 @@ tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, return tooling::Replacements(); if (Expanded.Language == FormatStyle::LK_JavaScript && isMpegTS(Code)) return tooling::Replacements(); - auto Env = Environment::CreateVirtualEnvironment(Code, FileName, Ranges); - auto reformatAfterApplying = [&] (TokenAnalyzer& Fixer) { - tooling::Replacements Fixes = Fixer.process(); - if (!Fixes.empty()) { - auto NewCode = applyAllReplacements(Code, Fixes); - if (NewCode) { - auto NewEnv = Environment::CreateVirtualEnvironment( - *NewCode, FileName, - tooling::calculateRangesAfterReplacements(Fixes, Ranges)); - Formatter Format(*NewEnv, Expanded, Status); - return Fixes.merge(Format.process()); - } - } - Formatter Format(*Env, Expanded, Status); - return Format.process(); - }; + typedef std::function + AnalyzerPass; + SmallVector Passes; - if (Style.Language == FormatStyle::LK_Cpp && - Style.FixNamespaceComments) { - NamespaceEndCommentsFixer CommentsFixer(*Env, Expanded); - return reformatAfterApplying(CommentsFixer); + if (Style.Language == FormatStyle::LK_Cpp) { + if (Style.FixNamespaceComments) + Passes.emplace_back([&](const Environment &Env) { + return NamespaceEndCommentsFixer(Env, Expanded).process(); + }); + + if (Style.SortUsingDeclarations) + Passes.emplace_back([&](const Environment &Env) { + return UsingDeclarationsSorter(Env, Expanded).process(); + }); } if (Style.Language == FormatStyle::LK_JavaScript && - Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) { - JavaScriptRequoter Requoter(*Env, Expanded); - return reformatAfterApplying(Requoter); + Style.JavaScriptQuotes != FormatStyle::JSQS_Leave) + Passes.emplace_back([&](const Environment &Env) { + return JavaScriptRequoter(Env, Expanded).process(); + }); + + Passes.emplace_back([&](const Environment &Env) { + return Formatter(Env, Expanded, Status).process(); + }); + + std::unique_ptr Env = + Environment::CreateVirtualEnvironment(Code, FileName, Ranges); + llvm::Optional CurrentCode = None; + tooling::Replacements Fixes; + for (size_t I = 0, E = Passes.size(); I < E; ++I) { + tooling::Replacements PassFixes = Passes[I](*Env); + auto NewCode = applyAllReplacements( + CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes); + if (NewCode) { + Fixes = Fixes.merge(PassFixes); + if (I + 1 < E) { + CurrentCode = std::move(*NewCode); + Env = Environment::CreateVirtualEnvironment( + *CurrentCode, FileName, + tooling::calculateRangesAfterReplacements(Fixes, Ranges)); + } + } } - Formatter Format(*Env, Expanded, Status); - return Format.process(); + return Fixes; } tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code, @@ -1943,6 +1963,16 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, return Fix.process(); } +tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, + StringRef Code, + ArrayRef Ranges, + StringRef FileName) { + std::unique_ptr Env = + Environment::CreateVirtualEnvironment(Code, FileName, Ranges); + UsingDeclarationsSorter Sorter(*Env, Style); + return Sorter.process(); +} + LangOptions getFormattingLangOpts(const FormatStyle &Style) { LangOptions LangOpts; LangOpts.CPlusPlus = 1; diff --git a/contrib/llvm/tools/clang/lib/Format/FormatToken.h b/contrib/llvm/tools/clang/lib/Format/FormatToken.h index 0c5a5284627c..c5bf48cdcc06 100644 --- a/contrib/llvm/tools/clang/lib/Format/FormatToken.h +++ b/contrib/llvm/tools/clang/lib/Format/FormatToken.h @@ -39,6 +39,7 @@ namespace format { TYPE(ConflictStart) \ TYPE(CtorInitializerColon) \ TYPE(CtorInitializerComma) \ + TYPE(DesignatedInitializerLSquare) \ TYPE(DesignatedInitializerPeriod) \ TYPE(DictLiteral) \ TYPE(ForEachMacro) \ diff --git a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp index 7ce699cf14a1..505f42ec9a06 100644 --- a/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp +++ b/contrib/llvm/tools/clang/lib/Format/TokenAnnotator.cpp @@ -145,6 +145,7 @@ class AnnotatingParser { (Left->Previous->isOneOf(tok::kw_static_assert, tok::kw_decltype, tok::kw_if, tok::kw_while, tok::l_paren, tok::comma) || + Left->Previous->endsSequence(tok::kw_constexpr, tok::kw_if) || Left->Previous->is(TT_BinaryOperator))) { // static_assert, if and while usually contain expressions. Contexts.back().IsExpression = true; @@ -339,6 +340,9 @@ class AnnotatingParser { Contexts.back().ContextKind == tok::l_brace && Parent->isOneOf(tok::l_brace, tok::comma)) { Left->Type = TT_JsComputedPropertyName; + } else if (Style.isCpp() && Contexts.back().ContextKind == tok::l_brace && + Parent && Parent->isOneOf(tok::l_brace, tok::comma)) { + Left->Type = TT_DesignatedInitializerLSquare; } else if (CurrentToken->is(tok::r_square) && Parent && Parent->is(TT_TemplateCloser)) { Left->Type = TT_ArraySubscriptLSquare; @@ -391,7 +395,8 @@ class AnnotatingParser { if (CurrentToken->isOneOf(tok::r_paren, tok::r_brace)) return false; if (CurrentToken->is(tok::colon)) { - if (Left->is(TT_ArraySubscriptLSquare)) { + if (Left->isOneOf(TT_ArraySubscriptLSquare, + TT_DesignatedInitializerLSquare)) { Left->Type = TT_ObjCMethodExpr; StartsObjCMethodExpr = true; Contexts.back().ColonIsObjCMethodExpr = true; @@ -572,6 +577,8 @@ class AnnotatingParser { break; case tok::kw_if: case tok::kw_while: + if (Tok->is(tok::kw_if) && CurrentToken && CurrentToken->is(tok::kw_constexpr)) + next(); if (CurrentToken && CurrentToken->is(tok::l_paren)) { next(); if (!parseParens(/*LookForDecls=*/true)) @@ -1972,7 +1979,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, if (Right.is(TT_LambdaLSquare) && Left.is(tok::equal)) return 35; if (!Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare, - TT_ArrayInitializerLSquare)) + TT_ArrayInitializerLSquare, + TT_DesignatedInitializerLSquare)) return 500; } @@ -2060,7 +2068,8 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, Style.AlignAfterOpenBracket != FormatStyle::BAS_DontAlign) return 100; if (Left.is(tok::l_paren) && Left.Previous && - Left.Previous->isOneOf(tok::kw_if, tok::kw_for)) + (Left.Previous->isOneOf(tok::kw_if, tok::kw_for) + || Left.Previous->endsSequence(tok::kw_constexpr, tok::kw_if))) return 1000; if (Left.is(tok::equal) && InFunctionDecl) return 110; @@ -2192,7 +2201,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, (Style.SpacesInSquareBrackets && Right.MatchingParen->is(TT_ArraySubscriptLSquare))); if (Right.is(tok::l_square) && - !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare) && + !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare, + TT_DesignatedInitializerLSquare) && !Left.isOneOf(tok::numeric_constant, TT_DictLiteral)) return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) @@ -2211,6 +2221,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, (Left.isOneOf(tok::kw_if, tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch, tok::kw_case, TT_ForEachMacro, TT_ObjCForIn) || + Left.endsSequence(tok::kw_constexpr, tok::kw_if) || (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch, tok::kw_new, tok::kw_delete) && (!Left.Previous || Left.Previous->isNot(tok::period))))) || @@ -2391,8 +2402,9 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Left.is(tok::greater) && Right.is(tok::greater)) return Right.is(TT_TemplateCloser) && Left.is(TT_TemplateCloser) && (Style.Standard != FormatStyle::LS_Cpp11 || Style.SpacesInAngles); - if (Right.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) || - Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar)) + if (Right.isOneOf(tok::arrow, tok::arrowstar, tok::periodstar) || + Left.isOneOf(tok::arrow, tok::period, tok::arrowstar, tok::periodstar) || + (Right.is(tok::period) && Right.isNot(TT_DesignatedInitializerPeriod))) return false; if (!Style.SpaceBeforeAssignmentOperators && Right.getPrecedence() == prec::Assignment) @@ -2468,8 +2480,8 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None || Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Empty || (Left.NestingLevel == 0 && Line.Level == 0 && - Style.AllowShortFunctionsOnASingleLine == - FormatStyle::SFS_Inline); + Style.AllowShortFunctionsOnASingleLine & + FormatStyle::SFS_InlineOnly); } else if (Style.Language == FormatStyle::LK_Java) { if (Right.is(tok::plus) && Left.is(tok::string_literal) && Right.Next && Right.Next->is(tok::string_literal)) diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp index 7f644651a6ab..8836c07cac71 100644 --- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -226,7 +226,7 @@ class LineJoiner { Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All || (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty && I[1]->First->is(tok::r_brace)) || - (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_Inline && + (Style.AllowShortFunctionsOnASingleLine & FormatStyle::SFS_InlineOnly && TheLine->Level != 0); if (Style.CompactNamespaces) { @@ -434,8 +434,11 @@ class LineJoiner { } else if (Limit != 0 && !Line.startsWith(tok::kw_namespace) && !startsExternCBlock(Line)) { // We don't merge short records. - if (Line.First->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct, - Keywords.kw_interface)) + FormatToken *RecordTok = + Line.First->is(tok::kw_typedef) ? Line.First->Next : Line.First; + if (RecordTok && + RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct, + Keywords.kw_interface)) return 0; // Check that we still have three lines and they fit into the limit. diff --git a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp index 27436dda67a7..f7678bb6b2a5 100644 --- a/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp +++ b/contrib/llvm/tools/clang/lib/Format/UnwrappedLineParser.cpp @@ -1516,6 +1516,8 @@ void UnwrappedLineParser::parseSquare() { void UnwrappedLineParser::parseIfThenElse() { assert(FormatTok->Tok.is(tok::kw_if) && "'if' expected"); nextToken(); + if (FormatTok->Tok.is(tok::kw_constexpr)) + nextToken(); if (FormatTok->Tok.is(tok::l_paren)) parseParens(); bool NeedsUnwrappedLine = false; diff --git a/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp new file mode 100644 index 000000000000..fb4f59fbc9bc --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.cpp @@ -0,0 +1,144 @@ +//===--- UsingDeclarationsSorter.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements UsingDeclarationsSorter, a TokenAnalyzer that +/// sorts consecutive using declarations. +/// +//===----------------------------------------------------------------------===// + +#include "UsingDeclarationsSorter.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Regex.h" + +#include + +#define DEBUG_TYPE "using-declarations-sorter" + +namespace clang { +namespace format { + +namespace { + +struct UsingDeclaration { + const AnnotatedLine *Line; + std::string Label; + + UsingDeclaration(const AnnotatedLine *Line, const std::string &Label) + : Line(Line), Label(Label) {} + + bool operator<(const UsingDeclaration &Other) const { + return Label < Other.Label; + } +}; + +/// Computes the label of a using declaration starting at tthe using token +/// \p UsingTok. +/// If \p UsingTok doesn't begin a using declaration, returns the empty string. +/// Note that this detects specifically using declarations, as in: +/// using A::B::C; +/// and not type aliases, as in: +/// using A = B::C; +/// Type aliases are in general not safe to permute. +std::string computeUsingDeclarationLabel(const FormatToken *UsingTok) { + assert(UsingTok && UsingTok->is(tok::kw_using) && "Expecting a using token"); + std::string Label; + const FormatToken *Tok = UsingTok->Next; + if (Tok && Tok->is(tok::kw_typename)) { + Label.append("typename "); + Tok = Tok->Next; + } + if (Tok && Tok->is(tok::coloncolon)) { + Label.append("::"); + Tok = Tok->Next; + } + bool HasIdentifier = false; + while (Tok && Tok->is(tok::identifier)) { + HasIdentifier = true; + Label.append(Tok->TokenText.str()); + Tok = Tok->Next; + if (!Tok || Tok->isNot(tok::coloncolon)) + break; + Label.append("::"); + Tok = Tok->Next; + } + if (HasIdentifier && Tok && Tok->isOneOf(tok::semi, tok::comma)) + return Label; + return ""; +} + +void endUsingDeclarationBlock( + SmallVectorImpl *UsingDeclarations, + const SourceManager &SourceMgr, tooling::Replacements *Fixes) { + SmallVector SortedUsingDeclarations( + UsingDeclarations->begin(), UsingDeclarations->end()); + std::sort(SortedUsingDeclarations.begin(), SortedUsingDeclarations.end()); + for (size_t I = 0, E = UsingDeclarations->size(); I < E; ++I) { + if ((*UsingDeclarations)[I].Line == SortedUsingDeclarations[I].Line) + continue; + auto Begin = (*UsingDeclarations)[I].Line->First->Tok.getLocation(); + auto End = (*UsingDeclarations)[I].Line->Last->Tok.getEndLoc(); + auto SortedBegin = + SortedUsingDeclarations[I].Line->First->Tok.getLocation(); + auto SortedEnd = SortedUsingDeclarations[I].Line->Last->Tok.getEndLoc(); + StringRef Text(SourceMgr.getCharacterData(SortedBegin), + SourceMgr.getCharacterData(SortedEnd) - + SourceMgr.getCharacterData(SortedBegin)); + DEBUG({ + StringRef OldText(SourceMgr.getCharacterData(Begin), + SourceMgr.getCharacterData(End) - + SourceMgr.getCharacterData(Begin)); + llvm::dbgs() << "Replacing '" << OldText << "' with '" << Text << "'\n"; + }); + auto Range = CharSourceRange::getCharRange(Begin, End); + auto Err = Fixes->add(tooling::Replacement(SourceMgr, Range, Text)); + if (Err) { + llvm::errs() << "Error while sorting using declarations: " + << llvm::toString(std::move(Err)) << "\n"; + } + } + UsingDeclarations->clear(); +} + +} // namespace + +UsingDeclarationsSorter::UsingDeclarationsSorter(const Environment &Env, + const FormatStyle &Style) + : TokenAnalyzer(Env, Style) {} + +tooling::Replacements UsingDeclarationsSorter::analyze( + TokenAnnotator &Annotator, SmallVectorImpl &AnnotatedLines, + FormatTokenLexer &Tokens) { + const SourceManager &SourceMgr = Env.getSourceManager(); + AffectedRangeMgr.computeAffectedLines(AnnotatedLines.begin(), + AnnotatedLines.end()); + tooling::Replacements Fixes; + SmallVector UsingDeclarations; + for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { + if (!AnnotatedLines[I]->Affected || AnnotatedLines[I]->InPPDirective || + !AnnotatedLines[I]->startsWith(tok::kw_using) || + AnnotatedLines[I]->First->Finalized) { + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + continue; + } + if (AnnotatedLines[I]->First->NewlinesBefore > 1) + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + std::string Label = computeUsingDeclarationLabel(AnnotatedLines[I]->First); + if (Label.empty()) { + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + continue; + } + UsingDeclarations.push_back(UsingDeclaration(AnnotatedLines[I], Label)); + } + endUsingDeclarationBlock(&UsingDeclarations, SourceMgr, &Fixes); + return Fixes; +} + +} // namespace format +} // namespace clang diff --git a/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h new file mode 100644 index 000000000000..f7d5f97e3a2a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Format/UsingDeclarationsSorter.h @@ -0,0 +1,37 @@ +//===--- UsingDeclarationsSorter.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file declares UsingDeclarationsSorter, a TokenAnalyzer that +/// sorts consecutive using declarations. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_FORMAT_USINGDECLARATIONSSORTER_H +#define LLVM_CLANG_LIB_FORMAT_USINGDECLARATIONSSORTER_H + +#include "TokenAnalyzer.h" + +namespace clang { +namespace format { + +class UsingDeclarationsSorter : public TokenAnalyzer { +public: + UsingDeclarationsSorter(const Environment &Env, const FormatStyle &Style); + + tooling::Replacements + analyze(TokenAnnotator &Annotator, + SmallVectorImpl &AnnotatedLines, + FormatTokenLexer &Tokens) override; +}; + +} // end namespace format +} // end namespace clang + +#endif diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp index 8d139f2c0a6d..1f34f10f55af 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -79,17 +79,6 @@ namespace { } } }; - - struct OnDiskData { - /// \brief The file in which the precompiled preamble is stored. - std::string PreambleFile; - - /// \brief Erase the preamble file. - void CleanPreambleFile(); - - /// \brief Erase temporary files and the preamble file. - void Cleanup(); - }; template std::unique_ptr valueOrNull(llvm::ErrorOr> Val) { @@ -105,81 +94,68 @@ namespace { Output = std::move(*Val); return true; } -} -static llvm::sys::SmartMutex &getOnDiskMutex() { - static llvm::sys::SmartMutex M(/* recursive = */ true); - return M; -} +/// \brief Get a source buffer for \p MainFilePath, handling all file-to-file +/// and file-to-buffer remappings inside \p Invocation. +static std::unique_ptr +getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation, + vfs::FileSystem *VFS, + StringRef FilePath) { + const auto &PreprocessorOpts = Invocation.getPreprocessorOpts(); -static void cleanupOnDiskMapAtExit(); + // Try to determine if the main file has been remapped, either from the + // command line (to another file) or directly through the compiler + // invocation (to a memory buffer). + llvm::MemoryBuffer *Buffer = nullptr; + std::unique_ptr BufferOwner; + auto FileStatus = VFS->status(FilePath); + if (FileStatus) { + llvm::sys::fs::UniqueID MainFileID = FileStatus->getUniqueID(); -typedef llvm::DenseMap> OnDiskDataMap; -static OnDiskDataMap &getOnDiskDataMap() { - static OnDiskDataMap M; - static bool hasRegisteredAtExit = false; - if (!hasRegisteredAtExit) { - hasRegisteredAtExit = true; - atexit(cleanupOnDiskMapAtExit); + // Check whether there is a file-file remapping of the main file + for (const auto &RF : PreprocessorOpts.RemappedFiles) { + std::string MPath(RF.first); + auto MPathStatus = VFS->status(MPath); + if (MPathStatus) { + llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID(); + if (MainFileID == MID) { + // We found a remapping. Try to load the resulting, remapped source. + BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second)); + if (!BufferOwner) + return nullptr; + } + } + } + + // Check whether there is a file-buffer remapping. It supercedes the + // file-file remapping. + for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { + std::string MPath(RB.first); + auto MPathStatus = VFS->status(MPath); + if (MPathStatus) { + llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID(); + if (MainFileID == MID) { + // We found a remapping. + BufferOwner.reset(); + Buffer = const_cast(RB.second); + } + } + } } - return M; -} -static void cleanupOnDiskMapAtExit() { - // Use the mutex because there can be an alive thread destroying an ASTUnit. - llvm::MutexGuard Guard(getOnDiskMutex()); - for (const auto &I : getOnDiskDataMap()) { - // We don't worry about freeing the memory associated with OnDiskDataMap. - // All we care about is erasing stale files. - I.second->Cleanup(); + // If the main source file was not remapped, load it now. + if (!Buffer && !BufferOwner) { + BufferOwner = valueOrNull(VFS->getBufferForFile(FilePath)); + if (!BufferOwner) + return nullptr; } -} -static OnDiskData &getOnDiskData(const ASTUnit *AU) { - // We require the mutex since we are modifying the structure of the - // DenseMap. - llvm::MutexGuard Guard(getOnDiskMutex()); - OnDiskDataMap &M = getOnDiskDataMap(); - auto &D = M[AU]; - if (!D) - D = llvm::make_unique(); - return *D; + if (BufferOwner) + return BufferOwner; + if (!Buffer) + return nullptr; + return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath); } - -static void erasePreambleFile(const ASTUnit *AU) { - getOnDiskData(AU).CleanPreambleFile(); -} - -static void removeOnDiskEntry(const ASTUnit *AU) { - // We require the mutex since we are modifying the structure of the - // DenseMap. - llvm::MutexGuard Guard(getOnDiskMutex()); - OnDiskDataMap &M = getOnDiskDataMap(); - OnDiskDataMap::iterator I = M.find(AU); - if (I != M.end()) { - I->second->Cleanup(); - M.erase(I); - } -} - -static void setPreambleFile(const ASTUnit *AU, StringRef preambleFile) { - getOnDiskData(AU).PreambleFile = preambleFile; -} - -static const std::string &getPreambleFile(const ASTUnit *AU) { - return getOnDiskData(AU).PreambleFile; -} - -void OnDiskData::CleanPreambleFile() { - if (!PreambleFile.empty()) { - llvm::sys::fs::remove(PreambleFile); - PreambleFile.clear(); - } -} - -void OnDiskData::Cleanup() { - CleanPreambleFile(); } struct ASTUnit::ASTWriterData { @@ -233,9 +209,6 @@ ASTUnit::~ASTUnit() { clearFileLevelDecls(); - // Clean up the temporary files and the preamble file. - removeOnDiskEntry(this); - // Free the buffers associated with remapped files. We are required to // perform this operation here because we explicitly request that the // compiler instance *not* free these buffers for each invocation of the @@ -575,16 +548,24 @@ class ASTInfoCollector : public ASTReaderListener { /// \brief Diagnostic consumer that saves each diagnostic it is given. class StoredDiagnosticConsumer : public DiagnosticConsumer { - SmallVectorImpl &StoredDiags; + SmallVectorImpl *StoredDiags; + SmallVectorImpl *StandaloneDiags; + const LangOptions *LangOpts; SourceManager *SourceMgr; public: - explicit StoredDiagnosticConsumer( - SmallVectorImpl &StoredDiags) - : StoredDiags(StoredDiags), SourceMgr(nullptr) {} + StoredDiagnosticConsumer( + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags) + : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), + LangOpts(nullptr), SourceMgr(nullptr) { + assert((StoredDiags || StandaloneDiags) && + "No output collections were passed to StoredDiagnosticConsumer."); + } void BeginSourceFile(const LangOptions &LangOpts, const Preprocessor *PP = nullptr) override { + this->LangOpts = &LangOpts; if (PP) SourceMgr = &PP->getSourceManager(); } @@ -603,8 +584,9 @@ class CaptureDroppedDiagnostics { public: CaptureDroppedDiagnostics(bool RequestCapture, DiagnosticsEngine &Diags, - SmallVectorImpl &StoredDiags) - : Diags(Diags), Client(StoredDiags), PreviousClient(nullptr) + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags) + : Diags(Diags), Client(StoredDiags, StandaloneDiags), PreviousClient(nullptr) { if (RequestCapture || Diags.getClient() == nullptr) { OwningPreviousClient = Diags.takeClient(); @@ -621,16 +603,35 @@ class CaptureDroppedDiagnostics { } // anonymous namespace +static ASTUnit::StandaloneDiagnostic +makeStandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag); + void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, - const Diagnostic &Info) { + const Diagnostic &Info) { // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); // Only record the diagnostic if it's part of the source manager we know // about. This effectively drops diagnostics from modules we're building. // FIXME: In the long run, ee don't want to drop source managers from modules. - if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) - StoredDiags.emplace_back(Level, Info); + if (!Info.hasSourceManager() || &Info.getSourceManager() == SourceMgr) { + StoredDiagnostic *ResultDiag = nullptr; + if (StoredDiags) { + StoredDiags->emplace_back(Level, Info); + ResultDiag = &StoredDiags->back(); + } + + if (StandaloneDiags) { + llvm::Optional StoredDiag = llvm::None; + if (!ResultDiag) { + StoredDiag.emplace(Level, Info); + ResultDiag = StoredDiag.getPointer(); + } + StandaloneDiags->push_back( + makeStandaloneDiagnostic(*LangOpts, *ResultDiag)); + } + } } IntrusiveRefCntPtr ASTUnit::getASTReader() const { @@ -665,7 +666,7 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr Diags, ASTUnit &AST, bool CaptureDiagnostics) { assert(Diags.get() && "no DiagnosticsEngine was provided"); if (CaptureDiagnostics) - Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics)); + Diags->setClient(new StoredDiagnosticConsumer(&AST.StoredDiagnostics, nullptr)); } std::unique_ptr ASTUnit::LoadFromASTFile( @@ -780,6 +781,11 @@ std::unique_ptr ASTUnit::LoadFromASTFile( namespace { +/// \brief Add the given macro to the hash of all top-level entities. +void AddDefinedMacroToHash(const Token &MacroNameTok, unsigned &Hash) { + Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash); +} + /// \brief Preprocessor callback class that updates a hash value with the names /// of all macros that have been defined by the translation unit. class MacroDefinitionTrackerPPCallbacks : public PPCallbacks { @@ -790,7 +796,7 @@ class MacroDefinitionTrackerPPCallbacks : public PPCallbacks { void MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) override { - Hash = llvm::HashString(MacroNameTok.getIdentifierInfo()->getName(), Hash); + AddDefinedMacroToHash(MacroNameTok, Hash); } }; @@ -916,45 +922,27 @@ class TopLevelDeclTrackerAction : public ASTFrontendAction { } }; -class PrecompilePreambleAction : public ASTFrontendAction { - ASTUnit &Unit; - bool HasEmittedPreamblePCH; - +class ASTUnitPreambleCallbacks : public PreambleCallbacks { public: - explicit PrecompilePreambleAction(ASTUnit &Unit) - : Unit(Unit), HasEmittedPreamblePCH(false) {} + unsigned getHash() const { return Hash; } - std::unique_ptr CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) override; - bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; } - void setHasEmittedPreamblePCH() { HasEmittedPreamblePCH = true; } - bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); } + std::vector takeTopLevelDecls() { return std::move(TopLevelDecls); } - bool hasCodeCompletionSupport() const override { return false; } - bool hasASTFileSupport() const override { return false; } - TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; } -}; - -class PrecompilePreambleConsumer : public PCHGenerator { - ASTUnit &Unit; - unsigned &Hash; - std::vector TopLevelDecls; - PrecompilePreambleAction *Action; - std::unique_ptr Out; - -public: - PrecompilePreambleConsumer(ASTUnit &Unit, PrecompilePreambleAction *Action, - const Preprocessor &PP, StringRef isysroot, - std::unique_ptr Out) - : PCHGenerator(PP, "", isysroot, std::make_shared(), - ArrayRef>(), - /*AllowASTWithErrors=*/true), - Unit(Unit), Hash(Unit.getCurrentTopLevelHashValue()), Action(Action), - Out(std::move(Out)) { - Hash = 0; + std::vector takeTopLevelDeclIDs() { + return std::move(TopLevelDeclIDs); } - bool HandleTopLevelDecl(DeclGroupRef DG) override { + void AfterPCHEmitted(ASTWriter &Writer) override { + TopLevelDeclIDs.reserve(TopLevelDecls.size()); + for (Decl *D : TopLevelDecls) { + // Invalid top-level decls may not have been serialized. + if (D->isInvalidDecl()) + continue; + TopLevelDeclIDs.push_back(Writer.getDeclID(D)); + } + } + + void HandleTopLevelDecl(DeclGroupRef DG) override { for (Decl *D : DG) { // FIXME: Currently ObjC method declarations are incorrectly being // reported as top-level declarations, even though their DeclContext @@ -965,59 +953,22 @@ class PrecompilePreambleConsumer : public PCHGenerator { AddTopLevelDeclarationToHash(D, Hash); TopLevelDecls.push_back(D); } - return true; } - void HandleTranslationUnit(ASTContext &Ctx) override { - PCHGenerator::HandleTranslationUnit(Ctx); - if (hasEmittedPCH()) { - // Write the generated bitstream to "Out". - *Out << getPCH(); - // Make sure it hits disk now. - Out->flush(); - // Free the buffer. - llvm::SmallVector Empty; - getPCH() = std::move(Empty); - - // Translate the top-level declarations we captured during - // parsing into declaration IDs in the precompiled - // preamble. This will allow us to deserialize those top-level - // declarations when requested. - for (Decl *D : TopLevelDecls) { - // Invalid top-level decls may not have been serialized. - if (D->isInvalidDecl()) - continue; - Unit.addTopLevelDeclFromPreamble(getWriter().getDeclID(D)); - } - - Action->setHasEmittedPreamblePCH(); - } + void HandleMacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + AddDefinedMacroToHash(MacroNameTok, Hash); } + +private: + unsigned Hash = 0; + std::vector TopLevelDecls; + std::vector TopLevelDeclIDs; + llvm::SmallVector PreambleDiags; }; } // anonymous namespace -std::unique_ptr -PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { - std::string Sysroot; - std::string OutputFile; - std::unique_ptr OS = - GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, - OutputFile); - if (!OS) - return nullptr; - - if (!CI.getFrontendOpts().RelocatablePCH) - Sysroot.clear(); - - CI.getPreprocessor().addPPCallbacks( - llvm::make_unique( - Unit.getCurrentTopLevelHashValue())); - return llvm::make_unique( - Unit, this, CI.getPreprocessor(), Sysroot, std::move(OS)); -} - static bool isNonDriverDiag(const StoredDiagnostic &StoredDiag) { return StoredDiag.getLocation().isValid(); } @@ -1125,15 +1076,9 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. - PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); if (OverrideMainBuffer) { - PreprocessorOpts.addRemappedFile(OriginalSourceFile, - OverrideMainBuffer.get()); - PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); - PreprocessorOpts.PrecompiledPreambleBytes.second - = PreambleEndsAtStartOfLine; - PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this); - PreprocessorOpts.DisablePCHValidation = true; + assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null"); + Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get()); // The stored diagnostic has the old source manager in it; update // the locations to refer into the new source manager. Since we've @@ -1186,116 +1131,6 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, return true; } -/// \brief Simple function to retrieve a path for a preamble precompiled header. -static std::string GetPreamblePCHPath() { - // FIXME: This is a hack so that we can override the preamble file during - // crash-recovery testing, which is the only case where the preamble files - // are not necessarily cleaned up. - const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); - if (TmpFile) - return TmpFile; - - SmallString<128> Path; - llvm::sys::fs::createTemporaryFile("preamble", "pch", Path); - - return Path.str(); -} - -/// \brief Compute the preamble for the main file, providing the source buffer -/// that corresponds to the main file along with a pair (bytes, start-of-line) -/// that describes the preamble. -ASTUnit::ComputedPreamble -ASTUnit::ComputePreamble(CompilerInvocation &Invocation, unsigned MaxLines, - IntrusiveRefCntPtr VFS) { - FrontendOptions &FrontendOpts = Invocation.getFrontendOpts(); - PreprocessorOptions &PreprocessorOpts = Invocation.getPreprocessorOpts(); - - // Try to determine if the main file has been remapped, either from the - // command line (to another file) or directly through the compiler invocation - // (to a memory buffer). - llvm::MemoryBuffer *Buffer = nullptr; - std::unique_ptr BufferOwner; - std::string MainFilePath(FrontendOpts.Inputs[0].getFile()); - auto MainFileStatus = VFS->status(MainFilePath); - if (MainFileStatus) { - llvm::sys::fs::UniqueID MainFileID = MainFileStatus->getUniqueID(); - - // Check whether there is a file-file remapping of the main file - for (const auto &RF : PreprocessorOpts.RemappedFiles) { - std::string MPath(RF.first); - auto MPathStatus = VFS->status(MPath); - if (MPathStatus) { - llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID(); - if (MainFileID == MID) { - // We found a remapping. Try to load the resulting, remapped source. - BufferOwner = valueOrNull(VFS->getBufferForFile(RF.second)); - if (!BufferOwner) - return ComputedPreamble(nullptr, nullptr, 0, true); - } - } - } - - // Check whether there is a file-buffer remapping. It supercedes the - // file-file remapping. - for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { - std::string MPath(RB.first); - auto MPathStatus = VFS->status(MPath); - if (MPathStatus) { - llvm::sys::fs::UniqueID MID = MPathStatus->getUniqueID(); - if (MainFileID == MID) { - // We found a remapping. - BufferOwner.reset(); - Buffer = const_cast(RB.second); - } - } - } - } - - // If the main source file was not remapped, load it now. - if (!Buffer && !BufferOwner) { - BufferOwner = valueOrNull(VFS->getBufferForFile(FrontendOpts.Inputs[0].getFile())); - if (!BufferOwner) - return ComputedPreamble(nullptr, nullptr, 0, true); - } - - if (!Buffer) - Buffer = BufferOwner.get(); - auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), - *Invocation.getLangOpts(), MaxLines); - return ComputedPreamble(Buffer, std::move(BufferOwner), Pre.first, - Pre.second); -} - -ASTUnit::PreambleFileHash -ASTUnit::PreambleFileHash::createForFile(off_t Size, time_t ModTime) { - PreambleFileHash Result; - Result.Size = Size; - Result.ModTime = ModTime; - Result.MD5 = {}; - return Result; -} - -ASTUnit::PreambleFileHash ASTUnit::PreambleFileHash::createForMemoryBuffer( - const llvm::MemoryBuffer *Buffer) { - PreambleFileHash Result; - Result.Size = Buffer->getBufferSize(); - Result.ModTime = 0; - - llvm::MD5 MD5Ctx; - MD5Ctx.update(Buffer->getBuffer().data()); - MD5Ctx.final(Result.MD5); - - return Result; -} - -namespace clang { -bool operator==(const ASTUnit::PreambleFileHash &LHS, - const ASTUnit::PreambleFileHash &RHS) { - return LHS.Size == RHS.Size && LHS.ModTime == RHS.ModTime && - LHS.MD5 == RHS.MD5; -} -} // namespace clang - static std::pair makeStandaloneRange(CharSourceRange Range, const SourceManager &SM, const LangOptions &LangOpts) { @@ -1367,135 +1202,41 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( const CompilerInvocation &PreambleInvocationIn, IntrusiveRefCntPtr VFS, bool AllowRebuild, unsigned MaxLines) { - assert(VFS && "VFS is null"); - auto PreambleInvocation = - std::make_shared(PreambleInvocationIn); - FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts(); - PreprocessorOptions &PreprocessorOpts - = PreambleInvocation->getPreprocessorOpts(); - - ComputedPreamble NewPreamble = - ComputePreamble(*PreambleInvocation, MaxLines, VFS); - - if (!NewPreamble.Size) { - // We couldn't find a preamble in the main source. Clear out the current - // preamble, if we have one. It's obviously no good any more. - Preamble.clear(); - erasePreambleFile(this); - - // The next time we actually see a preamble, precompile it. - PreambleRebuildCounter = 1; + auto MainFilePath = + PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile(); + std::unique_ptr MainFileBuffer = + getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(), + MainFilePath); + if (!MainFileBuffer) return nullptr; - } - - if (!Preamble.empty()) { - // We've previously computed a preamble. Check whether we have the same - // preamble now that we did before, and that there's enough space in - // the main-file buffer within the precompiled preamble to fit the - // new main file. - if (Preamble.size() == NewPreamble.Size && - PreambleEndsAtStartOfLine == NewPreamble.PreambleEndsAtStartOfLine && - memcmp(Preamble.getBufferStart(), NewPreamble.Buffer->getBufferStart(), - NewPreamble.Size) == 0) { - // The preamble has not changed. We may be able to re-use the precompiled - // preamble. - // Check that none of the files used by the preamble have changed. - bool AnyFileChanged = false; - - // First, make a record of those files that have been overridden via - // remapping or unsaved_files. - std::map OverriddenFiles; - for (const auto &R : PreprocessorOpts.RemappedFiles) { - if (AnyFileChanged) - break; + PreambleBounds Bounds = + ComputePreambleBounds(*PreambleInvocationIn.getLangOpts(), + MainFileBuffer.get(), MaxLines); + if (!Bounds.Size) + return nullptr; - vfs::Status Status; - if (!moveOnNoError(VFS->status(R.second), Status)) { - // If we can't stat the file we're remapping to, assume that something - // horrible happened. - AnyFileChanged = true; - break; - } + if (Preamble) { + if (Preamble->CanReuse(PreambleInvocationIn, MainFileBuffer.get(), Bounds, + VFS.get())) { + // Okay! We can re-use the precompiled preamble. - OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile( - Status.getSize(), - llvm::sys::toTimeT(Status.getLastModificationTime())); - } + // Set the state of the diagnostic object to mimic its state + // after parsing the preamble. + getDiagnostics().Reset(); + ProcessWarningOptions(getDiagnostics(), + PreambleInvocationIn.getDiagnosticOpts()); + getDiagnostics().setNumWarnings(NumWarningsInPreamble); - for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { - if (AnyFileChanged) - break; - - vfs::Status Status; - if (!moveOnNoError(VFS->status(RB.first), Status)) { - AnyFileChanged = true; - break; - } - - OverriddenFiles[Status.getUniqueID()] = - PreambleFileHash::createForMemoryBuffer(RB.second); - } - - // Check whether anything has changed. - for (llvm::StringMap::iterator - F = FilesInPreamble.begin(), FEnd = FilesInPreamble.end(); - !AnyFileChanged && F != FEnd; - ++F) { - vfs::Status Status; - if (!moveOnNoError(VFS->status(F->first()), Status)) { - // If we can't stat the file, assume that something horrible happened. - AnyFileChanged = true; - break; - } - - std::map::iterator Overridden - = OverriddenFiles.find(Status.getUniqueID()); - if (Overridden != OverriddenFiles.end()) { - // This file was remapped; check whether the newly-mapped file - // matches up with the previous mapping. - if (Overridden->second != F->second) - AnyFileChanged = true; - continue; - } - - // The file was not remapped; check whether it has changed on disk. - if (Status.getSize() != uint64_t(F->second.Size) || - llvm::sys::toTimeT(Status.getLastModificationTime()) != - F->second.ModTime) - AnyFileChanged = true; - } - - if (!AnyFileChanged) { - // Okay! We can re-use the precompiled preamble. - - // Set the state of the diagnostic object to mimic its state - // after parsing the preamble. - getDiagnostics().Reset(); - ProcessWarningOptions(getDiagnostics(), - PreambleInvocation->getDiagnosticOpts()); - getDiagnostics().setNumWarnings(NumWarningsInPreamble); - - return llvm::MemoryBuffer::getMemBufferCopy( - NewPreamble.Buffer->getBuffer(), FrontendOpts.Inputs[0].getFile()); - } + PreambleRebuildCounter = 1; + return MainFileBuffer; + } else { + Preamble.reset(); + PreambleDiagnostics.clear(); + TopLevelDeclsInPreamble.clear(); + PreambleRebuildCounter = 1; } - - // If we aren't allowed to rebuild the precompiled preamble, just - // return now. - if (!AllowRebuild) - return nullptr; - - // We can't reuse the previously-computed preamble. Build a new one. - Preamble.clear(); - PreambleDiagnostics.clear(); - erasePreambleFile(this); - PreambleRebuildCounter = 1; - } else if (!AllowRebuild) { - // We aren't allowed to rebuild the precompiled preamble; just - // return now. - return nullptr; } // If the preamble rebuild counter > 1, it's because we previously @@ -1506,164 +1247,61 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( return nullptr; } - // Create a temporary file for the precompiled preamble. In rare - // circumstances, this can fail. - std::string PreamblePCHPath = GetPreamblePCHPath(); - if (PreamblePCHPath.empty()) { - // Try again next time. - PreambleRebuildCounter = 1; - return nullptr; - } - - // We did not previously compute a preamble, or it can't be reused anyway. - SimpleTimer PreambleTimer(WantTiming); - PreambleTimer.setOutput("Precompiling preamble"); - - // Save the preamble text for later; we'll need to compare against it for - // subsequent reparses. - StringRef MainFilename = FrontendOpts.Inputs[0].getFile(); - Preamble.assign(FileMgr->getFile(MainFilename), - NewPreamble.Buffer->getBufferStart(), - NewPreamble.Buffer->getBufferStart() + NewPreamble.Size); - PreambleEndsAtStartOfLine = NewPreamble.PreambleEndsAtStartOfLine; - - PreambleBuffer = llvm::MemoryBuffer::getMemBufferCopy( - NewPreamble.Buffer->getBuffer().slice(0, Preamble.size()), MainFilename); - - // Remap the main source file to the preamble buffer. - StringRef MainFilePath = FrontendOpts.Inputs[0].getFile(); - PreprocessorOpts.addRemappedFile(MainFilePath, PreambleBuffer.get()); - - // Tell the compiler invocation to generate a temporary precompiled header. - FrontendOpts.ProgramAction = frontend::GeneratePCH; - // FIXME: Generate the precompiled header into memory? - FrontendOpts.OutputFile = PreamblePCHPath; - PreprocessorOpts.PrecompiledPreambleBytes.first = 0; - PreprocessorOpts.PrecompiledPreambleBytes.second = false; - - // Create the compiler instance to use for building the precompiled preamble. - std::unique_ptr Clang( - new CompilerInstance(std::move(PCHContainerOps))); - - // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar - CICleanup(Clang.get()); - - Clang->setInvocation(std::move(PreambleInvocation)); - OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); - - // Set up diagnostics, capturing all of the diagnostics produced. - Clang->setDiagnostics(&getDiagnostics()); - - // Create the target instance. - Clang->setTarget(TargetInfo::CreateTargetInfo( - Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); - if (!Clang->hasTarget()) { - llvm::sys::fs::remove(FrontendOpts.OutputFile); - Preamble.clear(); - PreambleRebuildCounter = DefaultPreambleRebuildInterval; - PreprocessorOpts.RemappedFileBuffers.pop_back(); - return nullptr; - } - - // Inform the target of the language options. - // - // FIXME: We shouldn't need to do this, the target should be immutable once - // created. This complexity should be lifted elsewhere. - Clang->getTarget().adjust(Clang->getLangOpts()); - - assert(Clang->getFrontendOpts().Inputs.size() == 1 && - "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == - InputKind::Source && - "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != - InputKind::LLVM_IR && - "IR inputs not support here!"); - - // Clear out old caches and data. - getDiagnostics().Reset(); - ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts()); - checkAndRemoveNonDriverDiags(StoredDiagnostics); - TopLevelDecls.clear(); - TopLevelDeclsInPreamble.clear(); - PreambleDiagnostics.clear(); - - VFS = createVFSFromCompilerInvocation(Clang->getInvocation(), - getDiagnostics(), VFS); - if (!VFS) + assert(!Preamble && "No Preamble should be stored at that point"); + // If we aren't allowed to rebuild the precompiled preamble, just + // return now. + if (!AllowRebuild) return nullptr; - // Create a file manager object to provide access to and cache the filesystem. - Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); + SmallVector NewPreambleDiagsStandalone; + SmallVector NewPreambleDiags; + ASTUnitPreambleCallbacks Callbacks; + { + llvm::Optional Capture; + if (CaptureDiagnostics) + Capture.emplace(/*RequestCapture=*/true, *Diagnostics, &NewPreambleDiags, + &NewPreambleDiagsStandalone); - // Create the source manager. - Clang->setSourceManager(new SourceManager(getDiagnostics(), - Clang->getFileManager())); + // We did not previously compute a preamble, or it can't be reused anyway. + SimpleTimer PreambleTimer(WantTiming); + PreambleTimer.setOutput("Precompiling preamble"); - auto PreambleDepCollector = std::make_shared(); - Clang->addDependencyCollector(PreambleDepCollector); - - std::unique_ptr Act; - Act.reset(new PrecompilePreambleAction(*this)); - if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) { - llvm::sys::fs::remove(FrontendOpts.OutputFile); - Preamble.clear(); - PreambleRebuildCounter = DefaultPreambleRebuildInterval; - PreprocessorOpts.RemappedFileBuffers.pop_back(); - return nullptr; - } - - Act->Execute(); - - // Transfer any diagnostics generated when parsing the preamble into the set - // of preamble diagnostics. - for (stored_diag_iterator I = stored_diag_afterDriver_begin(), - E = stored_diag_end(); - I != E; ++I) - PreambleDiagnostics.push_back( - makeStandaloneDiagnostic(Clang->getLangOpts(), *I)); - - Act->EndSourceFile(); - - checkAndRemoveNonDriverDiags(StoredDiagnostics); - - if (!Act->hasEmittedPreamblePCH()) { - // The preamble PCH failed (e.g. there was a module loading fatal error), - // so no precompiled header was generated. Forget that we even tried. - // FIXME: Should we leave a note for ourselves to try again? - llvm::sys::fs::remove(FrontendOpts.OutputFile); - Preamble.clear(); - TopLevelDeclsInPreamble.clear(); - PreambleRebuildCounter = DefaultPreambleRebuildInterval; - PreprocessorOpts.RemappedFileBuffers.pop_back(); - return nullptr; - } - - // Keep track of the preamble we precompiled. - setPreambleFile(this, FrontendOpts.OutputFile); - NumWarningsInPreamble = getDiagnostics().getNumWarnings(); - - // Keep track of all of the files that the source manager knows about, - // so we can verify whether they have changed or not. - FilesInPreamble.clear(); - SourceManager &SourceMgr = Clang->getSourceManager(); - for (auto &Filename : PreambleDepCollector->getDependencies()) { - const FileEntry *File = Clang->getFileManager().getFile(Filename); - if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())) - continue; - if (time_t ModTime = File->getModificationTime()) { - FilesInPreamble[File->getName()] = PreambleFileHash::createForFile( - File->getSize(), ModTime); + llvm::ErrorOr NewPreamble = PrecompiledPreamble::Build( + PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS, + PCHContainerOps, Callbacks); + if (NewPreamble) { + Preamble = std::move(*NewPreamble); + PreambleRebuildCounter = 1; } else { - llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); - FilesInPreamble[File->getName()] = - PreambleFileHash::createForMemoryBuffer(Buffer); + switch (static_cast(NewPreamble.getError().value())) { + case BuildPreambleError::CouldntCreateTempFile: + case BuildPreambleError::PreambleIsEmpty: + // Try again next time. + PreambleRebuildCounter = 1; + return nullptr; + case BuildPreambleError::CouldntCreateTargetInfo: + case BuildPreambleError::BeginSourceFileFailed: + case BuildPreambleError::CouldntEmitPCH: + case BuildPreambleError::CouldntCreateVFSOverlay: + // These erros are more likely to repeat, retry after some period. + PreambleRebuildCounter = DefaultPreambleRebuildInterval; + return nullptr; + } + llvm_unreachable("unexpected BuildPreambleError"); } } - PreambleRebuildCounter = 1; - PreprocessorOpts.RemappedFileBuffers.pop_back(); + assert(Preamble && "Preamble wasn't built"); + + TopLevelDecls.clear(); + TopLevelDeclsInPreamble = Callbacks.takeTopLevelDeclIDs(); + PreambleTopLevelHashValue = Callbacks.getHash(); + + NumWarningsInPreamble = getDiagnostics().getNumWarnings(); + + checkAndRemoveNonDriverDiags(NewPreambleDiags); + StoredDiagnostics = std::move(NewPreambleDiags); + PreambleDiagnostics = std::move(NewPreambleDiagsStandalone); // If the hash of top-level entities differs from the hash of the top-level // entities the last time we rebuilt the preamble, clear out the completion @@ -1673,11 +1311,12 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( PreambleTopLevelHashValue = CurrentTopLevelHashValue; } - return llvm::MemoryBuffer::getMemBufferCopy(NewPreamble.Buffer->getBuffer(), - MainFilename); + return MainFileBuffer; } void ASTUnit::RealizeTopLevelDeclsFromPreamble() { + assert(Preamble && "Should only be called when preamble was built"); + std::vector Resolved; Resolved.reserve(TopLevelDeclsInPreamble.size()); ExternalASTSource &Source = *getASTContext().getExternalSource(); @@ -1995,8 +1634,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine( { - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, - StoredDiagnostics); + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, + &StoredDiagnostics, nullptr); CI = clang::createInvocationFromCommandLine( llvm::makeArrayRef(ArgBegin, ArgEnd), Diags); @@ -2101,7 +1740,7 @@ bool ASTUnit::Reparse(std::shared_ptr PCHContainerOps, // If we have a preamble file lying around, or if we might try to // build a precompiled preamble, do so now. std::unique_ptr OverrideMainBuffer; - if (!getPreambleFile(this).empty() || PreambleRebuildCounter > 0) + if (Preamble || PreambleRebuildCounter > 0) OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS); @@ -2435,7 +2074,7 @@ void ASTUnit::CodeComplete( Clang->setDiagnostics(&Diag); CaptureDroppedDiagnostics Capture(true, Clang->getDiagnostics(), - StoredDiagnostics); + &StoredDiagnostics, nullptr); ProcessWarningOptions(Diag, Inv.getDiagnosticOpts()); // Create the target instance. @@ -2484,7 +2123,7 @@ void ASTUnit::CodeComplete( // point is within the main file, after the end of the precompiled // preamble. std::unique_ptr OverrideMainBuffer; - if (!getPreambleFile(this).empty()) { + if (Preamble) { std::string CompleteFilePath(File); auto VFS = FileMgr.getVirtualFileSystem(); @@ -2506,14 +2145,8 @@ void ASTUnit::CodeComplete( // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. if (OverrideMainBuffer) { - PreprocessorOpts.addRemappedFile(OriginalSourceFile, - OverrideMainBuffer.get()); - PreprocessorOpts.PrecompiledPreambleBytes.first = Preamble.size(); - PreprocessorOpts.PrecompiledPreambleBytes.second - = PreambleEndsAtStartOfLine; - PreprocessorOpts.ImplicitPCHInclude = getPreambleFile(this); - PreprocessorOpts.DisablePCHValidation = true; - + assert(Preamble && "No preamble was built, but OverrideMainBuffer is not null"); + Preamble->AddImplicitPreamble(Clang->getInvocation(), OverrideMainBuffer.get()); OwnedBuffers.push_back(OverrideMainBuffer.release()); } else { PreprocessorOpts.PrecompiledPreambleBytes.first = 0; @@ -2760,11 +2393,11 @@ SourceLocation ASTUnit::mapLocationFromPreamble(SourceLocation Loc) { if (SourceMgr) PreambleID = SourceMgr->getPreambleFileID(); - if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) + if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid()) return Loc; unsigned Offs; - if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble.size()) { + if (SourceMgr->isInFileID(Loc, PreambleID, &Offs) && Offs < Preamble->getBounds().Size) { SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(SourceMgr->getMainFileID()); return FileLoc.getLocWithOffset(Offs); @@ -2781,12 +2414,12 @@ SourceLocation ASTUnit::mapLocationToPreamble(SourceLocation Loc) { if (SourceMgr) PreambleID = SourceMgr->getPreambleFileID(); - if (Loc.isInvalid() || Preamble.empty() || PreambleID.isInvalid()) + if (Loc.isInvalid() || !Preamble || PreambleID.isInvalid()) return Loc; unsigned Offs; if (SourceMgr->isInFileID(Loc, SourceMgr->getMainFileID(), &Offs) && - Offs < Preamble.size()) { + Offs < Preamble->getBounds().Size) { SourceLocation FileLoc = SourceMgr->getLocForStartOfFile(PreambleID); return FileLoc.getLocWithOffset(Offs); } @@ -2932,17 +2565,6 @@ InputKind ASTUnit::getInputKind() const { return InputKind(Lang, Fmt, PP); } -void ASTUnit::PreambleData::countLines() const { - NumLines = 0; - if (empty()) - return; - - NumLines = std::count(Buffer.begin(), Buffer.end(), '\n'); - - if (Buffer.back() != '\n') - ++NumLines; -} - #ifndef NDEBUG ASTUnit::ConcurrencyState::ConcurrencyState() { Mutex = new llvm::sys::MutexImpl(/*recursive=*/true); diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index 72a8c3818093..e5da2ae4f22e 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -11,6 +11,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/MemoryBufferCache.h" @@ -1902,17 +1903,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc, StringRef ModuleName, StringRef Source) { + // Avoid creating filenames with special characters. + SmallString<128> CleanModuleName(ModuleName); + for (auto &C : CleanModuleName) + if (!isAlphanumeric(C)) + C = '_'; + // FIXME: Using a randomized filename here means that our intermediate .pcm // output is nondeterministic (as .pcm files refer to each other by name). // Can this affect the output in any way? SmallString<128> ModuleFileName; if (std::error_code EC = llvm::sys::fs::createTemporaryFile( - ModuleName, "pcm", ModuleFileName)) { + CleanModuleName, "pcm", ModuleFileName)) { getDiagnostics().Report(ImportLoc, diag::err_fe_unable_to_open_output) << ModuleFileName << EC.message(); return; } - std::string ModuleMapFileName = (ModuleName + ".map").str(); + std::string ModuleMapFileName = (CleanModuleName + ".map").str(); FrontendInputFile Input( ModuleMapFileName, diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index 1667af2d12bb..6254b0013bab 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -745,9 +745,22 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.CallFEntry = Args.hasArg(OPT_mfentry); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); - // TODO: map this from -gz in the driver and give it a named value - if (Args.hasArg(OPT_compress_debug_sections)) - Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU); + + if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, + OPT_compress_debug_sections_EQ)) { + if (A->getOption().getID() == OPT_compress_debug_sections) { + // TODO: be more clever about the compression type auto-detection + Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU); + } else { + auto DCT = llvm::StringSwitch(A->getValue()) + .Case("none", llvm::DebugCompressionType::None) + .Case("zlib", llvm::DebugCompressionType::Z) + .Case("zlib-gnu", llvm::DebugCompressionType::GNU) + .Default(llvm::DebugCompressionType::None); + Opts.setCompressDebugSections(DCT); + } + } + Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); for (auto A : Args.filtered(OPT_mlink_bitcode_file, OPT_mlink_cuda_bitcode)) { @@ -892,14 +905,18 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DiagnosticsWithHotness = Args.hasArg(options::OPT_fdiagnostics_show_hotness); + bool UsingSampleProfile = !Opts.SampleProfileFile.empty(); + if (Opts.DiagnosticsWithHotness && - Opts.getProfileUse() == CodeGenOptions::ProfileNone) + Opts.getProfileUse() == CodeGenOptions::ProfileNone && + !UsingSampleProfile) { Diags.Report(diag::warn_drv_fdiagnostics_show_hotness_requires_pgo); + } // If the user requested to use a sample profile for PGO, then the // backend will need to track source location information so the profile // can be incorporated into the IR. - if (!Opts.SampleProfileFile.empty()) + if (UsingSampleProfile) NeedLocTracking = true; // If the user requested a flag that requires source locations available in @@ -2379,9 +2396,51 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.AllowEditorPlaceholders = Args.hasArg(OPT_fallow_editor_placeholders); } +static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { + switch (Action) { + case frontend::ASTDeclList: + case frontend::ASTDump: + case frontend::ASTPrint: + case frontend::ASTView: + case frontend::EmitAssembly: + case frontend::EmitBC: + case frontend::EmitHTML: + case frontend::EmitLLVM: + case frontend::EmitLLVMOnly: + case frontend::EmitCodeGenOnly: + case frontend::EmitObj: + case frontend::FixIt: + case frontend::GenerateModule: + case frontend::GenerateModuleInterface: + case frontend::GeneratePCH: + case frontend::GeneratePTH: + case frontend::ParseSyntaxOnly: + case frontend::ModuleFileInfo: + case frontend::VerifyPCH: + case frontend::PluginAction: + case frontend::PrintDeclContext: + case frontend::RewriteObjC: + case frontend::RewriteTest: + case frontend::RunAnalysis: + case frontend::MigrateSource: + return false; + + case frontend::DumpRawTokens: + case frontend::DumpTokens: + case frontend::InitOnly: + case frontend::PrintPreamble: + case frontend::PrintPreprocessedInput: + case frontend::RewriteMacros: + case frontend::RunPreprocessorOnly: + return true; + } + llvm_unreachable("invalid frontend action"); +} + static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, FileManager &FileMgr, - DiagnosticsEngine &Diags) { + DiagnosticsEngine &Diags, + frontend::ActionKind Action) { using namespace options; Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); @@ -2454,6 +2513,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, else Opts.ObjCXXARCStandardLibrary = (ObjCXXARCStandardLibraryKind)Library; } + + // Always avoid lexing editor placeholders when we're just running the + // preprocessor as we never want to emit the + // "editor placeholder in source file" error in PP only mode. + if (isStrictlyPreprocessorAction(Action)) + Opts.LexEditorPlaceholders = false; } static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, @@ -2461,45 +2526,10 @@ static void ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts, frontend::ActionKind Action) { using namespace options; - switch (Action) { - case frontend::ASTDeclList: - case frontend::ASTDump: - case frontend::ASTPrint: - case frontend::ASTView: - case frontend::EmitAssembly: - case frontend::EmitBC: - case frontend::EmitHTML: - case frontend::EmitLLVM: - case frontend::EmitLLVMOnly: - case frontend::EmitCodeGenOnly: - case frontend::EmitObj: - case frontend::FixIt: - case frontend::GenerateModule: - case frontend::GenerateModuleInterface: - case frontend::GeneratePCH: - case frontend::GeneratePTH: - case frontend::ParseSyntaxOnly: - case frontend::ModuleFileInfo: - case frontend::VerifyPCH: - case frontend::PluginAction: - case frontend::PrintDeclContext: - case frontend::RewriteObjC: - case frontend::RewriteTest: - case frontend::RunAnalysis: - case frontend::MigrateSource: - Opts.ShowCPP = 0; - break; - - case frontend::DumpRawTokens: - case frontend::DumpTokens: - case frontend::InitOnly: - case frontend::PrintPreamble: - case frontend::PrintPreprocessedInput: - case frontend::RewriteMacros: - case frontend::RunPreprocessorOnly: + if (isStrictlyPreprocessorAction(Action)) Opts.ShowCPP = !Args.hasArg(OPT_dM); - break; - } + else + Opts.ShowCPP = 0; Opts.ShowComments = Args.hasArg(OPT_C); Opts.ShowLineMarkers = !Args.hasArg(OPT_P); @@ -2626,7 +2656,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, // ParsePreprocessorArgs and remove the FileManager // parameters from the function and the "FileManager.h" #include. FileManager FileMgr(Res.getFileSystemOpts()); - ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags); + ParsePreprocessorArgs(Res.getPreprocessorOpts(), Args, FileMgr, Diags, + Res.getFrontendOpts().ProgramAction); ParsePreprocessorOutputArgs(Res.getPreprocessorOutputOpts(), Args, Res.getFrontendOpts().ProgramAction); diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index 7c0b854648bd..f81a06b31869 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -561,7 +561,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.setFileManager(&AST->getFileManager()); CI.createSourceManager(CI.getFileManager()); CI.getSourceManager().initializeForReplay(AST->getSourceManager()); - CI.createPreprocessor(getTranslationUnitKind()); // Set up the input file for replay purposes. auto Kind = AST->getInputKind(); diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp index c5567a09636b..9621889b27ad 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -517,7 +517,7 @@ void PrintPreprocessedAction::ExecuteAction() { // file. This is mostly a sanity check in case the file has no // newlines whatsoever. if (end - cur > 256) end = cur + 256; - + while (next < end) { if (*cur == 0x0D) { // CR if (*next == 0x0A) // CRLF diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp new file mode 100644 index 000000000000..15b24cbed484 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -0,0 +1,563 @@ +//===--- PrecompiledPreamble.cpp - Build precompiled preambles --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Helper class to build precompiled preamble. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/PrecompiledPreamble.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Frontend/FrontendActions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Serialization/ASTWriter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/CrashRecoveryContext.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/MutexGuard.h" + +using namespace clang; + +namespace { + +/// Keeps a track of files to be deleted in destructor. +class TemporaryFiles { +public: + // A static instance to be used by all clients. + static TemporaryFiles &getInstance(); + +private: + // Disallow constructing the class directly. + TemporaryFiles() = default; + // Disallow copy. + TemporaryFiles(const TemporaryFiles &) = delete; + +public: + ~TemporaryFiles(); + + /// Adds \p File to a set of tracked files. + void addFile(StringRef File); + + /// Remove \p File from disk and from the set of tracked files. + void removeFile(StringRef File); + +private: + llvm::sys::SmartMutex Mutex; + llvm::StringSet<> Files; +}; + +TemporaryFiles &TemporaryFiles::getInstance() { + static TemporaryFiles Instance; + return Instance; +} + +TemporaryFiles::~TemporaryFiles() { + llvm::MutexGuard Guard(Mutex); + for (const auto &File : Files) + llvm::sys::fs::remove(File.getKey()); +} + +void TemporaryFiles::addFile(StringRef File) { + llvm::MutexGuard Guard(Mutex); + auto IsInserted = Files.insert(File).second; + (void)IsInserted; + assert(IsInserted && "File has already been added"); +} + +void TemporaryFiles::removeFile(StringRef File) { + llvm::MutexGuard Guard(Mutex); + auto WasPresent = Files.erase(File); + (void)WasPresent; + assert(WasPresent && "File was not tracked"); + llvm::sys::fs::remove(File); +} + +class PreambleMacroCallbacks : public PPCallbacks { +public: + PreambleMacroCallbacks(PreambleCallbacks &Callbacks) : Callbacks(Callbacks) {} + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + Callbacks.HandleMacroDefined(MacroNameTok, MD); + } + +private: + PreambleCallbacks &Callbacks; +}; + +class PrecompilePreambleAction : public ASTFrontendAction { +public: + PrecompilePreambleAction(PreambleCallbacks &Callbacks) + : Callbacks(Callbacks) {} + + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override; + + bool hasEmittedPreamblePCH() const { return HasEmittedPreamblePCH; } + + void setEmittedPreamblePCH(ASTWriter &Writer) { + this->HasEmittedPreamblePCH = true; + Callbacks.AfterPCHEmitted(Writer); + } + + bool shouldEraseOutputFiles() override { return !hasEmittedPreamblePCH(); } + bool hasCodeCompletionSupport() const override { return false; } + bool hasASTFileSupport() const override { return false; } + TranslationUnitKind getTranslationUnitKind() override { return TU_Prefix; } + +private: + friend class PrecompilePreambleConsumer; + + bool HasEmittedPreamblePCH = false; + PreambleCallbacks &Callbacks; +}; + +class PrecompilePreambleConsumer : public PCHGenerator { +public: + PrecompilePreambleConsumer(PrecompilePreambleAction &Action, + const Preprocessor &PP, StringRef isysroot, + std::unique_ptr Out) + : PCHGenerator(PP, "", isysroot, std::make_shared(), + ArrayRef>(), + /*AllowASTWithErrors=*/true), + Action(Action), Out(std::move(Out)) {} + + bool HandleTopLevelDecl(DeclGroupRef DG) override { + Action.Callbacks.HandleTopLevelDecl(DG); + return true; + } + + void HandleTranslationUnit(ASTContext &Ctx) override { + PCHGenerator::HandleTranslationUnit(Ctx); + if (!hasEmittedPCH()) + return; + + // Write the generated bitstream to "Out". + *Out << getPCH(); + // Make sure it hits disk now. + Out->flush(); + // Free the buffer. + llvm::SmallVector Empty; + getPCH() = std::move(Empty); + + Action.setEmittedPreamblePCH(getWriter()); + } + +private: + PrecompilePreambleAction &Action; + std::unique_ptr Out; +}; + +std::unique_ptr +PrecompilePreambleAction::CreateASTConsumer(CompilerInstance &CI, + + StringRef InFile) { + std::string Sysroot; + std::string OutputFile; + std::unique_ptr OS = + GeneratePCHAction::ComputeASTConsumerArguments(CI, InFile, Sysroot, + OutputFile); + if (!OS) + return nullptr; + + if (!CI.getFrontendOpts().RelocatablePCH) + Sysroot.clear(); + + CI.getPreprocessor().addPPCallbacks( + llvm::make_unique(Callbacks)); + return llvm::make_unique( + *this, CI.getPreprocessor(), Sysroot, std::move(OS)); +} + +template bool moveOnNoError(llvm::ErrorOr Val, T &Output) { + if (!Val) + return false; + Output = std::move(*Val); + return true; +} + +} // namespace + +PreambleBounds clang::ComputePreambleBounds(const LangOptions &LangOpts, + llvm::MemoryBuffer *Buffer, + unsigned MaxLines) { + auto Pre = Lexer::ComputePreamble(Buffer->getBuffer(), LangOpts, MaxLines); + return PreambleBounds(Pre.first, Pre.second); +} + +llvm::ErrorOr PrecompiledPreamble::Build( + const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, PreambleBounds Bounds, + DiagnosticsEngine &Diagnostics, IntrusiveRefCntPtr VFS, + std::shared_ptr PCHContainerOps, + PreambleCallbacks &Callbacks) { + assert(VFS && "VFS is null"); + + if (!Bounds.Size) + return BuildPreambleError::PreambleIsEmpty; + + auto PreambleInvocation = std::make_shared(Invocation); + FrontendOptions &FrontendOpts = PreambleInvocation->getFrontendOpts(); + PreprocessorOptions &PreprocessorOpts = + PreambleInvocation->getPreprocessorOpts(); + + // Create a temporary file for the precompiled preamble. In rare + // circumstances, this can fail. + llvm::ErrorOr PreamblePCHFile = + PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile(); + if (!PreamblePCHFile) + return BuildPreambleError::CouldntCreateTempFile; + + // Save the preamble text for later; we'll need to compare against it for + // subsequent reparses. + std::vector PreambleBytes(MainFileBuffer->getBufferStart(), + MainFileBuffer->getBufferStart() + + Bounds.Size); + bool PreambleEndsAtStartOfLine = Bounds.PreambleEndsAtStartOfLine; + + // Tell the compiler invocation to generate a temporary precompiled header. + FrontendOpts.ProgramAction = frontend::GeneratePCH; + // FIXME: Generate the precompiled header into memory? + FrontendOpts.OutputFile = PreamblePCHFile->getFilePath(); + PreprocessorOpts.PrecompiledPreambleBytes.first = 0; + PreprocessorOpts.PrecompiledPreambleBytes.second = false; + + // Create the compiler instance to use for building the precompiled preamble. + std::unique_ptr Clang( + new CompilerInstance(std::move(PCHContainerOps))); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar CICleanup( + Clang.get()); + + Clang->setInvocation(std::move(PreambleInvocation)); + Clang->setDiagnostics(&Diagnostics); + + // Create the target instance. + Clang->setTarget(TargetInfo::CreateTargetInfo( + Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); + if (!Clang->hasTarget()) + return BuildPreambleError::CouldntCreateTargetInfo; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Clang->getTarget().adjust(Clang->getLangOpts()); + + assert(Clang->getFrontendOpts().Inputs.size() == 1 && + "Invocation must have exactly one source file!"); + assert(Clang->getFrontendOpts().Inputs[0].getKind().getFormat() == + InputKind::Source && + "FIXME: AST inputs not yet supported here!"); + assert(Clang->getFrontendOpts().Inputs[0].getKind().getLanguage() != + InputKind::LLVM_IR && + "IR inputs not support here!"); + + // Clear out old caches and data. + Diagnostics.Reset(); + ProcessWarningOptions(Diagnostics, Clang->getDiagnosticOpts()); + + VFS = + createVFSFromCompilerInvocation(Clang->getInvocation(), Diagnostics, VFS); + if (!VFS) + return BuildPreambleError::CouldntCreateVFSOverlay; + + // Create a file manager object to provide access to and cache the filesystem. + Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); + + // Create the source manager. + Clang->setSourceManager( + new SourceManager(Diagnostics, Clang->getFileManager())); + + auto PreambleDepCollector = std::make_shared(); + Clang->addDependencyCollector(PreambleDepCollector); + + // Remap the main source file to the preamble buffer. + StringRef MainFilePath = FrontendOpts.Inputs[0].getFile(); + auto PreambleInputBuffer = llvm::MemoryBuffer::getMemBufferCopy( + MainFileBuffer->getBuffer().slice(0, Bounds.Size), MainFilePath); + if (PreprocessorOpts.RetainRemappedFileBuffers) { + // MainFileBuffer will be deleted by unique_ptr after leaving the method. + PreprocessorOpts.addRemappedFile(MainFilePath, PreambleInputBuffer.get()); + } else { + // In that case, remapped buffer will be deleted by CompilerInstance on + // BeginSourceFile, so we call release() to avoid double deletion. + PreprocessorOpts.addRemappedFile(MainFilePath, + PreambleInputBuffer.release()); + } + + std::unique_ptr Act; + Act.reset(new PrecompilePreambleAction(Callbacks)); + if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) + return BuildPreambleError::BeginSourceFileFailed; + + Act->Execute(); + + // Run the callbacks. + Callbacks.AfterExecute(*Clang); + + Act->EndSourceFile(); + + if (!Act->hasEmittedPreamblePCH()) + return BuildPreambleError::CouldntEmitPCH; + + // Keep track of all of the files that the source manager knows about, + // so we can verify whether they have changed or not. + llvm::StringMap FilesInPreamble; + + SourceManager &SourceMgr = Clang->getSourceManager(); + for (auto &Filename : PreambleDepCollector->getDependencies()) { + const FileEntry *File = Clang->getFileManager().getFile(Filename); + if (!File || File == SourceMgr.getFileEntryForID(SourceMgr.getMainFileID())) + continue; + if (time_t ModTime = File->getModificationTime()) { + FilesInPreamble[File->getName()] = + PrecompiledPreamble::PreambleFileHash::createForFile(File->getSize(), + ModTime); + } else { + llvm::MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); + FilesInPreamble[File->getName()] = + PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer(Buffer); + } + } + + return PrecompiledPreamble( + std::move(*PreamblePCHFile), std::move(PreambleBytes), + PreambleEndsAtStartOfLine, std::move(FilesInPreamble)); +} + +PreambleBounds PrecompiledPreamble::getBounds() const { + return PreambleBounds(PreambleBytes.size(), PreambleEndsAtStartOfLine); +} + +bool PrecompiledPreamble::CanReuse(const CompilerInvocation &Invocation, + const llvm::MemoryBuffer *MainFileBuffer, + PreambleBounds Bounds, + vfs::FileSystem *VFS) const { + + assert( + Bounds.Size <= MainFileBuffer->getBufferSize() && + "Buffer is too large. Bounds were calculated from a different buffer?"); + + auto PreambleInvocation = std::make_shared(Invocation); + PreprocessorOptions &PreprocessorOpts = + PreambleInvocation->getPreprocessorOpts(); + + if (!Bounds.Size) + return false; + + // We've previously computed a preamble. Check whether we have the same + // preamble now that we did before, and that there's enough space in + // the main-file buffer within the precompiled preamble to fit the + // new main file. + if (PreambleBytes.size() != Bounds.Size || + PreambleEndsAtStartOfLine != Bounds.PreambleEndsAtStartOfLine || + memcmp(PreambleBytes.data(), MainFileBuffer->getBufferStart(), + Bounds.Size) != 0) + return false; + // The preamble has not changed. We may be able to re-use the precompiled + // preamble. + + // Check that none of the files used by the preamble have changed. + // First, make a record of those files that have been overridden via + // remapping or unsaved_files. + std::map OverriddenFiles; + for (const auto &R : PreprocessorOpts.RemappedFiles) { + vfs::Status Status; + if (!moveOnNoError(VFS->status(R.second), Status)) { + // If we can't stat the file we're remapping to, assume that something + // horrible happened. + return false; + } + + OverriddenFiles[Status.getUniqueID()] = PreambleFileHash::createForFile( + Status.getSize(), llvm::sys::toTimeT(Status.getLastModificationTime())); + } + + for (const auto &RB : PreprocessorOpts.RemappedFileBuffers) { + vfs::Status Status; + if (!moveOnNoError(VFS->status(RB.first), Status)) + return false; + + OverriddenFiles[Status.getUniqueID()] = + PreambleFileHash::createForMemoryBuffer(RB.second); + } + + // Check whether anything has changed. + for (const auto &F : FilesInPreamble) { + vfs::Status Status; + if (!moveOnNoError(VFS->status(F.first()), Status)) { + // If we can't stat the file, assume that something horrible happened. + return false; + } + + std::map::iterator Overridden = + OverriddenFiles.find(Status.getUniqueID()); + if (Overridden != OverriddenFiles.end()) { + // This file was remapped; check whether the newly-mapped file + // matches up with the previous mapping. + if (Overridden->second != F.second) + return false; + continue; + } + + // The file was not remapped; check whether it has changed on disk. + if (Status.getSize() != uint64_t(F.second.Size) || + llvm::sys::toTimeT(Status.getLastModificationTime()) != + F.second.ModTime) + return false; + } + return true; +} + +void PrecompiledPreamble::AddImplicitPreamble( + CompilerInvocation &CI, llvm::MemoryBuffer *MainFileBuffer) const { + auto &PreprocessorOpts = CI.getPreprocessorOpts(); + + // Configure ImpicitPCHInclude. + PreprocessorOpts.PrecompiledPreambleBytes.first = PreambleBytes.size(); + PreprocessorOpts.PrecompiledPreambleBytes.second = PreambleEndsAtStartOfLine; + PreprocessorOpts.ImplicitPCHInclude = PCHFile.getFilePath(); + PreprocessorOpts.DisablePCHValidation = true; + + // Remap main file to point to MainFileBuffer. + auto MainFilePath = CI.getFrontendOpts().Inputs[0].getFile(); + PreprocessorOpts.addRemappedFile(MainFilePath, MainFileBuffer); +} + +PrecompiledPreamble::PrecompiledPreamble( + TempPCHFile PCHFile, std::vector PreambleBytes, + bool PreambleEndsAtStartOfLine, + llvm::StringMap FilesInPreamble) + : PCHFile(std::move(PCHFile)), FilesInPreamble(FilesInPreamble), + PreambleBytes(std::move(PreambleBytes)), + PreambleEndsAtStartOfLine(PreambleEndsAtStartOfLine) {} + +llvm::ErrorOr +PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() { + // FIXME: This is a hack so that we can override the preamble file during + // crash-recovery testing, which is the only case where the preamble files + // are not necessarily cleaned up. + const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); + if (TmpFile) + return TempPCHFile::createFromCustomPath(TmpFile); + return TempPCHFile::createInSystemTempDir("preamble", "pch"); +} + +llvm::ErrorOr +PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix, + StringRef Suffix) { + llvm::SmallString<64> File; + auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, /*ref*/ File); + if (EC) + return EC; + return TempPCHFile(std::move(File).str()); +} + +llvm::ErrorOr +PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) { + return TempPCHFile(Path.str()); +} + +PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath) + : FilePath(std::move(FilePath)) { + TemporaryFiles::getInstance().addFile(*this->FilePath); +} + +PrecompiledPreamble::TempPCHFile::TempPCHFile(TempPCHFile &&Other) { + FilePath = std::move(Other.FilePath); + Other.FilePath = None; +} + +PrecompiledPreamble::TempPCHFile &PrecompiledPreamble::TempPCHFile:: +operator=(TempPCHFile &&Other) { + RemoveFileIfPresent(); + + FilePath = std::move(Other.FilePath); + Other.FilePath = None; + return *this; +} + +PrecompiledPreamble::TempPCHFile::~TempPCHFile() { RemoveFileIfPresent(); } + +void PrecompiledPreamble::TempPCHFile::RemoveFileIfPresent() { + if (FilePath) { + TemporaryFiles::getInstance().removeFile(*FilePath); + FilePath = None; + } +} + +llvm::StringRef PrecompiledPreamble::TempPCHFile::getFilePath() const { + assert(FilePath && "TempPCHFile doesn't have a FilePath. Had it been moved?"); + return *FilePath; +} + +PrecompiledPreamble::PreambleFileHash +PrecompiledPreamble::PreambleFileHash::createForFile(off_t Size, + time_t ModTime) { + PreambleFileHash Result; + Result.Size = Size; + Result.ModTime = ModTime; + Result.MD5 = {}; + return Result; +} + +PrecompiledPreamble::PreambleFileHash +PrecompiledPreamble::PreambleFileHash::createForMemoryBuffer( + const llvm::MemoryBuffer *Buffer) { + PreambleFileHash Result; + Result.Size = Buffer->getBufferSize(); + Result.ModTime = 0; + + llvm::MD5 MD5Ctx; + MD5Ctx.update(Buffer->getBuffer().data()); + MD5Ctx.final(Result.MD5); + + return Result; +} + +void PreambleCallbacks::AfterExecute(CompilerInstance &CI) {} +void PreambleCallbacks::AfterPCHEmitted(ASTWriter &Writer) {} +void PreambleCallbacks::HandleTopLevelDecl(DeclGroupRef DG) {} +void PreambleCallbacks::HandleMacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) {} + +std::error_code clang::make_error_code(BuildPreambleError Error) { + return std::error_code(static_cast(Error), BuildPreambleErrorCategory()); +} + +const char *BuildPreambleErrorCategory::name() const noexcept { + return "build-preamble.error"; +} + +std::string BuildPreambleErrorCategory::message(int condition) const { + switch (static_cast(condition)) { + case BuildPreambleError::PreambleIsEmpty: + return "Preamble is empty"; + case BuildPreambleError::CouldntCreateTempFile: + return "Could not create temporary file for PCH"; + case BuildPreambleError::CouldntCreateTargetInfo: + return "CreateTargetInfo() return null"; + case BuildPreambleError::CouldntCreateVFSOverlay: + return "Could not create VFS Overlay"; + case BuildPreambleError::BeginSourceFileFailed: + return "BeginSourceFile() return an error"; + case BuildPreambleError::CouldntEmitPCH: + return "Could not emit PCH"; + } + llvm_unreachable("unexpected BuildPreambleError"); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 832eaf2926f0..5336de1f7468 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -349,7 +349,7 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, case tok::pp_include_next: startNewLineIfNeeded(); MoveToLine(HashLoc); - OS << "#pragma clang module import " << Imported->getFullModuleName() + OS << "#pragma clang module import " << Imported->getFullModuleName(true) << " /* clang -E: implicit import for " << "#" << PP.getSpelling(IncludeTok) << " " << (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"') @@ -378,14 +378,14 @@ void PrintPPOutputPPCallbacks::InclusionDirective(SourceLocation HashLoc, /// Handle entering the scope of a module during a module compilation. void PrintPPOutputPPCallbacks::BeginModule(const Module *M) { startNewLineIfNeeded(); - OS << "#pragma clang module begin " << M->getFullModuleName(); + OS << "#pragma clang module begin " << M->getFullModuleName(true); setEmittedDirectiveOnThisLine(); } /// Handle leaving the scope of a module during a module compilation. void PrintPPOutputPPCallbacks::EndModule(const Module *M) { startNewLineIfNeeded(); - OS << "#pragma clang module end /*" << M->getFullModuleName() << "*/"; + OS << "#pragma clang module end /*" << M->getFullModuleName(true) << "*/"; setEmittedDirectiveOnThisLine(); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 45feffbcb5b5..e93f737c47fd 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -9,6 +9,7 @@ #include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/AST/ASTConsumer.h" +#include "clang/Basic/CharInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -224,7 +225,15 @@ class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener { auto OS = Out.lock(); assert(OS && "loaded module file after finishing rewrite action?"); - (*OS) << "#pragma clang module build " << MF->ModuleName << "\n"; + (*OS) << "#pragma clang module build "; + if (isValidIdentifier(MF->ModuleName)) + (*OS) << MF->ModuleName; + else { + (*OS) << '"'; + OS->write_escaped(MF->ModuleName); + (*OS) << '"'; + } + (*OS) << '\n'; // Rewrite the contents of the module in a separate compiler instance. CompilerInstance Instance(CI.getPCHContainerOperations(), @@ -234,9 +243,12 @@ class RewriteIncludesAction::RewriteImportsListener : public ASTReaderListener { Instance.createDiagnostics( new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()), /*ShouldOwnClient=*/true); + Instance.getFrontendOpts().DisableFree = false; Instance.getFrontendOpts().Inputs.clear(); Instance.getFrontendOpts().Inputs.emplace_back( Filename, InputKind(InputKind::Unknown, InputKind::Precompiled)); + Instance.getFrontendOpts().ModuleFiles.clear(); + Instance.getFrontendOpts().ModuleMapFiles.clear(); // Don't recursively rewrite imports. We handle them all at the top level. Instance.getPreprocessorOutputOpts().RewriteImports = false; diff --git a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp index 3564cebba8a8..e0477069b340 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/Rewrite/InclusionRewriter.cpp @@ -140,7 +140,7 @@ void InclusionRewriter::WriteLineInfo(StringRef Filename, int Line, } void InclusionRewriter::WriteImplicitModuleImport(const Module *Mod) { - OS << "#pragma clang module import " << Mod->getFullModuleName() + OS << "#pragma clang module import " << Mod->getFullModuleName(true) << " /* clang -frewrite-includes: implicit import */" << MainEOL; } @@ -471,15 +471,15 @@ void InclusionRewriter::Process(FileID FileId, else if (const IncludedFile *Inc = FindIncludeAtLocation(Loc)) { const Module *Mod = FindEnteredModule(Loc); if (Mod) - OS << "#pragma clang module begin " << Mod->getFullModuleName() - << "\n"; + OS << "#pragma clang module begin " + << Mod->getFullModuleName(true) << "\n"; // Include and recursively process the file. Process(Inc->Id, Inc->FileType); if (Mod) - OS << "#pragma clang module end /*" << Mod->getFullModuleName() - << "*/\n"; + OS << "#pragma clang module end /*" + << Mod->getFullModuleName(true) << "*/\n"; // Add line marker to indicate we're returning from an included // file. diff --git a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp index 2162c039c48b..d1127722c8ca 100644 --- a/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Index/IndexDecl.cpp @@ -351,9 +351,11 @@ class IndexingDeclVisitor : public ConstDeclVisitor { IndexCtx.indexTagDecl(D, Relations); } else { auto *Parent = dyn_cast(D->getDeclContext()); + SmallVector Relations; + gatherTemplatePseudoOverrides(D, Relations); return IndexCtx.handleReference(D, D->getLocation(), Parent, D->getLexicalDeclContext(), - SymbolRoleSet()); + SymbolRoleSet(), Relations); } } return true; @@ -609,18 +611,16 @@ class IndexingDeclVisitor : public ConstDeclVisitor { ClassTemplateSpecializationDecl *D) { // FIXME: Notify subsequent callbacks if info comes from implicit // instantiation. - if (D->isThisDeclarationADefinition()) { - llvm::PointerUnion - Template = D->getSpecializedTemplateOrPartial(); - const Decl *SpecializationOf = - Template.is() - ? (Decl *)Template.get() - : Template.get(); - IndexCtx.indexTagDecl( - D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), - SpecializationOf)); - } + llvm::PointerUnion + Template = D->getSpecializedTemplateOrPartial(); + const Decl *SpecializationOf = + Template.is() + ? (Decl *)Template.get() + : Template.get(); + IndexCtx.indexTagDecl( + D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), + SpecializationOf)); if (TypeSourceInfo *TSI = D->getTypeAsWritten()) IndexCtx.indexTypeSourceInfo(TSI, /*Parent=*/nullptr, D->getLexicalDeclContext()); diff --git a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp index 447ff212f06e..012189aa6f9f 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp @@ -19,6 +19,7 @@ #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" @@ -2750,7 +2751,7 @@ static const char *findPlaceholderEnd(const char *CurPtr, bool Lexer::lexEditorPlaceholder(Token &Result, const char *CurPtr) { assert(CurPtr[-1] == '<' && CurPtr[0] == '#' && "Not a placeholder!"); - if (!PP || LexingRawMode) + if (!PP || !PP->getPreprocessorOpts().LexEditorPlaceholders || LexingRawMode) return false; const char *End = findPlaceholderEnd(CurPtr + 1, BufferEnd); if (!End) diff --git a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp index 89c2ebd00a68..8c79e50176e1 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp @@ -538,7 +538,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, assert(CurPPLexer->LexingRawMode && "We have to be skipping here!"); CurPPLexer->LexingRawMode = false; IdentifierInfo *IfNDefMacro = nullptr; - const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro); + const bool CondValue = EvaluateDirectiveExpression(IfNDefMacro).Conditional; CurPPLexer->LexingRawMode = true; if (Callbacks) { const SourceLocation CondEnd = CurPPLexer->getSourceLocation(); @@ -635,7 +635,7 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { // Evaluate the condition of the #elif. IdentifierInfo *IfNDefMacro = nullptr; CurPTHLexer->ParsingPreprocessorDirective = true; - bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro); + bool ShouldEnter = EvaluateDirectiveExpression(IfNDefMacro).Conditional; CurPTHLexer->ParsingPreprocessorDirective = false; // If this condition is true, enter it! @@ -2654,7 +2654,13 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, } // Should we include the stuff contained by this directive? - if (!MI == isIfndef) { + if (PPOpts->SingleFileParseMode && !MI) { + // In 'single-file-parse mode' undefined identifiers trigger parsing of all + // the directive blocks. + CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), + /*wasskip*/false, /*foundnonskip*/false, + /*foundelse*/false); + } else if (!MI == isIfndef) { // Yes, remember that we are inside a conditional, then lex the next token. CurPPLexer->pushConditionalLevel(DirectiveTok.getLocation(), /*wasskip*/false, /*foundnonskip*/true, @@ -2676,7 +2682,8 @@ void Preprocessor::HandleIfDirective(Token &IfToken, // Parse and evaluate the conditional expression. IdentifierInfo *IfNDefMacro = nullptr; const SourceLocation ConditionalBegin = CurPPLexer->getSourceLocation(); - const bool ConditionalTrue = EvaluateDirectiveExpression(IfNDefMacro); + const DirectiveEvalResult DER = EvaluateDirectiveExpression(IfNDefMacro); + const bool ConditionalTrue = DER.Conditional; const SourceLocation ConditionalEnd = CurPPLexer->getSourceLocation(); // If this condition is equivalent to #ifndef X, and if this is the first @@ -2695,7 +2702,12 @@ void Preprocessor::HandleIfDirective(Token &IfToken, (ConditionalTrue ? PPCallbacks::CVK_True : PPCallbacks::CVK_False)); // Should we include the stuff contained by this directive? - if (ConditionalTrue) { + if (PPOpts->SingleFileParseMode && DER.IncludedUndefinedIds) { + // In 'single-file-parse mode' undefined identifiers trigger parsing of all + // the directive blocks. + CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false, + /*foundnonskip*/false, /*foundelse*/false); + } else if (ConditionalTrue) { // Yes, remember that we are inside a conditional, then lex the next token. CurPPLexer->pushConditionalLevel(IfToken.getLocation(), /*wasskip*/false, /*foundnonskip*/true, /*foundelse*/false); @@ -2756,6 +2768,14 @@ void Preprocessor::HandleElseDirective(Token &Result) { if (Callbacks) Callbacks->Else(Result.getLocation(), CI.IfLoc); + if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) { + // In 'single-file-parse mode' undefined identifiers trigger parsing of all + // the directive blocks. + CurPPLexer->pushConditionalLevel(CI.IfLoc, /*wasskip*/false, + /*foundnonskip*/false, /*foundelse*/true); + return; + } + // Finally, skip the rest of the contents of this block. SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, /*FoundElse*/true, Result.getLocation()); @@ -2791,6 +2811,14 @@ void Preprocessor::HandleElifDirective(Token &ElifToken) { SourceRange(ConditionalBegin, ConditionalEnd), PPCallbacks::CVK_NotEvaluated, CI.IfLoc); + if (PPOpts->SingleFileParseMode && !CI.FoundNonSkip) { + // In 'single-file-parse mode' undefined identifiers trigger parsing of all + // the directive blocks. + CurPPLexer->pushConditionalLevel(ElifToken.getLocation(), /*wasskip*/false, + /*foundnonskip*/false, /*foundelse*/false); + return; + } + // Finally, skip the rest of the contents of this block. SkipExcludedConditionalBlock(CI.IfLoc, /*Foundnonskip*/true, /*FoundElse*/CI.FoundElse, diff --git a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp index 862a4713e4bc..12f5084298df 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp @@ -73,6 +73,7 @@ class PPValue { static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, Token &PeekTok, bool ValueLive, + bool &IncludedUndefinedIds, Preprocessor &PP); /// DefinedTracker - This struct is used while parsing expressions to keep track @@ -93,6 +94,7 @@ struct DefinedTracker { /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this /// indicates the macro that was checked. IdentifierInfo *TheMacro; + bool IncludedUndefinedIds = false; }; /// EvaluateDefined - Process a 'defined(sym)' expression. @@ -128,6 +130,7 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, MacroDefinition Macro = PP.getMacroDefinition(II); Result.Val = !!Macro; Result.Val.setIsUnsigned(false); // Result is signed intmax_t. + DT.IncludedUndefinedIds = !Macro; // If there is a macro, mark it used. if (Result.Val != 0 && ValueLive) @@ -255,6 +258,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0. Result.setIdentifier(II); Result.setRange(PeekTok.getLocation()); + DT.IncludedUndefinedIds = (II->getTokenID() != tok::kw_true && + II->getTokenID() != tok::kw_false); PP.LexNonComment(PeekTok); return false; } @@ -400,7 +405,8 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // Just use DT unmodified as our result. } else { // Otherwise, we have something like (x+y), and we consumed '(x'. - if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, PP)) + if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, ValueLive, + DT.IncludedUndefinedIds, PP)) return true; if (PeekTok.isNot(tok::r_paren)) { @@ -532,6 +538,7 @@ static void diagnoseUnexpectedOperator(Preprocessor &PP, PPValue &LHS, /// evaluation, such as division by zero warnings. static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, Token &PeekTok, bool ValueLive, + bool &IncludedUndefinedIds, Preprocessor &PP) { unsigned PeekPrec = getPrecedence(PeekTok.getKind()); // If this token isn't valid, report the error. @@ -571,6 +578,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, // Parse the RHS of the operator. DefinedTracker DT; if (EvaluateValue(RHS, PeekTok, DT, RHSIsLive, PP)) return true; + IncludedUndefinedIds = DT.IncludedUndefinedIds; // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. @@ -601,7 +609,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, RHSPrec = ThisPrec+1; if (PeekPrec >= RHSPrec) { - if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive, PP)) + if (EvaluateDirectiveSubExpr(RHS, RHSPrec, PeekTok, RHSIsLive, + IncludedUndefinedIds, PP)) return true; PeekPrec = getPrecedence(PeekTok.getKind()); } @@ -769,7 +778,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, // Parse anything after the : with the same precedence as ?. We allow // things of equal precedence because ?: is right associative. if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec, - PeekTok, AfterColonLive, PP)) + PeekTok, AfterColonLive, + IncludedUndefinedIds, PP)) return true; // Now that we have the condition, the LHS and the RHS of the :, evaluate. @@ -806,7 +816,8 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, /// EvaluateDirectiveExpression - Evaluate an integer constant expression that /// may occur after a #if or #elif directive. If the expression is equivalent /// to "!defined(X)" return X in IfNDefMacro. -bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { +Preprocessor::DirectiveEvalResult +Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { SaveAndRestore PPDir(ParsingIfOrElifDirective, true); // Save the current state of 'DisableMacroExpansion' and reset it to false. If // 'DisableMacroExpansion' is true, then we must be in a macro argument list @@ -833,7 +844,7 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Restore 'DisableMacroExpansion'. DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; - return false; + return {false, DT.IncludedUndefinedIds}; } // If we are at the end of the expression after just parsing a value, there @@ -847,20 +858,20 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Restore 'DisableMacroExpansion'. DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; - return ResVal.Val != 0; + return {ResVal.Val != 0, DT.IncludedUndefinedIds}; } // Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the // operator and the stuff after it. if (EvaluateDirectiveSubExpr(ResVal, getPrecedence(tok::question), - Tok, true, *this)) { + Tok, true, DT.IncludedUndefinedIds, *this)) { // Parse error, skip the rest of the macro line. if (Tok.isNot(tok::eod)) DiscardUntilEndOfDirective(); // Restore 'DisableMacroExpansion'. DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; - return false; + return {false, DT.IncludedUndefinedIds}; } // If we aren't at the tok::eod token, something bad happened, like an extra @@ -872,5 +883,5 @@ bool Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // Restore 'DisableMacroExpansion'. DisableMacroExpansion = DisableMacroExpansionAtStartOfDirective; - return ResVal.Val != 0; + return {ResVal.Val != 0, DT.IncludedUndefinedIds}; } diff --git a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp index c16478dd2be4..bf2363a0a6f4 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/TokenKinds.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/LiteralSupport.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" @@ -754,15 +755,52 @@ void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) { getHeaderSearchInfo().AddIncludeAlias(OriginalSource, ReplaceFileName); } +// Lex a component of a module name: either an identifier or a string literal; +// for components that can be expressed both ways, the two forms are equivalent. +static bool LexModuleNameComponent( + Preprocessor &PP, Token &Tok, + std::pair &ModuleNameComponent, + bool First) { + PP.LexUnexpandedToken(Tok); + if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) { + StringLiteralParser Literal(Tok, PP); + if (Literal.hadError) + return true; + ModuleNameComponent = std::make_pair( + PP.getIdentifierInfo(Literal.GetString()), Tok.getLocation()); + } else if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) { + ModuleNameComponent = + std::make_pair(Tok.getIdentifierInfo(), Tok.getLocation()); + } else { + PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << First; + return true; + } + return false; +} + +static bool LexModuleName( + Preprocessor &PP, Token &Tok, + llvm::SmallVectorImpl> + &ModuleName) { + while (true) { + std::pair NameComponent; + if (LexModuleNameComponent(PP, Tok, NameComponent, ModuleName.empty())) + return true; + ModuleName.push_back(NameComponent); + + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::period)) + return false; + } +} + void Preprocessor::HandlePragmaModuleBuild(Token &Tok) { SourceLocation Loc = Tok.getLocation(); - LexUnexpandedToken(Tok); - if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) { - Diag(Tok.getLocation(), diag::err_pp_expected_module_name) << true; + std::pair ModuleNameLoc; + if (LexModuleNameComponent(*this, Tok, ModuleNameLoc, true)) return; - } - IdentifierInfo *ModuleName = Tok.getIdentifierInfo(); + IdentifierInfo *ModuleName = ModuleNameLoc.first; LexUnexpandedToken(Tok); if (Tok.isNot(tok::eod)) { @@ -1383,26 +1421,6 @@ struct PragmaMessageHandler : public PragmaHandler { } }; -static bool LexModuleName( - Preprocessor &PP, Token &Tok, - llvm::SmallVectorImpl> - &ModuleName) { - while (true) { - PP.LexUnexpandedToken(Tok); - if (Tok.isAnnotation() || !Tok.getIdentifierInfo()) { - PP.Diag(Tok.getLocation(), diag::err_pp_expected_module_name) - << ModuleName.empty(); - return true; - } - - ModuleName.emplace_back(Tok.getIdentifierInfo(), Tok.getLocation()); - - PP.LexUnexpandedToken(Tok); - if (Tok.isNot(tok::period)) - return false; - } -} - /// Handle the clang \#pragma module import extension. The syntax is: /// \code /// #pragma clang module import some.module.name @@ -1473,7 +1491,7 @@ struct PragmaModuleBeginHandler : public PragmaHandler { // be loaded or implicitly loadable. // FIXME: We could create the submodule here. We'd need to know whether // it's supposed to be explicit, but not much else. - Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule(Current); + Module *M = PP.getHeaderSearchInfo().lookupModule(Current); if (!M) { PP.Diag(ModuleName.front().second, diag::err_pp_module_begin_no_module_map) << Current; diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 22696a957a10..d0ce9fc89583 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -2629,6 +2629,8 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { return DSC_class; if (Context == Declarator::FileContext) return DSC_top_level; + if (Context == Declarator::TemplateParamContext) + return DSC_template_param; if (Context == Declarator::TemplateTypeArgContext) return DSC_template_type_arg; if (Context == Declarator::TrailingReturnContext) @@ -4261,7 +4263,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, AS, DS.getModulePrivateSpecLoc(), TParams, Owned, IsDependent, ScopedEnumKWLoc, IsScopedUsingClassTag, BaseType, - DSC == DSC_type_specifier, &SkipBody); + DSC == DSC_type_specifier, + DSC == DSC_template_param || + DSC == DSC_template_type_arg, &SkipBody); if (SkipBody.ShouldSkip) { assert(TUK == Sema::TUK_Definition && "can only skip a definition"); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index 1a4607a84cff..a724fa242268 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -1887,7 +1887,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation(), false, clang::TypeResult(), DSC == DSC_type_specifier, - &SkipBody); + DSC == DSC_template_param || + DSC == DSC_template_type_arg, &SkipBody); // If ActOnTag said the type was dependent, try again with the // less common call. diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp index 77e63efc065e..caa6323d3209 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp @@ -3627,6 +3627,14 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { SourceLocation OrigLoc = Tok.getLocation(); assert(!LM.Toks.empty() && "ParseLexedObjCMethodDef - Empty body!"); + // Store an artificial EOF token to ensure that we don't run off the end of + // the method's body when we come to parse it. + Token Eof; + Eof.startToken(); + Eof.setKind(tok::eof); + Eof.setEofData(MCDecl); + Eof.setLocation(OrigLoc); + LM.Toks.push_back(Eof); // Append the current token at the end of the new token stream so that it // doesn't get lost. LM.Toks.push_back(Tok); @@ -3658,7 +3666,7 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { Actions.ActOnDefaultCtorInitializers(MCDecl); ParseFunctionStatementBody(MCDecl, BodyScope); } - + if (Tok.getLocation() != OrigLoc) { // Due to parsing error, we either went over the cached tokens or // there are still cached tokens left. If it's the latter case skip the @@ -3670,4 +3678,6 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) { while (Tok.getLocation() != OrigLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); } + // Clean up the remaining EOF token. + ConsumeAnyToken(); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp index 37c80fe5e520..944cd775d52a 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp @@ -674,7 +674,8 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // FIXME: The type should probably be restricted in some way... Not all // declarators (parts of declarators?) are accepted for parameters. DeclSpec DS(AttrFactory); - ParseDeclarationSpecifiers(DS); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, + DSC_template_param); // Parse this as a typename. Declarator ParamDecl(DS, Declarator::TemplateParamContext); diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index db688b12cbcf..934e13e72d05 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -278,6 +278,150 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, S.Diag(Body->getLocStart(), diag::warn_infinite_recursive_function); } +//===----------------------------------------------------------------------===// +// Check for throw in a non-throwing function. +//===----------------------------------------------------------------------===// +enum ThrowState { + FoundNoPathForThrow, + FoundPathForThrow, + FoundPathWithNoThrowOutFunction, +}; + +static bool isThrowCaught(const CXXThrowExpr *Throw, + const CXXCatchStmt *Catch) { + const Type *ThrowType = nullptr; + if (Throw->getSubExpr()) + ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull(); + if (!ThrowType) + return false; + const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull(); + if (!CaughtType) + return true; + if (ThrowType->isReferenceType()) + ThrowType = ThrowType->castAs() + ->getPointeeType() + ->getUnqualifiedDesugaredType(); + if (CaughtType->isReferenceType()) + CaughtType = CaughtType->castAs() + ->getPointeeType() + ->getUnqualifiedDesugaredType(); + if (CaughtType == ThrowType) + return true; + const CXXRecordDecl *CaughtAsRecordType = + CaughtType->getPointeeCXXRecordDecl(); + const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl(); + if (CaughtAsRecordType && ThrowTypeAsRecordType) + return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType); + return false; +} + +static bool isThrowCaughtByHandlers(const CXXThrowExpr *CE, + const CXXTryStmt *TryStmt) { + for (unsigned H = 0, E = TryStmt->getNumHandlers(); H < E; ++H) { + if (isThrowCaught(CE, TryStmt->getHandler(H))) + return true; + } + return false; +} + +static bool doesThrowEscapePath(CFGBlock Block, SourceLocation &OpLoc) { + for (const auto &B : Block) { + if (B.getKind() != CFGElement::Statement) + continue; + const auto *CE = dyn_cast(B.getAs()->getStmt()); + if (!CE) + continue; + + OpLoc = CE->getThrowLoc(); + for (const auto &I : Block.succs()) { + if (!I.isReachable()) + continue; + if (const auto *Terminator = + dyn_cast_or_null(I->getTerminator())) + if (isThrowCaughtByHandlers(CE, Terminator)) + return false; + } + return true; + } + return false; +} + +static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) { + + unsigned ExitID = BodyCFG->getExit().getBlockID(); + + SmallVector States(BodyCFG->getNumBlockIDs(), + FoundNoPathForThrow); + States[BodyCFG->getEntry().getBlockID()] = FoundPathWithNoThrowOutFunction; + + SmallVector Stack; + Stack.push_back(&BodyCFG->getEntry()); + while (!Stack.empty()) { + CFGBlock *CurBlock = Stack.back(); + Stack.pop_back(); + + unsigned ID = CurBlock->getBlockID(); + ThrowState CurState = States[ID]; + if (CurState == FoundPathWithNoThrowOutFunction) { + if (ExitID == ID) + continue; + + if (doesThrowEscapePath(*CurBlock, OpLoc)) + CurState = FoundPathForThrow; + } + + // Loop over successor blocks and add them to the Stack if their state + // changes. + for (const auto &I : CurBlock->succs()) + if (I.isReachable()) { + unsigned NextID = I->getBlockID(); + if (NextID == ExitID && CurState == FoundPathForThrow) { + States[NextID] = CurState; + } else if (States[NextID] < CurState) { + States[NextID] = CurState; + Stack.push_back(I); + } + } + } + // Return true if the exit node is reachable, and only reachable through + // a throw expression. + return States[ExitID] == FoundPathForThrow; +} + +static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, + const FunctionDecl *FD) { + if (!S.getSourceManager().isInSystemHeader(OpLoc)) { + S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD; + if (S.getLangOpts().CPlusPlus11 && + (isa(FD) || + FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || + FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) + S.Diag(FD->getLocation(), diag::note_throw_in_dtor); + else + S.Diag(FD->getLocation(), diag::note_throw_in_function); + } +} + +static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, + AnalysisDeclContext &AC) { + CFG *BodyCFG = AC.getCFG(); + if (!BodyCFG) + return; + if (BodyCFG->getExit().pred_empty()) + return; + SourceLocation OpLoc; + if (hasThrowOutNonThrowingFunc(OpLoc, BodyCFG)) + EmitDiagForCXXThrowInNonThrowingFunc(S, OpLoc, FD); +} + +static bool isNoexcept(const FunctionDecl *FD) { + const auto *FPT = FD->getType()->castAs(); + if (FPT->getExceptionSpecType() != EST_None && + FPT->isNothrow(FD->getASTContext())) + return true; + return false; +} + //===----------------------------------------------------------------------===// // Check for missing return value. //===----------------------------------------------------------------------===// @@ -2127,6 +2271,12 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, } } + // Check for throw out of non-throwing function. + if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getLocStart())) + if (const FunctionDecl *FD = dyn_cast(D)) + if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) + checkThrowInNonThrowingFunc(S, FD, AC); + // If none of the previous checks caused a CFG build, trigger one here // for -Wtautological-overlap-compare if (!Diags.isIgnored(diag::warn_tautological_overlap_comparison, diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp index e7b0914641ff..007a5e483e6c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp @@ -740,6 +740,9 @@ void Sema::ActOnEndOfTranslationUnit() { // Load pending instantiations from the external source. SmallVector Pending; ExternalSource->ReadPendingInstantiations(Pending); + for (auto PII : Pending) + if (auto Func = dyn_cast(PII.first)) + Func->setInstantiationIsPending(true); PendingInstantiations.insert(PendingInstantiations.begin(), Pending.begin(), Pending.end()); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp index b938ac387c4d..cac5f682275e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp @@ -629,12 +629,6 @@ static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) { // emitted, because (say) the definition could include "inline". FunctionDecl *Def = FD->getDefinition(); - // We may currently be parsing the body of FD, in which case - // FD->getDefinition() will be null, but we still want to treat FD as though - // it's a definition. - if (!Def && FD->willHaveBody()) - Def = FD; - if (Def && !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def))) return true; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index cba220daf774..e340456bc6da 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -7260,11 +7260,11 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { NewVD->setInvalidDecl(); return; } - // OpenCL v1.1 s6.5.2 and s6.5.3 no local or constant variables - // in functions. if (T.getAddressSpace() == LangAS::opencl_constant || T.getAddressSpace() == LangAS::opencl_local) { FunctionDecl *FD = getCurFunctionDecl(); + // OpenCL v1.1 s6.5.2 and s6.5.3: no local or constant variables + // in functions. if (FD && !FD->hasAttr()) { if (T.getAddressSpace() == LangAS::opencl_constant) Diag(NewVD->getLocation(), diag::err_opencl_function_variable) @@ -7275,6 +7275,20 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { NewVD->setInvalidDecl(); return; } + // OpenCL v2.0 s6.5.2 and s6.5.3: local and constant variables must be + // in the outermost scope of a kernel function. + if (FD && FD->hasAttr()) { + if (!getCurScope()->isFunctionScope()) { + if (T.getAddressSpace() == LangAS::opencl_constant) + Diag(NewVD->getLocation(), diag::err_opencl_addrspace_scope) + << "constant"; + else + Diag(NewVD->getLocation(), diag::err_opencl_addrspace_scope) + << "local"; + NewVD->setInvalidDecl(); + return; + } + } } else if (T.getAddressSpace() != LangAS::Default) { // Do not allow other address spaces on automatic variable. Diag(NewVD->getLocation(), diag::err_as_qualified_auto_decl) << 1; @@ -12218,6 +12232,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD) { FD->setBody(Body); + FD->setWillHaveBody(false); if (getLangOpts().CPlusPlus14) { if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && @@ -13075,7 +13090,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, - bool IsTypeSpecifier, SkipBodyInfo *SkipBody) { + bool IsTypeSpecifier, bool IsTemplateParamOrArg, + SkipBodyInfo *SkipBody) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != nullptr || TUK == TUK_Definition) && @@ -13345,11 +13361,11 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // also need to do a redeclaration lookup there, just in case // there's a shadow friend decl. if (Name && Previous.empty() && - (TUK == TUK_Reference || TUK == TUK_Friend)) { + (TUK == TUK_Reference || TUK == TUK_Friend || IsTemplateParamOrArg)) { if (Invalid) goto CreateNewDecl; assert(SS.isEmpty()); - if (TUK == TUK_Reference) { + if (TUK == TUK_Reference || IsTemplateParamOrArg) { // C++ [basic.scope.pdecl]p5: // -- for an elaborated-type-specifier of the form // @@ -13782,7 +13798,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // C++11 [dcl.type]p3: // A type-specifier-seq shall not define a class or enumeration [...]. - if (getLangOpts().CPlusPlus && IsTypeSpecifier && TUK == TUK_Definition) { + if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) && + TUK == TUK_Definition) { Diag(New->getLocation(), diag::err_type_defined_in_type_specifier) << Context.getTagDeclType(New); Invalid = true; @@ -16089,7 +16106,10 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { // lexically within the module. if (getLangOpts().trackLocalOwningModule()) { for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) { - cast(DC)->setHidden(true); + cast(DC)->setModuleOwnershipKind( + getLangOpts().ModulesLocalVisibility + ? Decl::ModuleOwnershipKind::VisibleWhenImported + : Decl::ModuleOwnershipKind::Visible); cast(DC)->setLocalOwningModule(Mod); } } @@ -16129,7 +16149,8 @@ void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) { for (auto *DC = CurContext; DC; DC = DC->getLexicalParent()) { cast(DC)->setLocalOwningModule(getCurrentModule()); if (!getCurrentModule()) - cast(DC)->setHidden(false); + cast(DC)->setModuleOwnershipKind( + Decl::ModuleOwnershipKind::Unowned); } } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index b43642f5493b..e8503427536d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -6903,6 +6903,32 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, return true; } +static bool +shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, + const VersionTuple &DeploymentVersion, + const VersionTuple &DeclVersion) { + const auto &Triple = Context.getTargetInfo().getTriple(); + VersionTuple ForceAvailabilityFromVersion; + switch (Triple.getOS()) { + case llvm::Triple::IOS: + case llvm::Triple::TvOS: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11); + break; + case llvm::Triple::WatchOS: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4); + break; + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13); + break; + default: + // New targets should always warn about availability. + return Triple.getVendor() == llvm::Triple::Apple; + } + return DeploymentVersion >= ForceAvailabilityFromVersion || + DeclVersion >= ForceAvailabilityFromVersion; +} + static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, @@ -6991,13 +7017,26 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } break; - case AR_NotYetIntroduced: - diag = diag::warn_partial_availability; - diag_message = diag::warn_partial_message; - diag_fwdclass_message = diag::warn_partial_fwdclass_message; + case AR_NotYetIntroduced: { + // We would like to emit the diagnostic even if -Wunguarded-availability is + // not specified for deployment targets >= to iOS 11 or equivalent or + // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or + // later. + const AvailabilityAttr *AA = getAttrForPlatform(S.getASTContext(), D); + VersionTuple Introduced = AA->getIntroduced(); + bool NewWarning = shouldDiagnoseAvailabilityByDefault( + S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), + Introduced); + diag = NewWarning ? diag::warn_partial_availability_new + : diag::warn_partial_availability; + diag_message = NewWarning ? diag::warn_partial_message_new + : diag::warn_partial_message; + diag_fwdclass_message = NewWarning ? diag::warn_partial_fwdclass_message_new + : diag::warn_partial_fwdclass_message; property_note_select = /* partial */ 2; available_here_select_kind = /* partial */ 3; break; + } case AR_Available: llvm_unreachable("Warning for availability of available declaration?"); @@ -7317,7 +7356,18 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx)) return; - SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability) + // We would like to emit the diagnostic even if -Wunguarded-availability is + // not specified for deployment targets >= to iOS 11 or equivalent or + // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or + // later. + unsigned DiagKind = + shouldDiagnoseAvailabilityByDefault( + SemaRef.Context, + SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced) + ? diag::warn_unguarded_availability_new + : diag::warn_unguarded_availability; + + SemaRef.Diag(Range.getBegin(), DiagKind) << Range << D << AvailabilityAttr::getPrettyPlatformName( SemaRef.getASTContext().getTargetInfo().getPlatformName()) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index 844299bb87cf..453ece9d9c4d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -13394,7 +13394,8 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, /*ScopedEnumKWLoc=*/SourceLocation(), /*ScopedEnumUsesClassTag=*/false, /*UnderlyingType=*/TypeResult(), - /*IsTypeSpecifier=*/false); + /*IsTypeSpecifier=*/false, + /*IsTemplateParamOrArg=*/false); } NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); @@ -13878,6 +13879,9 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { return; } + // Deleted function does not have a body. + Fn->setWillHaveBody(false); + if (const FunctionDecl *Prev = Fn->getPreviousDecl()) { // Don't consider the implicit declaration we generate for explicit // specializations. FIXME: Do not generate these implicit declarations. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 75a6903392ea..f49df6b3216d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -13732,6 +13732,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // call to such a function. InstantiateFunctionDefinition(PointOfInstantiation, Func); else { + Func->setInstantiationIsPending(true); PendingInstantiations.push_back(std::make_pair(Func, PointOfInstantiation)); // Notify the consumer that a function was implicitly instantiated. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index a9ff21bc41ab..710ead30790f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -2630,7 +2630,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, // Make the function visible to name lookup, even if we found it in // an unimported module. It either is an implicitly-declared global // allocation function, or is suppressing that function. - Func->setHidden(false); + Func->setVisibleDespiteOwningModule(); return; } } @@ -2662,7 +2662,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, FnType, /*TInfo=*/nullptr, SC_None, false, true); Alloc->setImplicit(); // Global allocation functions should always be visible. - Alloc->setHidden(false); + Alloc->setVisibleDespiteOwningModule(); // Implicit sized deallocation functions always have default visibility. Alloc->addAttr( diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index 1fb25f4e0e7c..2e7fb875a276 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -862,6 +862,16 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { if (!Record->isCompleteDefinition()) return Found; + // For conversion operators, 'operator auto' should only match + // 'operator auto'. Since 'auto' is not a type, it shouldn't be considered + // as a candidate for template substitution. + auto *ContainedDeducedType = + R.getLookupName().getCXXNameType()->getContainedDeducedType(); + if (R.getLookupName().getNameKind() == + DeclarationName::CXXConversionFunctionName && + ContainedDeducedType && ContainedDeducedType->isUndeducedType()) + return Found; + for (CXXRecordDecl::conversion_iterator U = Record->conversion_begin(), UEnd = Record->conversion_end(); U != UEnd; ++U) { FunctionTemplateDecl *ConvTemplate = dyn_cast(*U); @@ -1331,7 +1341,7 @@ void Sema::makeMergedDefinitionVisible(NamedDecl *ND) { Context.mergeDefinitionIntoModule(ND, M); else // We're not building a module; just make the definition visible. - ND->setHidden(false); + ND->setVisibleDespiteOwningModule(); // If ND is a template declaration, make the template parameters // visible too. They're not (necessarily) within a mergeable DeclContext. @@ -1518,7 +1528,7 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { !SemaRef.getLangOpts().ModulesLocalVisibility) { // Cache the fact that this declaration is implicitly visible because // its parent has a visible definition. - D->setHidden(false); + D->setVisibleDespiteOwningModule(); } return true; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index 1eea151a4ec8..a8923ce9e27d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -8612,7 +8612,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, SourceLocation(), false, TypeResult(), - /*IsTypeSpecifier*/false); + /*IsTypeSpecifier*/false, + /*IsTemplateParamOrArg*/false); assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); if (!TagD) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp index fe92dd8ac653..f4f0c804aee1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2045,7 +2045,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // The instantiation is visible here, even if it was first declared in an // unimported module. - Instantiation->setHidden(false); + Instantiation->setVisibleDespiteOwningModule(); // FIXME: This loses the as-written tag kind for an explicit instantiation. Instantiation->setTagKind(Pattern->getTagKind()); @@ -2247,7 +2247,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, // The instantiation is visible here, even if it was first declared in an // unimported module. - Instantiation->setHidden(false); + Instantiation->setVisibleDespiteOwningModule(); // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 148ce24293a0..abe912fb548b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1782,6 +1782,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Previous.clear(); } + if (isFriend) + Function->setObjectOfFriendDecl(); + SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous, isExplicitSpecialization); @@ -3782,6 +3785,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Try again at the end of the translation unit (at which point a // definition will be required). assert(!Recursive); + Function->setInstantiationIsPending(true); PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); } else if (TSK == TSK_ImplicitInstantiation) { @@ -3801,6 +3805,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Postpone late parsed template instantiations. if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) { + Function->setInstantiationIsPending(true); PendingInstantiations.push_back( std::make_pair(Function, PointOfInstantiation)); return; @@ -3863,7 +3868,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // The instantiation is visible here, even if it was first declared in an // unimported module. - Function->setHidden(false); + Function->setVisibleDespiteOwningModule(); // Copy the inner loc start from the pattern. Function->setInnerLocStart(PatternDecl->getInnerLocStart()); @@ -4269,7 +4274,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // The instantiation is visible here, even if it was first declared in an // unimported module. - Var->setHidden(false); + Var->setVisibleDespiteOwningModule(); // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate @@ -4285,9 +4290,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, InstantiateVariableInitializer(Var, PatternDecl, TemplateArgs); PreviousContext.pop(); - // FIXME: Need to inform the ASTConsumer that we instantiated the - // initializer? - // This variable may have local implicit instantiations that need to be // instantiated within this scope. LocalInstantiations.perform(); @@ -4397,7 +4399,6 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (Def->isStaticDataMember() && !Def->isOutOfLine()) { // We're instantiating an inline static data member whose definition was // provided inside the class. - // FIXME: Update record? InstantiateVariableInitializer(Var, Def, TemplateArgs); } else if (!VarSpec) { Var = cast_or_null(SubstDecl(Def, Var->getDeclContext(), @@ -5146,6 +5147,8 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true, DefinitionRequired, true); + if (Function->isDefined()) + Function->setInstantiationIsPending(false); continue; } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp index eeb0132c1690..ef2841849ff6 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp @@ -3580,8 +3580,8 @@ static void moveMethodToBackOfGlobalList(Sema &S, ObjCMethodDecl *Method) { void ASTReader::makeNamesVisible(const HiddenNames &Names, Module *Owner) { assert(Owner->NameVisibility != Module::Hidden && "nothing to make visible?"); for (Decl *D : Names) { - bool wasHidden = D->Hidden; - D->Hidden = false; + bool wasHidden = D->isHidden(); + D->setVisibleDespiteOwningModule(); if (wasHidden && SemaObj) { if (ObjCMethodDecl *Method = dyn_cast(D)) { @@ -3648,7 +3648,7 @@ void ASTReader::mergeDefinitionVisibility(NamedDecl *Def, if (Def->isHidden()) { // If MergedDef is visible or becomes visible, make the definition visible. if (!MergedDef->isHidden()) - Def->Hidden = false; + Def->setVisibleDespiteOwningModule(); else if (getContext().getLangOpts().ModulesLocalVisibility) { getContext().mergeDefinitionIntoModule( Def, MergedDef->getImportedOwningModule(), @@ -9324,9 +9324,20 @@ void ASTReader::diagnoseOdrViolations() { diag::err_module_odr_violation_different_definitions) << FirstRecord << FirstModule.empty() << FirstModule; + if (FirstDecl) { + Diag(FirstDecl->getLocation(), diag::note_first_module_difference) + << FirstRecord << FirstDecl->getSourceRange(); + } + Diag(SecondRecord->getLocation(), diag::note_module_odr_violation_different_definitions) << SecondModule; + + if (SecondDecl) { + Diag(SecondDecl->getLocation(), diag::note_second_module_difference) + << SecondDecl->getSourceRange(); + } + Diagnosed = true; break; } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp index ed103e629216..07ab421cfc51 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp @@ -522,31 +522,29 @@ void ASTDeclReader::VisitDecl(Decl *D) { D->setTopLevelDeclInObjCContainer(Record.readInt()); D->setAccess((AccessSpecifier)Record.readInt()); D->FromASTFile = true; - D->setModulePrivate(Record.readInt()); - D->Hidden = D->isModulePrivate(); + bool ModulePrivate = Record.readInt(); // Determine whether this declaration is part of a (sub)module. If so, it // may not yet be visible. if (unsigned SubmoduleID = readSubmoduleID()) { // Store the owning submodule ID in the declaration. + D->setModuleOwnershipKind( + ModulePrivate ? Decl::ModuleOwnershipKind::ModulePrivate + : Decl::ModuleOwnershipKind::VisibleWhenImported); D->setOwningModuleID(SubmoduleID); - if (D->Hidden) { - // Module-private declarations are never visible, so there is no work to do. + if (ModulePrivate) { + // Module-private declarations are never visible, so there is no work to + // do. } else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) { // If local visibility is being tracked, this declaration will become - // hidden and visible as the owning module does. Inform Sema that this - // declaration might not be visible. - D->Hidden = true; + // hidden and visible as the owning module does. } else if (Module *Owner = Reader.getSubmodule(SubmoduleID)) { - if (Owner->NameVisibility != Module::AllVisible) { - // The owning module is not visible. Mark this declaration as hidden. - D->Hidden = true; - - // Note that this declaration was hidden because its owning module is - // not yet visible. + // Mark the declaration as visible when its owning module becomes visible. + if (Owner->NameVisibility == Module::AllVisible) + D->setVisibleDespiteOwningModule(); + else Reader.HiddenNamesMap[Owner].push_back(D); - } } } } @@ -3934,10 +3932,21 @@ void ASTDeclReader::UpdateDecl(Decl *D) { break; } - case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: - cast(D)->getMemberSpecializationInfo()->setPointOfInstantiation( + case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: { + VarDecl *VD = cast(D); + VD->getMemberSpecializationInfo()->setPointOfInstantiation( ReadSourceLocation()); + uint64_t Val = Record.readInt(); + if (Val && !VD->getInit()) { + VD->setInit(Record.readExpr()); + if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3 + EvaluatedStmt *Eval = VD->ensureEvaluatedStmt(); + Eval->CheckedICE = true; + Eval->IsICE = Val == 3; + } + } break; + } case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: { auto Param = cast(D); @@ -4133,7 +4142,7 @@ void ASTDeclReader::UpdateDecl(Decl *D) { Reader.HiddenNamesMap[Owner].push_back(Exported); } else { // The declaration is now visible. - Exported->Hidden = false; + Exported->setVisibleDespiteOwningModule(); } break; } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index dcacabec1225..1c0db14ced14 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -5033,9 +5033,18 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { case UPD_CXX_ADDED_FUNCTION_DEFINITION: break; - case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: + case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: { + const VarDecl *VD = cast(D); Record.AddSourceLocation(Update.getLoc()); + if (VD->getInit()) { + Record.push_back(!VD->isInitKnownICE() ? 1 + : (VD->isInitICE() ? 3 : 2)); + Record.AddStmt(const_cast(VD->getInit())); + } else { + Record.push_back(0); + } break; + } case UPD_CXX_INSTANTIATED_DEFAULT_ARGUMENT: Record.AddStmt(const_cast( diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index 48d6cd8a527c..097d4198800d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -50,8 +50,10 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE, state = state->assume(ArgSVal.castAs(), true); // FIXME: do we want to warn here? Not right now. The most reports might // come from infeasible paths, thus being false positives. - if (!state) + if (!state) { + C.generateSink(C.getState(), C.getPredecessor()); return true; + } C.addTransition(state); return true; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 32e3ce9270aa..77c24629d71e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -120,6 +120,7 @@ class CStringChecker : public Checker< eval::Call, void evalStdCopy(CheckerContext &C, const CallExpr *CE) const; void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const; void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const; + void evalMemset(CheckerContext &C, const CallExpr *CE) const; // Utility methods std::pair @@ -1999,6 +2000,54 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C, C.addTransition(State); } +void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const { + if (CE->getNumArgs() != 3) + return; + + CurrentFunctionDescription = "memory set function"; + + const Expr *Mem = CE->getArg(0); + const Expr *Size = CE->getArg(2); + ProgramStateRef State = C.getState(); + + // See if the size argument is zero. + const LocationContext *LCtx = C.getLocationContext(); + SVal SizeVal = State->getSVal(Size, LCtx); + QualType SizeTy = Size->getType(); + + ProgramStateRef StateZeroSize, StateNonZeroSize; + std::tie(StateZeroSize, StateNonZeroSize) = + assumeZero(C, State, SizeVal, SizeTy); + + // Get the value of the memory area. + SVal MemVal = State->getSVal(Mem, LCtx); + + // If the size is zero, there won't be any actual memory access, so + // just bind the return value to the Mem buffer and return. + if (StateZeroSize && !StateNonZeroSize) { + StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal); + C.addTransition(StateZeroSize); + return; + } + + // Ensure the memory area is not null. + // If it is NULL there will be a NULL pointer dereference. + State = checkNonNull(C, StateNonZeroSize, Mem, MemVal); + if (!State) + return; + + State = CheckBufferAccess(C, State, Size, Mem); + if (!State) + return; + State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem), + /*IsSourceBuffer*/false, Size); + if (!State) + return; + + State = State->BindExpr(CE, LCtx, MemVal); + C.addTransition(State); +} + static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name) { IdentifierInfo *II = FD->getIdentifier(); if (!II) @@ -2032,6 +2081,8 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { evalFunction = &CStringChecker::evalMemcmp; else if (C.isCLibraryFunction(FDecl, "memmove")) evalFunction = &CStringChecker::evalMemmove; + else if (C.isCLibraryFunction(FDecl, "memset")) + evalFunction = &CStringChecker::evalMemset; else if (C.isCLibraryFunction(FDecl, "strcpy")) evalFunction = &CStringChecker::evalStrcpy; else if (C.isCLibraryFunction(FDecl, "strncpy")) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp index 1885b0e39203..83955c586b68 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp @@ -73,12 +73,17 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU, bool ReportNormalClones = Mgr.getAnalyzerOptions().getBooleanOption( "ReportNormalClones", true, this); + StringRef IgnoredFilesPattern = Mgr.getAnalyzerOptions().getOptionAsString( + "IgnoredFilesPattern", "", this); + // Let the CloneDetector create a list of clones from all the analyzed // statements. We don't filter for matching variable patterns at this point // because reportSuspiciousClones() wants to search them for errors. std::vector AllCloneGroups; - Detector.findClones(AllCloneGroups, RecursiveCloneTypeIIConstraint(), + Detector.findClones(AllCloneGroups, + FilenamePatternConstraint(IgnoredFilesPattern), + RecursiveCloneTypeIIConstraint(), MinComplexityConstraint(MinComplexity), MinGroupSizeConstraint(2), OnlyLargestCloneConstraint()); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp index af35c2b0e991..6bbaaac05e6b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp @@ -281,6 +281,9 @@ void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const { IdentifierInfo *setLabelNSSegmentedControl[] = { &Ctx.Idents.get("setLabel"), &Ctx.Idents.get("forSegment")}; ADD_METHOD(NSSegmentedControl, setLabelNSSegmentedControl, 2, 0) + IdentifierInfo *setToolTipNSSegmentedControl[] = { + &Ctx.Idents.get("setToolTip"), &Ctx.Idents.get("forSegment")}; + ADD_METHOD(NSSegmentedControl, setToolTipNSSegmentedControl, 2, 0) NEW_RECEIVER(NSButtonCell) ADD_UNARY_METHOD(NSButtonCell, setTitle, 0) @@ -562,6 +565,46 @@ void NonLocalizedStringChecker::initUIMethods(ASTContext &Ctx) const { IdentifierInfo *setTitleUISegmentedControl[] = { &Ctx.Idents.get("setTitle"), &Ctx.Idents.get("forSegmentAtIndex")}; ADD_METHOD(UISegmentedControl, setTitleUISegmentedControl, 2, 0) + + NEW_RECEIVER(NSAccessibilityCustomRotorItemResult) + IdentifierInfo + *initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult[] = { + &Ctx.Idents.get("initWithItemLoadingToken"), + &Ctx.Idents.get("customLabel")}; + ADD_METHOD(NSAccessibilityCustomRotorItemResult, + initWithItemLoadingTokenNSAccessibilityCustomRotorItemResult, 2, 1) + ADD_UNARY_METHOD(NSAccessibilityCustomRotorItemResult, setCustomLabel, 0) + + NEW_RECEIVER(UIContextualAction) + IdentifierInfo *contextualActionWithStyleUIContextualAction[] = { + &Ctx.Idents.get("contextualActionWithStyle"), &Ctx.Idents.get("title"), + &Ctx.Idents.get("handler")}; + ADD_METHOD(UIContextualAction, contextualActionWithStyleUIContextualAction, 3, + 1) + ADD_UNARY_METHOD(UIContextualAction, setTitle, 0) + + NEW_RECEIVER(NSAccessibilityCustomRotor) + IdentifierInfo *initWithLabelNSAccessibilityCustomRotor[] = { + &Ctx.Idents.get("initWithLabel"), &Ctx.Idents.get("itemSearchDelegate")}; + ADD_METHOD(NSAccessibilityCustomRotor, + initWithLabelNSAccessibilityCustomRotor, 2, 0) + ADD_UNARY_METHOD(NSAccessibilityCustomRotor, setLabel, 0) + + NEW_RECEIVER(NSWindowTab) + ADD_UNARY_METHOD(NSWindowTab, setTitle, 0) + ADD_UNARY_METHOD(NSWindowTab, setToolTip, 0) + + NEW_RECEIVER(NSAccessibilityCustomAction) + IdentifierInfo *initWithNameNSAccessibilityCustomAction[] = { + &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("handler")}; + ADD_METHOD(NSAccessibilityCustomAction, + initWithNameNSAccessibilityCustomAction, 2, 0) + IdentifierInfo *initWithNameTargetNSAccessibilityCustomAction[] = { + &Ctx.Idents.get("initWithName"), &Ctx.Idents.get("target"), + &Ctx.Idents.get("selector")}; + ADD_METHOD(NSAccessibilityCustomAction, + initWithNameTargetNSAccessibilityCustomAction, 3, 0) + ADD_UNARY_METHOD(NSAccessibilityCustomAction, setName, 0) } #define LSF_INSERT(function_name) LSF.insert(&Ctx.Idents.get(function_name)); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 45ef612ee1d5..11b9f8c4f725 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -293,7 +293,7 @@ unsigned AnalyzerOptions::getMaxInlinableSize() { DefaultValue = 4; break; case UMK_Deep: - DefaultValue = 50; + DefaultValue = 100; break; } @@ -332,7 +332,7 @@ unsigned AnalyzerOptions::getMaxNodesPerTopLevelFunction() { DefaultValue = 75000; break; case UMK_Deep: - DefaultValue = 150000; + DefaultValue = 225000; break; } MaxNodesPerTopLevelFunction = getOptionAsInteger("max-nodes", DefaultValue); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 8f720a2067b1..6f1e8391e67c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -980,10 +980,9 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, // transfer functions as "0 == E". SVal Result; if (Optional LV = V.getAs()) { - Loc X = svalBuilder.makeNull(); + Loc X = svalBuilder.makeNullWithType(Ex->getType()); Result = evalBinOp(state, BO_EQ, *LV, X, U->getType()); - } - else if (Ex->getType()->isFloatingType()) { + } else if (Ex->getType()->isFloatingType()) { // FIXME: handle floating point types. Result = UnknownVal(); } else { diff --git a/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp b/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp index 37c14f4a26e1..2fc2b508ef21 100644 --- a/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp +++ b/contrib/llvm/tools/clang/tools/driver/cc1as_main.cpp @@ -202,9 +202,22 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels); // Any DebugInfoKind implies GenDwarfForAssembly. Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ); - // TODO: base this on -gz instead - if (Args.hasArg(OPT_compress_debug_sections)) - Opts.CompressDebugSections = llvm::DebugCompressionType::GNU; + + if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, + OPT_compress_debug_sections_EQ)) { + if (A->getOption().getID() == OPT_compress_debug_sections) { + // TODO: be more clever about the compression type auto-detection + Opts.CompressDebugSections = llvm::DebugCompressionType::GNU; + } else { + Opts.CompressDebugSections = + llvm::StringSwitch(A->getValue()) + .Case("none", llvm::DebugCompressionType::None) + .Case("zlib", llvm::DebugCompressionType::Z) + .Case("zlib-gnu", llvm::DebugCompressionType::GNU) + .Default(llvm::DebugCompressionType::None); + } + } + Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations); Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); diff --git a/contrib/llvm/tools/clang/tools/driver/driver.cpp b/contrib/llvm/tools/clang/tools/driver/driver.cpp index 4bd3b228d0ff..af25d9598021 100644 --- a/contrib/llvm/tools/clang/tools/driver/driver.cpp +++ b/contrib/llvm/tools/clang/tools/driver/driver.cpp @@ -53,8 +53,15 @@ using namespace clang::driver; using namespace llvm::opt; std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) { - if (!CanonicalPrefixes) - return Argv0; + if (!CanonicalPrefixes) { + SmallString<128> ExecutablePath(Argv0); + // Do a PATH lookup if Argv0 isn't a valid path. + if (!llvm::sys::fs::exists(ExecutablePath)) + if (llvm::ErrorOr P = + llvm::sys::findProgramByName(ExecutablePath)) + ExecutablePath = *P; + return ExecutablePath.str(); + } // This just needs to be some symbol in the binary; C++ doesn't // allow taking the address of ::main however. diff --git a/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp b/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp index 49c1edce3220..62fcccbacb55 100644 --- a/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp +++ b/contrib/llvm/tools/clang/utils/TableGen/NeonEmitter.cpp @@ -860,6 +860,10 @@ void Type::applyModifier(char Mod) { Float = true; ElementBitwidth = 64; break; + case 'H': + Float = true; + ElementBitwidth = 16; + break; case 'g': if (AppliedQuad) Bitwidth /= 2; @@ -1006,7 +1010,7 @@ std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) const { } static bool isFloatingPointProtoModifier(char Mod) { - return Mod == 'F' || Mod == 'f'; + return Mod == 'F' || Mod == 'f' || Mod == 'H'; } std::string Intrinsic::getBuiltinTypeStr() { diff --git a/contrib/llvm/tools/lld/COFF/Chunks.cpp b/contrib/llvm/tools/lld/COFF/Chunks.cpp index 359dbe69559f..56124acaf9a1 100644 --- a/contrib/llvm/tools/lld/COFF/Chunks.cpp +++ b/contrib/llvm/tools/lld/COFF/Chunks.cpp @@ -37,8 +37,14 @@ SectionChunk::SectionChunk(ObjectFile *F, const coff_section *H) Align = Header->getAlignment(); - // Only COMDAT sections are subject of dead-stripping. - Live = !isCOMDAT(); + // Chunks may be discarded during comdat merging. + Discarded = false; + + // If linker GC is disabled, every chunk starts out alive. If linker GC is + // enabled, treat non-comdat sections as roots. Generally optimized object + // files will be built with -ffunction-sections or /Gy, so most things worth + // stripping will be in a comdat. + Live = !Config->DoGC || !isCOMDAT(); } static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } @@ -46,6 +52,15 @@ static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } +static void applySecRel(const SectionChunk *Sec, uint8_t *Off, Defined *Sym) { + // Don't apply section relative relocations to absolute symbols in codeview + // debug info sections. MSVC does not treat such relocations as fatal errors, + // and they can be found in the standard library for linker-provided symbols + // like __guard_fids_table and __safe_se_handler_table. + if (!(isa(Sym) && Sec->isCodeView())) + add32(Off, Sym->getSecrel()); +} + void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, uint64_t P) const { uint64_t S = Sym->getRVA(); @@ -60,7 +75,7 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, Defined *Sym, case IMAGE_REL_AMD64_REL32_4: add32(Off, S - P - 8); break; case IMAGE_REL_AMD64_REL32_5: add32(Off, S - P - 9); break; case IMAGE_REL_AMD64_SECTION: add16(Off, Sym->getSectionIndex()); break; - case IMAGE_REL_AMD64_SECREL: add32(Off, Sym->getSecrel()); break; + case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, Sym); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } @@ -75,7 +90,7 @@ void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, Defined *Sym, case IMAGE_REL_I386_DIR32NB: add32(Off, S); break; case IMAGE_REL_I386_REL32: add32(Off, S - P - 4); break; case IMAGE_REL_I386_SECTION: add16(Off, Sym->getSectionIndex()); break; - case IMAGE_REL_I386_SECREL: add32(Off, Sym->getSecrel()); break; + case IMAGE_REL_I386_SECREL: applySecRel(this, Off, Sym); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } @@ -135,7 +150,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, Defined *Sym, case IMAGE_REL_ARM_BRANCH20T: applyBranch20T(Off, S - P - 4); break; case IMAGE_REL_ARM_BRANCH24T: applyBranch24T(Off, S - P - 4); break; case IMAGE_REL_ARM_BLX23T: applyBranch24T(Off, S - P - 4); break; - case IMAGE_REL_ARM_SECREL: add32(Off, Sym->getSecrel()); break; + case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, Sym); break; default: fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); } @@ -226,8 +241,12 @@ bool SectionChunk::isCOMDAT() const { void SectionChunk::printDiscardedMessage() const { // Removed by dead-stripping. If it's removed by ICF, ICF already // printed out the name, so don't repeat that here. - if (Sym && this == Repl) - message("Discarded " + Sym->getName()); + if (Sym && this == Repl) { + if (Discarded) + message("Discarded comdat symbol " + Sym->getName()); + else if (!Live) + message("Discarded " + Sym->getName()); + } } StringRef SectionChunk::getDebugName() { diff --git a/contrib/llvm/tools/lld/COFF/Chunks.h b/contrib/llvm/tools/lld/COFF/Chunks.h index f7412517765c..54fffc5f6d08 100644 --- a/contrib/llvm/tools/lld/COFF/Chunks.h +++ b/contrib/llvm/tools/lld/COFF/Chunks.h @@ -64,7 +64,6 @@ class Chunk { uint64_t getRVA() const { return RVA; } uint32_t getAlign() const { return Align; } void setRVA(uint64_t V) { RVA = V; } - void setOutputSectionOff(uint64_t V) { OutputSectionOff = V; } // Returns true if this has non-zero data. BSS chunks return // false. If false is returned, the space occupied by this chunk @@ -97,17 +96,19 @@ class Chunk { Chunk(Kind K = OtherKind) : ChunkKind(K) {} const Kind ChunkKind; + // The alignment of this chunk. The writer uses the value. + uint32_t Align = 1; + // The RVA of this chunk in the output. The writer sets a value. uint64_t RVA = 0; +public: // The offset from beginning of the output section. The writer sets a value. uint64_t OutputSectionOff = 0; +protected: // The output section for this chunk. OutputSection *Out = nullptr; - - // The alignment of this chunk. The writer uses the value. - uint32_t Align = 1; }; // A chunk corresponding a section of an input file. @@ -159,13 +160,29 @@ class SectionChunk : public Chunk { StringRef getDebugName() override; void setSymbol(DefinedRegular *S) { if (!Sym) Sym = S; } + // Returns true if the chunk was not dropped by GC or COMDAT deduplication. + bool isLive() { return Live && !Discarded; } + // Used by the garbage collector. - bool isLive() { return !Config->DoGC || Live; } void markLive() { + assert(Config->DoGC && "should only mark things live from GC"); assert(!isLive() && "Cannot mark an already live section!"); Live = true; } + // Returns true if this chunk was dropped by COMDAT deduplication. + bool isDiscarded() const { return Discarded; } + + // Used by the SymbolTable when discarding unused comdat sections. This is + // redundant when GC is enabled, as all comdat sections will start out dead. + void markDiscarded() { Discarded = true; } + + // True if this is a codeview debug info chunk. These will not be laid out in + // the image. Instead they will end up in the PDB, if one is requested. + bool isCodeView() const { + return SectionName == ".debug" || SectionName.startswith(".debug$"); + } + // Allow iteration over the bodies of this chunk's relocated symbols. llvm::iterator_range symbols() const { return llvm::make_range(symbol_iterator(File, Relocs.begin()), @@ -196,6 +213,9 @@ class SectionChunk : public Chunk { llvm::iterator_range Relocs; size_t NumRelocs; + // True if this chunk was discarded because it was a duplicate comdat section. + bool Discarded; + // Used by the garbage collector. bool Live; diff --git a/contrib/llvm/tools/lld/COFF/Config.h b/contrib/llvm/tools/lld/COFF/Config.h index d859b1fbb7d9..9fcea96d65d3 100644 --- a/contrib/llvm/tools/lld/COFF/Config.h +++ b/contrib/llvm/tools/lld/COFF/Config.h @@ -161,9 +161,6 @@ struct Configuration { bool LargeAddressAware = false; bool HighEntropyVA = false; bool AppContainer = false; - - // This is for debugging. - bool DumpPdb = false; }; extern Configuration *Config; diff --git a/contrib/llvm/tools/lld/COFF/Driver.cpp b/contrib/llvm/tools/lld/COFF/Driver.cpp index 71a9c679d19f..22efb312ae49 100644 --- a/contrib/llvm/tools/lld/COFF/Driver.cpp +++ b/contrib/llvm/tools/lld/COFF/Driver.cpp @@ -905,7 +905,6 @@ void LinkerDriver::link(ArrayRef ArgsArr) { Config->TerminalServerAware = false; if (Args.hasArg(OPT_nosymtab)) Config->WriteSymtab = false; - Config->DumpPdb = Args.hasArg(OPT_dumppdb); Config->MapFile = getMapFile(Args); @@ -936,9 +935,9 @@ void LinkerDriver::link(ArrayRef ArgsArr) { Config->Machine = AMD64; } - // Windows specific -- Input files can be Windows resource files (.res files). - // We invoke cvtres.exe to convert resource files to a regular COFF file - // then link the result file normally. + // Input files can be Windows resource files (.res files). We use + // WindowsResource to convert resource files to a regular COFF file, + // then link the resulting file normally. if (!Resources.empty()) addBuffer(convertResToCOFF(Resources)); @@ -1027,17 +1026,21 @@ void LinkerDriver::link(ArrayRef ArgsArr) { if (Config->ImageBase == uint64_t(-1)) Config->ImageBase = getDefaultImageBase(); - Symtab.addRelative(mangle("__ImageBase"), 0); + Symtab.addSynthetic(mangle("__ImageBase"), nullptr); if (Config->Machine == I386) { - Config->SEHTable = Symtab.addRelative("___safe_se_handler_table", 0); - Config->SEHCount = Symtab.addAbsolute("___safe_se_handler_count", 0); + Symtab.addAbsolute("___safe_se_handler_table", 0); + Symtab.addAbsolute("___safe_se_handler_count", 0); } // We do not support /guard:cf (control flow protection) yet. // Define CFG symbols anyway so that we can link MSVC 2015 CRT. - Symtab.addAbsolute(mangle("__guard_fids_table"), 0); Symtab.addAbsolute(mangle("__guard_fids_count"), 0); + Symtab.addAbsolute(mangle("__guard_fids_table"), 0); Symtab.addAbsolute(mangle("__guard_flags"), 0x100); + Symtab.addAbsolute(mangle("__guard_iat_count"), 0); + Symtab.addAbsolute(mangle("__guard_iat_table"), 0); + Symtab.addAbsolute(mangle("__guard_longjmp_count"), 0); + Symtab.addAbsolute(mangle("__guard_longjmp_table"), 0); // This code may add new undefined symbols to the link, which may enqueue more // symbol resolution tasks, so we need to continue executing tasks until we diff --git a/contrib/llvm/tools/lld/COFF/Driver.h b/contrib/llvm/tools/lld/COFF/Driver.h index 3eb950cca25c..2b5d1e7ae28b 100644 --- a/contrib/llvm/tools/lld/COFF/Driver.h +++ b/contrib/llvm/tools/lld/COFF/Driver.h @@ -178,7 +178,7 @@ void runMSVCLinker(std::string Rsp, ArrayRef Objects); // Create enum with OPT_xxx values for each option in Options.td enum { OPT_INVALID = 0, -#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, #include "Options.inc" #undef OPTION }; diff --git a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp index 42619b8fa438..d0152b0917b6 100644 --- a/contrib/llvm/tools/lld/COFF/DriverUtils.cpp +++ b/contrib/llvm/tools/lld/COFF/DriverUtils.cpp @@ -20,12 +20,15 @@ #include "Symbols.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/WindowsResource.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" @@ -41,6 +44,9 @@ namespace lld { namespace coff { namespace { +const uint16_t SUBLANG_ENGLISH_US = 0x0409; +const uint16_t RT_MANIFEST = 24; + class Executor { public: explicit Executor(StringRef S) : Prog(Saver.save(S)) {} @@ -257,26 +263,6 @@ void parseManifestUAC(StringRef Arg) { } } -// Quote each line with "". Existing double-quote is converted -// to two double-quotes. -static void quoteAndPrint(raw_ostream &Out, StringRef S) { - while (!S.empty()) { - StringRef Line; - std::tie(Line, S) = S.split("\n"); - if (Line.empty()) - continue; - Out << '\"'; - for (int I = 0, E = Line.size(); I != E; ++I) { - if (Line[I] == '\"') { - Out << "\"\""; - } else { - Out << Line[I]; - } - } - Out << "\"\n"; - } -} - // An RAII temporary file class that automatically removes a temporary file. namespace { class TemporaryFile { @@ -390,38 +376,64 @@ static std::string createManifestXml() { return readFile(File2.Path); } +static std::unique_ptr +createMemoryBufferForManifestRes(size_t ManifestSize) { + size_t ResSize = alignTo(object::WIN_RES_MAGIC_SIZE + + object::WIN_RES_NULL_ENTRY_SIZE + + sizeof(object::WinResHeaderPrefix) + + sizeof(object::WinResIDs) + + sizeof(object::WinResHeaderSuffix) + + ManifestSize, + object::WIN_RES_DATA_ALIGNMENT); + return MemoryBuffer::getNewMemBuffer(ResSize); +} + +static void writeResFileHeader(char *&Buf) { + memcpy(Buf, COFF::WinResMagic, sizeof(COFF::WinResMagic)); + Buf += sizeof(COFF::WinResMagic); + memset(Buf, 0, object::WIN_RES_NULL_ENTRY_SIZE); + Buf += object::WIN_RES_NULL_ENTRY_SIZE; +} + +static void writeResEntryHeader(char *&Buf, size_t ManifestSize) { + // Write the prefix. + auto *Prefix = reinterpret_cast(Buf); + Prefix->DataSize = ManifestSize; + Prefix->HeaderSize = sizeof(object::WinResHeaderPrefix) + + sizeof(object::WinResIDs) + + sizeof(object::WinResHeaderSuffix); + Buf += sizeof(object::WinResHeaderPrefix); + + // Write the Type/Name IDs. + auto *IDs = reinterpret_cast(Buf); + IDs->setType(RT_MANIFEST); + IDs->setName(Config->ManifestID); + Buf += sizeof(object::WinResIDs); + + // Write the suffix. + auto *Suffix = reinterpret_cast(Buf); + Suffix->DataVersion = 0; + Suffix->MemoryFlags = object::WIN_RES_PURE_MOVEABLE; + Suffix->Language = SUBLANG_ENGLISH_US; + Suffix->Version = 0; + Suffix->Characteristics = 0; + Buf += sizeof(object::WinResHeaderSuffix); +} + // Create a resource file containing a manifest XML. std::unique_ptr createManifestRes() { - // Create a temporary file for the resource script file. - TemporaryFile RCFile("manifest", "rc"); + std::string Manifest = createManifestXml(); - // Open the temporary file for writing. - std::error_code EC; - raw_fd_ostream Out(RCFile.Path, EC, sys::fs::F_Text); - if (EC) - fatal(EC, "failed to open " + RCFile.Path); + std::unique_ptr Res = + createMemoryBufferForManifestRes(Manifest.size()); - // Write resource script to the RC file. - Out << "#define LANG_ENGLISH 9\n" - << "#define SUBLANG_DEFAULT 1\n" - << "#define APP_MANIFEST " << Config->ManifestID << "\n" - << "#define RT_MANIFEST 24\n" - << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n" - << "APP_MANIFEST RT_MANIFEST {\n"; - quoteAndPrint(Out, createManifestXml()); - Out << "}\n"; - Out.close(); + char *Buf = const_cast(Res->getBufferStart()); + writeResFileHeader(Buf); + writeResEntryHeader(Buf, Manifest.size()); - // Create output resource file. - TemporaryFile ResFile("output-resource", "res"); - - Executor E("rc.exe"); - E.add("/fo"); - E.add(ResFile.Path); - E.add("/nologo"); - E.add(RCFile.Path); - E.run(); - return ResFile.getMemoryBuffer(); + // Copy the manifest data into the .res file. + std::copy(Manifest.begin(), Manifest.end(), Buf); + return Res; } void createSideBySideManifest() { @@ -592,40 +604,22 @@ void checkFailIfMismatch(StringRef Arg) { // using cvtres.exe. std::unique_ptr convertResToCOFF(const std::vector &MBs) { - // Create an output file path. - TemporaryFile File("resource-file", "obj"); + object::WindowsResourceParser Parser; - // Execute cvtres.exe. - Executor E("cvtres.exe"); - E.add("/machine:" + machineToStr(Config->Machine)); - E.add("/readonly"); - E.add("/nologo"); - E.add("/out:" + Twine(File.Path)); - - // We must create new files because the memory buffers we have may have no - // underlying file still existing on the disk. - // It happens if it was created from a TemporaryFile, which usually delete - // the file just after creating the MemoryBuffer. - std::vector ResFiles; - ResFiles.reserve(MBs.size()); for (MemoryBufferRef MB : MBs) { - // We store the temporary file in a vector to avoid deletion - // before running cvtres - ResFiles.emplace_back("resource-file", "res"); - TemporaryFile& ResFile = ResFiles.back(); - // Write the content of the resource in a temporary file - std::error_code EC; - raw_fd_ostream OS(ResFile.Path, EC, sys::fs::F_None); - if (EC) - fatal(EC, "failed to open " + ResFile.Path); - OS << MB.getBuffer(); - OS.close(); - - E.add(ResFile.Path); + std::unique_ptr Bin = check(object::createBinary(MB)); + object::WindowsResource *RF = dyn_cast(Bin.get()); + if (!RF) + fatal("cannot compile non-resource file as resource"); + if (auto EC = Parser.parse(RF)) + fatal(EC, "failed to parse .res file"); } - E.run(); - return File.getMemoryBuffer(); + Expected> E = + llvm::object::writeWindowsResourceCOFF(Config->Machine, Parser); + if (!E) + fatal(errorToErrorCode(E.takeError()), "failed to write .res to COFF"); + return std::move(E.get()); } // Run MSVC link.exe for given in-memory object files. @@ -657,11 +651,9 @@ void runMSVCLinker(std::string Rsp, ArrayRef Objects) { // Create table mapping all options defined in Options.td static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ - { \ - X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \ - OPT_##GROUP, OPT_##ALIAS, X6 \ - }, +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ + {X1, X2, X10, X11, OPT_##ID, llvm::opt::Option::KIND##Class, \ + X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, #include "Options.inc" #undef OPTION }; diff --git a/contrib/llvm/tools/lld/COFF/InputFiles.cpp b/contrib/llvm/tools/lld/COFF/InputFiles.cpp index 58e8dd329f1f..c26483e3e368 100644 --- a/contrib/llvm/tools/lld/COFF/InputFiles.cpp +++ b/contrib/llvm/tools/lld/COFF/InputFiles.cpp @@ -132,17 +132,17 @@ void ObjectFile::initializeChunks() { if (!Config->Debug && Name.startswith(".debug")) continue; - // CodeView sections are stored to a different vector because they are - // not linked in the regular manner. - if (Name == ".debug" || Name.startswith(".debug$")) { - DebugChunks.push_back(make(this, Sec)); - continue; - } - if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) continue; auto *C = make(this, Sec); - Chunks.push_back(C); + + // CodeView sections are stored to a different vector because they are not + // linked in the regular manner. + if (C->isCodeView()) + DebugChunks.push_back(C); + else + Chunks.push_back(C); + SparseChunks[I] = C; } } @@ -249,8 +249,12 @@ SymbolBody *ObjectFile::createDefined(COFFSymbolRef Sym, const void *AuxP, auto *Aux = reinterpret_cast(AuxP); if (Aux->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) if (auto *ParentSC = cast_or_null( - SparseChunks[Aux->getNumber(Sym.isBigObj())])) + SparseChunks[Aux->getNumber(Sym.isBigObj())])) { ParentSC->addAssociative(SC); + // If we already discarded the parent, discard the child. + if (ParentSC->isDiscarded()) + SC->markDiscarded(); + } SC->Checksum = Aux->CheckSum; } diff --git a/contrib/llvm/tools/lld/COFF/Options.td b/contrib/llvm/tools/lld/COFF/Options.td index 14a1aa04afd6..61523c4f2256 100644 --- a/contrib/llvm/tools/lld/COFF/Options.td +++ b/contrib/llvm/tools/lld/COFF/Options.td @@ -102,7 +102,6 @@ def nosymtab : F<"nosymtab">; def msvclto : F<"msvclto">; // Flags for debugging -def dumppdb : Joined<["/", "-"], "dumppdb">; def lldmap : F<"lldmap">; def lldmap_file : Joined<["/", "-"], "lldmap:">; diff --git a/contrib/llvm/tools/lld/COFF/PDB.cpp b/contrib/llvm/tools/lld/COFF/PDB.cpp index 116766740e58..c9842cfd1b9a 100644 --- a/contrib/llvm/tools/lld/COFF/PDB.cpp +++ b/contrib/llvm/tools/lld/COFF/PDB.cpp @@ -15,10 +15,11 @@ #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" -#include "llvm/DebugInfo/CodeView/SymbolDumper.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" @@ -46,8 +47,6 @@ using namespace lld; using namespace lld::coff; using namespace llvm; using namespace llvm::codeview; -using namespace llvm::support; -using namespace llvm::support::endian; using llvm::object::coff_section; @@ -68,22 +67,24 @@ static SectionChunk *findByName(std::vector &Sections, return nullptr; } -static ArrayRef getDebugSection(ObjectFile *File, StringRef SecName) { - SectionChunk *Sec = findByName(File->getDebugChunks(), SecName); - if (!Sec) - return {}; - +static ArrayRef consumeDebugMagic(ArrayRef Data, + StringRef SecName) { // First 4 bytes are section magic. - ArrayRef Data = Sec->getContents(); if (Data.size() < 4) fatal(SecName + " too short"); - if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) + if (support::endian::read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) fatal(SecName + " has an invalid magic"); return Data.slice(4); } +static ArrayRef getDebugSection(ObjectFile *File, StringRef SecName) { + if (SectionChunk *Sec = findByName(File->getDebugChunks(), SecName)) + return consumeDebugMagic(Sec->getContents(), SecName); + return {}; +} + static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, - codeview::TypeTableBuilder &TypeTable) { + TypeTableBuilder &TypeTable) { // Start the TPI or IPI stream header. TpiBuilder.setVersionHeader(pdb::PdbTpiV80); @@ -94,17 +95,148 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, }); } +static void mergeDebugT(ObjectFile *File, + TypeTableBuilder &IDTable, + TypeTableBuilder &TypeTable, + SmallVectorImpl &TypeIndexMap, + pdb::PDBTypeServerHandler &Handler) { + ArrayRef Data = getDebugSection(File, ".debug$T"); + if (Data.empty()) + return; + + BinaryByteStream Stream(Data, support::little); + CVTypeArray Types; + BinaryStreamReader Reader(Stream); + Handler.addSearchPath(sys::path::parent_path(File->getName())); + if (auto EC = Reader.readArray(Types, Reader.getLength())) + fatal(EC, "Reader::readArray failed"); + if (auto Err = mergeTypeAndIdRecords(IDTable, TypeTable, + TypeIndexMap, &Handler, Types)) + fatal(Err, "codeview::mergeTypeStreams failed"); +} + +static bool remapTypeIndex(TypeIndex &TI, ArrayRef TypeIndexMap) { + if (TI.isSimple()) + return true; + if (TI.toArrayIndex() >= TypeIndexMap.size()) + return false; + TI = TypeIndexMap[TI.toArrayIndex()]; + return true; +} + +static bool remapTypesInSymbolRecord(ObjectFile *File, + MutableArrayRef Contents, + ArrayRef TypeIndexMap, + ArrayRef TypeRefs) { + for (const TiReference &Ref : TypeRefs) { + unsigned ByteSize = Ref.Count * sizeof(TypeIndex); + if (Contents.size() < Ref.Offset + ByteSize) { + log("ignoring short symbol record"); + return false; + } + MutableArrayRef TIs( + reinterpret_cast(Contents.data() + Ref.Offset), Ref.Count); + for (TypeIndex &TI : TIs) + if (!remapTypeIndex(TI, TypeIndexMap)) { + log("ignoring symbol record in " + File->getName() + + " with bad type index 0x" + utohexstr(TI.getIndex())); + return false; + } + } + return true; +} + +/// MSVC translates S_PROC_ID_END to S_END. +uint16_t canonicalizeSymbolKind(SymbolKind Kind) { + if (Kind == SymbolKind::S_PROC_ID_END) + return SymbolKind::S_END; + return Kind; +} + +/// Copy the symbol record. In a PDB, symbol records must be 4 byte aligned. +/// The object file may not be aligned. +static MutableArrayRef copySymbolForPdb(const CVSymbol &Sym, + BumpPtrAllocator &Alloc) { + size_t Size = alignTo(Sym.length(), alignOf(CodeViewContainer::Pdb)); + assert(Size >= 4 && "record too short"); + assert(Size <= MaxRecordLength && "record too long"); + void *Mem = Alloc.Allocate(Size, 4); + + // Copy the symbol record and zero out any padding bytes. + MutableArrayRef NewData(reinterpret_cast(Mem), Size); + memcpy(NewData.data(), Sym.data().data(), Sym.length()); + memset(NewData.data() + Sym.length(), 0, Size - Sym.length()); + + // Update the record prefix length. It should point to the beginning of the + // next record. MSVC does some canonicalization of the record kind, so we do + // that as well. + auto *Prefix = reinterpret_cast(Mem); + Prefix->RecordKind = canonicalizeSymbolKind(Sym.kind()); + Prefix->RecordLen = Size - 2; + return NewData; +} + +static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, + ArrayRef TypeIndexMap, + BinaryStreamRef SymData) { + // FIXME: Improve error recovery by warning and skipping records when + // possible. + CVSymbolArray Syms; + BinaryStreamReader Reader(SymData); + ExitOnErr(Reader.readArray(Syms, Reader.getLength())); + for (const CVSymbol &Sym : Syms) { + // Discover type index references in the record. Skip it if we don't know + // where they are. + SmallVector TypeRefs; + if (!discoverTypeIndices(Sym, TypeRefs)) { + log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind())); + continue; + } + + // Copy the symbol record so we can mutate it. + MutableArrayRef NewData = copySymbolForPdb(Sym, Alloc); + + // Re-map all the type index references. + MutableArrayRef Contents = + NewData.drop_front(sizeof(RecordPrefix)); + if (!remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs)) + continue; + + // FIXME: Fill in "Parent" and "End" fields by maintaining a stack of + // scopes. + + // Add the symbol to the module. + File->ModuleDBI->addSymbol(CVSymbol(Sym.kind(), NewData)); + } +} + +// Allocate memory for a .debug$S section and relocate it. +static ArrayRef relocateDebugChunk(BumpPtrAllocator &Alloc, + SectionChunk *DebugChunk) { + uint8_t *Buffer = Alloc.Allocate(DebugChunk->getSize()); + assert(DebugChunk->OutputSectionOff == 0 && + "debug sections should not be in output sections"); + DebugChunk->writeTo(Buffer); + return consumeDebugMagic(makeArrayRef(Buffer, DebugChunk->getSize()), + ".debug$S"); +} + // Add all object files to the PDB. Merge .debug$T sections into IpiData and // TpiData. -static void addObjectsToPDB(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, - codeview::TypeTableBuilder &TypeTable, - codeview::TypeTableBuilder &IDTable) { +static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, + pdb::PDBFileBuilder &Builder, + TypeTableBuilder &TypeTable, + TypeTableBuilder &IDTable) { // Follow type servers. If the same type server is encountered more than // once for this instance of `PDBTypeServerHandler` (for example if many // object files reference the same TypeServer), the types from the // TypeServer will only be visited once. pdb::PDBTypeServerHandler Handler; + // PDBs use a single global string table for filenames in the file checksum + // table. + auto PDBStrTab = std::make_shared(); + // Visit all .debug$T sections to add them to Builder. for (ObjectFile *File : Symtab->ObjectFiles) { // Add a module descriptor for every object file. We need to put an absolute @@ -118,25 +250,74 @@ static void addObjectsToPDB(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); File->ModuleDBI->setObjFileName(Path); - // FIXME: Walk the .debug$S sections and add them. Do things like recording - // source files. + // Before we can process symbol substreams from .debug$S, we need to process + // type information, file checksums, and the string table. Add type info to + // the PDB first, so that we can get the map from object file type and item + // indices to PDB type and item indices. + SmallVector TypeIndexMap; + mergeDebugT(File, IDTable, TypeTable, TypeIndexMap, Handler); - ArrayRef Data = getDebugSection(File, ".debug$T"); - if (Data.empty()) - continue; + // Now do all line info. + for (SectionChunk *DebugChunk : File->getDebugChunks()) { + if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") + continue; - BinaryByteStream Stream(Data, support::little); - codeview::CVTypeArray Types; - BinaryStreamReader Reader(Stream); - SmallVector SourceToDest; - Handler.addSearchPath(llvm::sys::path::parent_path(File->getName())); - if (auto EC = Reader.readArray(Types, Reader.getLength())) - fatal(EC, "Reader::readArray failed"); - if (auto Err = codeview::mergeTypeAndIdRecords( - IDTable, TypeTable, SourceToDest, &Handler, Types)) - fatal(Err, "codeview::mergeTypeStreams failed"); + ArrayRef RelocatedDebugContents = + relocateDebugChunk(Alloc, DebugChunk); + if (RelocatedDebugContents.empty()) + continue; + + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(RelocatedDebugContents, support::little); + ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); + + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { + case DebugSubsectionKind::StringTable: + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::FileChecksums: + ExitOnErr(Checksums.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::Lines: + // We can add the relocated line table directly to the PDB without + // modification because the file checksum offsets will stay the same. + File->ModuleDBI->addDebugSubsection(SS); + break; + case DebugSubsectionKind::Symbols: + mergeSymbolRecords(Alloc, File, TypeIndexMap, SS.getRecordData()); + break; + default: + // FIXME: Process the rest of the subsections. + break; + } + } + + if (Checksums.valid()) { + // Make a new file checksum table that refers to offsets in the PDB-wide + // string table. Generally the string table subsection appears after the + // checksum table, so we have to do this after looping over all the + // subsections. + if (!CVStrTab.valid()) + fatal(".debug$S sections must have both a string table subsection " + "and a checksum subsection table or neither"); + auto NewChecksums = + make_unique(*PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile( + *File->ModuleDBI, FileName)); + NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); + } + File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); + } + } } + Builder.getStringTableBuilder().setStrings(*PDBStrTab); + // Construct TPI stream contents. addTypeInfo(Builder.getTpiBuilder(), TypeTable); @@ -144,56 +325,10 @@ static void addObjectsToPDB(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, addTypeInfo(Builder.getIpiBuilder(), IDTable); } -static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) { - ListScope LS(W, "DebugT"); - ArrayRef Data = getDebugSection(File, ".debug$T"); - if (Data.empty()) - return; - - LazyRandomTypeCollection Types(Data, 100); - TypeDumpVisitor TDV(Types, &W, false); - // Use a default implementation that does not follow type servers and instead - // just dumps the contents of the TypeServer2 record. - if (auto EC = codeview::visitTypeStream(Types, TDV)) - fatal(EC, "CVTypeDumper::dump failed"); -} - -static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) { - ListScope LS(W, "DebugS"); - ArrayRef Data = getDebugSection(File, ".debug$S"); - if (Data.empty()) - return; - - BinaryByteStream Stream(Data, llvm::support::little); - CVSymbolArray Symbols; - BinaryStreamReader Reader(Stream); - if (auto EC = Reader.readArray(Symbols, Reader.getLength())) - fatal(EC, "StreamReader.readArray failed"); - - TypeDatabase TDB(0); - CVSymbolDumper SymbolDumper(W, TDB, CodeViewContainer::ObjectFile, nullptr, - false); - if (auto EC = SymbolDumper.dump(Symbols)) - fatal(EC, "CVSymbolDumper::dump failed"); -} - -// Dump CodeView debug info. This is for debugging. -static void dumpCodeView(SymbolTable *Symtab) { - ScopedPrinter W(outs()); - - for (ObjectFile *File : Symtab->ObjectFiles) { - dumpDebugT(W, File); - dumpDebugS(W, File); - } -} - // Creates a PDB file. void coff::createPDB(StringRef Path, SymbolTable *Symtab, ArrayRef SectionTable, const llvm::codeview::DebugInfo *DI) { - if (Config->DumpPdb) - dumpCodeView(Symtab); - BumpPtrAllocator Alloc; pdb::PDBFileBuilder Builder(Alloc); ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize @@ -219,9 +354,9 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab, pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setVersionHeader(pdb::PdbDbiV110); - codeview::TypeTableBuilder TypeTable(BAlloc); - codeview::TypeTableBuilder IDTable(BAlloc); - addObjectsToPDB(Symtab, Builder, TypeTable, IDTable); + TypeTableBuilder TypeTable(BAlloc); + TypeTableBuilder IDTable(BAlloc); + addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable); // Add Section Contributions. addSectionContribs(Symtab, DbiBuilder); diff --git a/contrib/llvm/tools/lld/COFF/Strings.cpp b/contrib/llvm/tools/lld/COFF/Strings.cpp index d0558413f673..84f9b9a55a32 100644 --- a/contrib/llvm/tools/lld/COFF/Strings.cpp +++ b/contrib/llvm/tools/lld/COFF/Strings.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "Strings.h" +#include #if defined(_MSC_VER) #include @@ -21,6 +22,10 @@ using namespace llvm; Optional coff::demangle(StringRef S) { #if defined(_MSC_VER) + // UnDecorateSymbolName is not thread-safe, so we need a mutex. + static std::mutex Mu; + std::lock_guard Lock(Mu); + char Buf[4096]; if (S.startswith("?")) if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0)) diff --git a/contrib/llvm/tools/lld/COFF/SymbolTable.cpp b/contrib/llvm/tools/lld/COFF/SymbolTable.cpp index 310eab274526..c06e42bb114b 100644 --- a/contrib/llvm/tools/lld/COFF/SymbolTable.cpp +++ b/contrib/llvm/tools/lld/COFF/SymbolTable.cpp @@ -219,13 +219,13 @@ Symbol *SymbolTable::addAbsolute(StringRef N, uint64_t VA) { return S; } -Symbol *SymbolTable::addRelative(StringRef N, uint64_t VA) { +Symbol *SymbolTable::addSynthetic(StringRef N, Chunk *C) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa(S->body()) || isa(S->body())) - replaceBody(S, N, VA); + replaceBody(S, N, C); else if (!isa(S->body())) reportDuplicate(S, nullptr); return S; @@ -244,6 +244,12 @@ Symbol *SymbolTable::addRegular(InputFile *F, StringRef N, bool IsCOMDAT, reportDuplicate(S, F); } else if (SP == SP_NEW) { replaceBody(S, F, N, IsCOMDAT, /*IsExternal*/ true, Sym, C); + } else if (SP == SP_EXISTING && IsCOMDAT && C) { + C->markDiscarded(); + // Discard associative chunks that we've parsed so far. No need to recurse + // because an associative section cannot have children. + for (SectionChunk *Child : C->children()) + Child->markDiscarded(); } return S; } diff --git a/contrib/llvm/tools/lld/COFF/SymbolTable.h b/contrib/llvm/tools/lld/COFF/SymbolTable.h index 0aa8a4593b5c..ea74678c28d8 100644 --- a/contrib/llvm/tools/lld/COFF/SymbolTable.h +++ b/contrib/llvm/tools/lld/COFF/SymbolTable.h @@ -85,7 +85,7 @@ class SymbolTable { // Creates an Undefined symbol for a given name. SymbolBody *addUndefined(StringRef Name); - Symbol *addRelative(StringRef N, uint64_t VA); + Symbol *addSynthetic(StringRef N, Chunk *C); Symbol *addAbsolute(StringRef N, uint64_t VA); Symbol *addUndefined(StringRef Name, InputFile *F, bool IsWeakAlias); diff --git a/contrib/llvm/tools/lld/COFF/Symbols.cpp b/contrib/llvm/tools/lld/COFF/Symbols.cpp index 5c185a511dd7..1cf2934a355b 100644 --- a/contrib/llvm/tools/lld/COFF/Symbols.cpp +++ b/contrib/llvm/tools/lld/COFF/Symbols.cpp @@ -61,6 +61,8 @@ COFFSymbolRef DefinedCOFF::getCOFFSymbol() { return COFFSymbolRef(reinterpret_cast(Sym)); } +uint16_t DefinedAbsolute::OutputSectionIndex = 0; + static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { if (Machine == AMD64) return make(S); diff --git a/contrib/llvm/tools/lld/COFF/Symbols.h b/contrib/llvm/tools/lld/COFF/Symbols.h index 801fc87f91d9..8c1390c45876 100644 --- a/contrib/llvm/tools/lld/COFF/Symbols.h +++ b/contrib/llvm/tools/lld/COFF/Symbols.h @@ -50,13 +50,13 @@ class SymbolBody { DefinedImportThunkKind, DefinedImportDataKind, DefinedAbsoluteKind, - DefinedRelativeKind, + DefinedSyntheticKind, UndefinedKind, LazyKind, LastDefinedCOFFKind = DefinedCommonKind, - LastDefinedKind = DefinedRelativeKind, + LastDefinedKind = DefinedSyntheticKind, }; Kind kind() const { return static_cast(SymbolKind); } @@ -112,11 +112,11 @@ class Defined : public SymbolBody { // Returns the RVA relative to the beginning of the output section. // Used to implement SECREL relocation type. - uint64_t getSecrel(); + uint32_t getSecrel(); // Returns the output section index. // Used to implement SECTION relocation type. - uint64_t getSectionIndex(); + uint16_t getSectionIndex(); // Returns true if this symbol points to an executable (e.g. .text) section. // Used to implement ARM relocations. @@ -167,6 +167,7 @@ class DefinedRegular : public DefinedCOFF { bool isCOMDAT() { return IsCOMDAT; } SectionChunk *getChunk() { return *Data; } uint32_t getValue() { return Sym->Value; } + uint32_t getSecrel(); private: SectionChunk **Data; @@ -186,6 +187,8 @@ class DefinedCommon : public DefinedCOFF { } uint64_t getRVA() { return Data->getRVA(); } + uint32_t getSecrel() { return Data->OutputSectionOff; } + uint16_t getSectionIndex(); private: friend SymbolTable; @@ -212,28 +215,34 @@ class DefinedAbsolute : public Defined { uint64_t getRVA() { return VA - Config->ImageBase; } void setVA(uint64_t V) { VA = V; } + // The sentinel absolute symbol section index. Section index relocations + // against absolute symbols resolve to this 16 bit number, and it is the + // largest valid section index plus one. This is written by the Writer. + static uint16_t OutputSectionIndex; + private: uint64_t VA; }; -// This is a kind of absolute symbol but relative to the image base. -// Unlike absolute symbols, relocations referring this kind of symbols -// are subject of the base relocation. This type is used rarely -- -// mainly for __ImageBase. -class DefinedRelative : public Defined { +// This symbol is used for linker-synthesized symbols like __ImageBase and +// __safe_se_handler_table. +class DefinedSynthetic : public Defined { public: - explicit DefinedRelative(StringRef Name, uint64_t V = 0) - : Defined(DefinedRelativeKind, Name), RVA(V) {} + explicit DefinedSynthetic(StringRef Name, Chunk *C) + : Defined(DefinedSyntheticKind, Name), C(C) {} static bool classof(const SymbolBody *S) { - return S->kind() == DefinedRelativeKind; + return S->kind() == DefinedSyntheticKind; } - uint64_t getRVA() { return RVA; } - void setRVA(uint64_t V) { RVA = V; } + // A null chunk indicates that this is __ImageBase. Otherwise, this is some + // other synthesized chunk, like SEHTableChunk. + uint32_t getRVA() const { return C ? C->getRVA() : 0; } + uint32_t getSecrel() const { return C ? C->OutputSectionOff : 0; } + Chunk *getChunk() const { return C; } private: - uint64_t RVA; + Chunk *C; }; // This class represents a symbol defined in an archive file. It is @@ -350,8 +359,8 @@ inline uint64_t Defined::getRVA() { switch (kind()) { case DefinedAbsoluteKind: return cast(this)->getRVA(); - case DefinedRelativeKind: - return cast(this)->getRVA(); + case DefinedSyntheticKind: + return cast(this)->getRVA(); case DefinedImportDataKind: return cast(this)->getRVA(); case DefinedImportThunkKind: @@ -386,7 +395,7 @@ struct Symbol { // AlignedCharArrayUnion gives us a struct with a char array field that is // large and aligned enough to store any derived class of SymbolBody. llvm::AlignedCharArrayUnion< - DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedRelative, Lazy, + DefinedRegular, DefinedCommon, DefinedAbsolute, DefinedSynthetic, Lazy, Undefined, DefinedImportData, DefinedImportThunk, DefinedLocalImport> Body; diff --git a/contrib/llvm/tools/lld/COFF/Writer.cpp b/contrib/llvm/tools/lld/COFF/Writer.cpp index fb1f3cae5bb2..d32577b361fa 100644 --- a/contrib/llvm/tools/lld/COFF/Writer.cpp +++ b/contrib/llvm/tools/lld/COFF/Writer.cpp @@ -181,7 +181,7 @@ void OutputSection::addChunk(Chunk *C) { uint64_t Off = Header.VirtualSize; Off = alignTo(Off, C->getAlign()); C->setRVA(Off); - C->setOutputSectionOff(Off); + C->OutputSectionOff = Off; Off += C->getSize(); Header.VirtualSize = Off; if (C->hasData()) @@ -210,16 +210,46 @@ void OutputSection::writeHeaderTo(uint8_t *Buf) { } } -uint64_t Defined::getSecrel() { - if (auto *D = dyn_cast(this)) - return getRVA() - D->getChunk()->getOutputSection()->getRVA(); - fatal("SECREL relocation points to a non-regular symbol"); +uint32_t Defined::getSecrel() { + assert(this); + switch (kind()) { + case DefinedRegularKind: + return cast(this)->getSecrel(); + case DefinedCommonKind: + return cast(this)->getSecrel(); + case DefinedSyntheticKind: + return cast(this)->getSecrel(); + default: + break; + } + fatal("SECREL relocation points to a non-regular symbol: " + toString(*this)); } -uint64_t Defined::getSectionIndex() { +uint32_t DefinedRegular::getSecrel() { + assert(getChunk()->isLive() && "relocation against discarded section"); + uint64_t Diff = getRVA() - getChunk()->getOutputSection()->getRVA(); + assert(Diff < UINT32_MAX && "section offset too large"); + return (uint32_t)Diff; +} + +uint16_t Defined::getSectionIndex() { if (auto *D = dyn_cast(this)) return D->getChunk()->getOutputSection()->SectionIndex; - fatal("SECTION relocation points to a non-regular symbol"); + if (isa(this)) + return DefinedAbsolute::OutputSectionIndex; + if (auto *D = dyn_cast(this)) + return D->getSectionIndex(); + if (auto *D = dyn_cast(this)) { + if (!D->getChunk()) + return 0; + return D->getChunk()->getOutputSection()->SectionIndex; + } + fatal("SECTION relocation points to a non-regular symbol: " + + toString(*this)); +} + +uint16_t DefinedCommon::getSectionIndex() { + return Data->getOutputSection()->SectionIndex; } bool Defined::isExecutable() { @@ -345,12 +375,19 @@ void Writer::createMiscChunks() { for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { if (!File->SEHCompat) return; - for (SymbolBody *B : File->SEHandlers) - Handlers.insert(cast(B)); + for (SymbolBody *B : File->SEHandlers) { + // Make sure the handler is still live. Assume all handlers are regular + // symbols. + auto *D = dyn_cast(B); + if (D && D->getChunk()->isLive()) + Handlers.insert(D); + } } - SEHTable = make(Handlers); - RData->addChunk(SEHTable); + if (!Handlers.empty()) { + SEHTable = make(Handlers); + RData->addChunk(SEHTable); + } } // Create .idata section for the DLL-imported symbol table. @@ -442,12 +479,15 @@ size_t Writer::addEntryToStringTable(StringRef Str) { Optional Writer::createSymbol(Defined *Def) { // Relative symbols are unrepresentable in a COFF symbol table. - if (isa(Def)) + if (isa(Def)) return None; - if (auto *D = dyn_cast(Def)) - if (!D->getChunk()->isLive()) + if (auto *D = dyn_cast(Def)) { + // Don't write dead symbols or symbols in codeview sections to the symbol + // table. + if (!D->getChunk()->isLive() || D->getChunk()->isCodeView()) return None; + } if (auto *Sym = dyn_cast(Def)) if (!Sym->File->Live) @@ -599,6 +639,15 @@ template void Writer::writeHeader() { auto *PE = reinterpret_cast(Buf); Buf += sizeof(*PE); PE->Magic = Config->is64() ? PE32Header::PE32_PLUS : PE32Header::PE32; + + // If {Major,Minor}LinkerVersion is left at 0.0, then for some + // reason signing the resulting PE file with Authenticode produces a + // signature that fails to validate on Windows 7 (but is OK on 10). + // Set it to 14.0, which is what VS2015 outputs, and which avoids + // that problem. + PE->MajorLinkerVersion = 14; + PE->MinorLinkerVersion = 0; + PE->ImageBase = Config->ImageBase; PE->SectionAlignment = PageSize; PE->FileAlignment = SectorSize; @@ -743,10 +792,13 @@ void Writer::openFile(StringRef Path) { void Writer::fixSafeSEHSymbols() { if (!SEHTable) return; - if (auto *T = dyn_cast(Config->SEHTable->body())) - T->setRVA(SEHTable->getRVA()); - if (auto *C = dyn_cast(Config->SEHCount->body())) - C->setVA(SEHTable->getSize() / 4); + // Replace the absolute table symbol with a synthetic symbol pointing to the + // SEHTable chunk so that we can emit base relocations for it and resolve + // section relative relocations. + Symbol *T = Symtab->find("___safe_se_handler_table"); + Symbol *C = Symtab->find("___safe_se_handler_count"); + replaceBody(T, T->body()->getName(), SEHTable); + cast(C->body())->setVA(SEHTable->getSize() / 4); } // Handles /section options to allow users to overwrite @@ -762,6 +814,10 @@ void Writer::setSectionPermissions() { // Write section contents to a mmap'ed file. void Writer::writeSections() { + // Record the section index that should be used when resolving a section + // relocation against an absolute symbol. + DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1; + uint8_t *Buf = Buffer->getBufferStart(); for (OutputSection *Sec : OutputSections) { uint8_t *SecBuf = Buf + Sec->getFileOff(); diff --git a/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp b/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp index 113d0960d5f5..b26cf0815109 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/AArch64.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -371,4 +370,7 @@ void AArch64::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); } -TargetInfo *elf::createAArch64TargetInfo() { return make(); } +TargetInfo *elf::getAArch64TargetInfo() { + static AArch64 Target; + return &Target; +} diff --git a/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp b/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp index 68e516f9e6cf..de566c617ac0 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/AMDGPU.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "Target.h" #include "llvm/Object/ELF.h" @@ -79,4 +78,7 @@ RelExpr AMDGPU::getRelExpr(uint32_t Type, const SymbolBody &S, } } -TargetInfo *elf::createAMDGPUTargetInfo() { return make(); } +TargetInfo *elf::getAMDGPUTargetInfo() { + static AMDGPU Target; + return &Target; +} diff --git a/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp b/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp index b245cbd7005a..e4b06ade4487 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/ARM.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -58,6 +57,7 @@ ARM::ARM() { GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 20; + TrapInstr = 0xd4d4d4d4; // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; @@ -429,4 +429,7 @@ int64_t ARM::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { } } -TargetInfo *elf::createARMTargetInfo() { return make(); } +TargetInfo *elf::getARMTargetInfo() { + static ARM Target; + return &Target; +} diff --git a/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp b/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp index 86343a6faa16..3853248f8fbd 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/AVR.cpp @@ -28,7 +28,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "Target.h" #include "llvm/Object/ELF.h" @@ -75,4 +74,7 @@ void AVR::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -TargetInfo *elf::createAVRTargetInfo() { return make(); } +TargetInfo *elf::getAVRTargetInfo() { + static AVR Target; + return &Target; +} diff --git a/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp b/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp index 79642df8a885..b8d796f5897a 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/Mips.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "OutputSections.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -55,6 +54,7 @@ template MIPS::MIPS() { CopyRel = R_MIPS_COPY; PltRel = R_MIPS_JUMP_SLOT; NeedsThunks = true; + TrapInstr = 0xefefefef; if (ELFT::Is64Bits) { RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; @@ -412,11 +412,12 @@ bool MIPS::usesOnlyLowPageBits(uint32_t Type) const { return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST; } -template TargetInfo *elf::createMipsTargetInfo() { - return make>(); +template TargetInfo *elf::getMipsTargetInfo() { + static MIPS Target; + return &Target; } -template TargetInfo *elf::createMipsTargetInfo(); -template TargetInfo *elf::createMipsTargetInfo(); -template TargetInfo *elf::createMipsTargetInfo(); -template TargetInfo *elf::createMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); +template TargetInfo *elf::getMipsTargetInfo(); diff --git a/contrib/llvm/tools/lld/ELF/Mips.cpp b/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp similarity index 99% rename from contrib/llvm/tools/lld/ELF/Mips.cpp rename to contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp index af92fb9d24fd..ed183e9a3061 100644 --- a/contrib/llvm/tools/lld/ELF/Mips.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/MipsArchTree.cpp @@ -1,4 +1,4 @@ -//===- Mips.cpp ----------------------------------------------------------===// +//===- MipsArchTree.cpp --------------------------------------------------===// // // The LLVM Linker // diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp index b5f0d5b4c687..19e10729a00e 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/PPC.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "Target.h" #include "llvm/Support/Endian.h" @@ -22,7 +21,7 @@ using namespace lld::elf; namespace { class PPC final : public TargetInfo { public: - PPC() {} + PPC() { GotBaseSymOff = 0x8000; } void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; @@ -60,4 +59,7 @@ RelExpr PPC::getRelExpr(uint32_t Type, const SymbolBody &S, } } -TargetInfo *elf::createPPCTargetInfo() { return make(); } +TargetInfo *elf::getPPCTargetInfo() { + static PPC Target; + return &Target; +} diff --git a/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp index eb1e917d5790..bf414d75bec7 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/PPC64.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "Error.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -212,4 +211,7 @@ void PPC64::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { } } -TargetInfo *elf::createPPC64TargetInfo() { return make(); } +TargetInfo *elf::getPPC64TargetInfo() { + static PPC64 Target; + return &Target; +} diff --git a/contrib/llvm/tools/lld/ELF/Arch/X86.cpp b/contrib/llvm/tools/lld/ELF/Arch/X86.cpp index bc0d2b81a613..a1e9bcaf1b12 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/X86.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/X86.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -47,6 +46,7 @@ class X86 final : public TargetInfo { } // namespace X86::X86() { + GotBaseSymOff = -1; CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; PltRel = R_386_JUMP_SLOT; @@ -60,9 +60,7 @@ X86::X86() { PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; - - // 0xCC is the "int3" (call debug exception handler) instruction. - TrapInstr = 0xcccccccc; + TrapInstr = 0xcccccccc; // 0xcc = INT3 } RelExpr X86::getRelExpr(uint32_t Type, const SymbolBody &S, @@ -360,4 +358,7 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { memcpy(Loc - 2, Inst, sizeof(Inst)); } -TargetInfo *elf::createX86TargetInfo() { return make(); } +TargetInfo *elf::getX86TargetInfo() { + static X86 Target; + return &Target; +} diff --git a/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp b/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp index b790868c7125..10179f57ee93 100644 --- a/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp +++ b/contrib/llvm/tools/lld/ELF/Arch/X86_64.cpp @@ -9,7 +9,6 @@ #include "Error.h" #include "InputFiles.h" -#include "Memory.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -52,6 +51,7 @@ template class X86_64 final : public TargetInfo { } // namespace template X86_64::X86_64() { + GotBaseSymOff = -1; CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; PltRel = R_X86_64_JUMP_SLOT; @@ -65,13 +65,11 @@ template X86_64::X86_64() { PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; + TrapInstr = 0xcccccccc; // 0xcc = INT3 // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. DefaultImageBase = 0x200000; - - // 0xCC is the "int3" (call debug exception handler) instruction. - TrapInstr = 0xcccccccc; } template @@ -464,5 +462,12 @@ void X86_64::relaxGot(uint8_t *Loc, uint64_t Val) const { write32le(Loc - 1, Val + 1); } -TargetInfo *elf::createX32TargetInfo() { return make>(); } -TargetInfo *elf::createX86_64TargetInfo() { return make>(); } +TargetInfo *elf::getX32TargetInfo() { + static X86_64 Target; + return &Target; +} + +TargetInfo *elf::getX86_64TargetInfo() { + static X86_64 Target; + return &Target; +} diff --git a/contrib/llvm/tools/lld/ELF/CMakeLists.txt b/contrib/llvm/tools/lld/ELF/CMakeLists.txt index 09a19fee14b2..b4bc215a77eb 100644 --- a/contrib/llvm/tools/lld/ELF/CMakeLists.txt +++ b/contrib/llvm/tools/lld/ELF/CMakeLists.txt @@ -12,6 +12,7 @@ add_lld_library(lldELF Arch/ARM.cpp Arch/AVR.cpp Arch/Mips.cpp + Arch/MipsArchTree.cpp Arch/PPC.cpp Arch/PPC64.cpp Arch/X86.cpp @@ -29,7 +30,6 @@ add_lld_library(lldELF LinkerScript.cpp MapFile.cpp MarkLive.cpp - Mips.cpp OutputSections.cpp Relocations.cpp ScriptLexer.cpp diff --git a/contrib/llvm/tools/lld/ELF/Config.h b/contrib/llvm/tools/lld/ELF/Config.h index 9c73b4c9c068..32e86b0ec7b6 100644 --- a/contrib/llvm/tools/lld/ELF/Config.h +++ b/contrib/llvm/tools/lld/ELF/Config.h @@ -70,7 +70,7 @@ struct VersionDefinition { // Structure for mapping renamed symbols struct RenamedSymbol { Symbol *Target; - uint8_t OrigBinding; + uint8_t OriginalBinding; }; // This struct contains the global configuration for the linker. diff --git a/contrib/llvm/tools/lld/ELF/Driver.cpp b/contrib/llvm/tools/lld/ELF/Driver.cpp index f24c941fe773..5fb33caea46f 100644 --- a/contrib/llvm/tools/lld/ELF/Driver.cpp +++ b/contrib/llvm/tools/lld/ELF/Driver.cpp @@ -200,6 +200,7 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { error("attempted static link of dynamic object " + Path); return; } + // DSOs usually have DT_SONAME tags in their ELF headers, and the // sonames are used to identify DSOs. But if they are missing, // they are identified by filenames. We don't know whether the new @@ -210,8 +211,8 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { // If a file was specified by -lfoo, the directory part is not // significant, as a user did not specify it. This behavior is // compatible with GNU. - Files.push_back(createSharedFile( - MBRef, WithLOption ? sys::path::filename(Path) : Path)); + Files.push_back( + createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path)); return; default: if (InLib) @@ -301,7 +302,7 @@ static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key, for (auto *Arg : Args.filtered(OPT_z)) { std::pair KV = StringRef(Arg->getValue()).split('='); if (KV.first == Key) { - uint64_t Result; + uint64_t Result = Default; if (!to_integer(KV.second, Result)) error("invalid " + Key + ": " + KV.second); return Result; @@ -907,12 +908,47 @@ getDefsym(opt::InputArgList &Args) { return Ret; } +// Parses `--exclude-libs=lib,lib,...`. +// The library names may be delimited by commas or colons. +static DenseSet getExcludeLibs(opt::InputArgList &Args) { + DenseSet Ret; + for (auto *Arg : Args.filtered(OPT_exclude_libs)) { + StringRef S = Arg->getValue(); + for (;;) { + size_t Pos = S.find_first_of(",:"); + if (Pos == StringRef::npos) + break; + Ret.insert(S.substr(0, Pos)); + S = S.substr(Pos + 1); + } + Ret.insert(S); + } + return Ret; +} + +// Handles the -exclude-libs option. If a static library file is specified +// by the -exclude-libs option, all public symbols from the archive become +// private unless otherwise specified by version scripts or something. +// A special library name "ALL" means all archive files. +// +// This is not a popular option, but some programs such as bionic libc use it. +static void excludeLibs(opt::InputArgList &Args, ArrayRef Files) { + DenseSet Libs = getExcludeLibs(Args); + bool All = Libs.count("ALL"); + + for (InputFile *File : Files) + if (auto *F = dyn_cast(File)) + if (All || Libs.count(path::filename(F->getName()))) + for (Symbol *Sym : F->getSymbols()) + Sym->VersionId = VER_NDX_LOCAL; +} + // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template void LinkerDriver::link(opt::InputArgList &Args) { SymbolTable Symtab; elf::Symtab::X = &Symtab; - Target = createTarget(); + Target = getTarget(); Config->MaxPageSize = getMaxPageSize(Args); Config->ImageBase = getImageBase(Args); @@ -958,8 +994,17 @@ template void LinkerDriver::link(opt::InputArgList &Args) { if (ErrorCount) return; + // Handle the `--undefined ` options. Symtab.scanUndefinedFlags(); + + // Handle undefined symbols in DSOs. Symtab.scanShlibUndefined(); + + // Handle the -exclude-libs option. + if (Args.hasArg(OPT_exclude_libs)) + excludeLibs(Args, Files); + + // Apply version scripts. Symtab.scanVersionScript(); // Create wrapped symbols for -wrap option. diff --git a/contrib/llvm/tools/lld/ELF/Driver.h b/contrib/llvm/tools/lld/ELF/Driver.h index 8955624dbc12..62d2edf8c53c 100644 --- a/contrib/llvm/tools/lld/ELF/Driver.h +++ b/contrib/llvm/tools/lld/ELF/Driver.h @@ -58,7 +58,7 @@ class ELFOptTable : public llvm::opt::OptTable { // Create enum with OPT_xxx values for each option in Options.td enum { OPT_INVALID = 0, -#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, +#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID, #include "ELF/Options.inc" #undef OPTION }; diff --git a/contrib/llvm/tools/lld/ELF/DriverUtils.cpp b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp index 9b2020472b5f..d1ff70bbf737 100644 --- a/contrib/llvm/tools/lld/ELF/DriverUtils.cpp +++ b/contrib/llvm/tools/lld/ELF/DriverUtils.cpp @@ -42,9 +42,9 @@ using namespace lld::elf; // Create table mapping all options defined in Options.td static const opt::OptTable::Info OptInfo[] = { -#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \ - {X1, X2, X9, X10, OPT_##ID, opt::Option::KIND##Class, \ - X8, X7, OPT_##GROUP, OPT_##ALIAS, X6}, +#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \ + {X1, X2, X10, X11, OPT_##ID, opt::Option::KIND##Class, \ + X9, X8, OPT_##GROUP, OPT_##ALIAS, X7, X12}, #include "ELF/Options.inc" #undef OPTION }; diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.cpp b/contrib/llvm/tools/lld/ELF/InputFiles.cpp index 3d11239bf88f..1ff0b4224e70 100644 --- a/contrib/llvm/tools/lld/ELF/InputFiles.cpp +++ b/contrib/llvm/tools/lld/ELF/InputFiles.cpp @@ -632,8 +632,9 @@ ArchiveFile::ArchiveFile(std::unique_ptr &&File) File(std::move(File)) {} template void ArchiveFile::parse() { + Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symtab::X->addLazyArchive(this, Sym); + Symbols.push_back(Symtab::X->addLazyArchive(this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. diff --git a/contrib/llvm/tools/lld/ELF/InputFiles.h b/contrib/llvm/tools/lld/ELF/InputFiles.h index 2eec78444837..544a0b009b39 100644 --- a/contrib/llvm/tools/lld/ELF/InputFiles.h +++ b/contrib/llvm/tools/lld/ELF/InputFiles.h @@ -251,6 +251,7 @@ class ArchiveFile : public InputFile { explicit ArchiveFile(std::unique_ptr &&File); static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } template void parse(); + ArrayRef getSymbols() { return Symbols; } // Returns a memory buffer for a given symbol and the offset in the archive // for the member. An empty memory buffer and an offset of zero @@ -261,6 +262,7 @@ class ArchiveFile : public InputFile { private: std::unique_ptr File; llvm::DenseSet Seen; + std::vector Symbols; }; class BitcodeFile : public InputFile { diff --git a/contrib/llvm/tools/lld/ELF/InputSection.cpp b/contrib/llvm/tools/lld/ELF/InputSection.cpp index 9aae82bc2992..b1d5e1349460 100644 --- a/contrib/llvm/tools/lld/ELF/InputSection.cpp +++ b/contrib/llvm/tools/lld/ELF/InputSection.cpp @@ -399,9 +399,16 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef Rels) { } } +// The ARM and AArch64 ABI handle pc-relative relocations to undefined weak +// references specially. The general rule is that the value of the symbol in +// this context is the address of the place P. A further special case is that +// branch relocations to an undefined weak reference resolve to the next +// instruction. static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A, uint32_t P) { switch (Type) { + // Unresolved branch relocations to weak references resolve to next + // instruction, this will be either 2 or 4 bytes on from P. case R_ARM_THM_JUMP11: return P + 2 + A; case R_ARM_CALL: @@ -415,22 +422,38 @@ static uint32_t getARMUndefinedRelativeWeakVA(uint32_t Type, uint32_t A, case R_ARM_THM_CALL: // We don't want an interworking BLX to ARM return P + 5 + A; - default: + // Unresolved non branch pc-relative relocations + // R_ARM_TARGET2 which can be resolved relatively is not present as it never + // targets a weak-reference. + case R_ARM_MOVW_PREL_NC: + case R_ARM_MOVT_PREL: + case R_ARM_REL32: + case R_ARM_THM_MOVW_PREL_NC: + case R_ARM_THM_MOVT_PREL: return P + A; } + llvm_unreachable("ARM pc-relative relocation expected\n"); } +// The comment above getARMUndefinedRelativeWeakVA applies to this function. static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, uint64_t P) { switch (Type) { + // Unresolved branch relocations to weak references resolve to next + // instruction, this is 4 bytes on from P. case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: return P + 4 + A; - default: + // Unresolved non branch pc-relative relocations + case R_AARCH64_PREL16: + case R_AARCH64_PREL32: + case R_AARCH64_PREL64: + case R_AARCH64_ADR_PREL_LO21: return P + A; } + llvm_unreachable("AArch64 pc-relative relocation expected\n"); } // ARM SBREL relocations are of the form S + A - B where B is the static base diff --git a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp index f5a59f0c8c4d..d369a6f978a2 100644 --- a/contrib/llvm/tools/lld/ELF/LinkerScript.cpp +++ b/contrib/llvm/tools/lld/ELF/LinkerScript.cpp @@ -338,8 +338,9 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { void LinkerScript::discard(ArrayRef V) { for (InputSectionBase *S : V) { S->Live = false; - if (S == InX::ShStrTab) - error("discarding .shstrtab section is not allowed"); + if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab || + S == InX::DynStrTab) + error("discarding " + S->Name + " section is not allowed"); discard(S->DependentSections); } } @@ -463,11 +464,6 @@ void LinkerScript::fabricateDefaultCommands() { OSCmd->Sec = Sec; SecToCommand[Sec] = OSCmd; - // Prefer user supplied address over additional alignment constraint - auto I = Config->SectionStartMap.find(Sec->Name); - if (I != Config->SectionStartMap.end()) - OSCmd->AddrExpr = [=] { return I->second; }; - Commands.push_back(OSCmd); if (Sec->Sections.size()) { auto *ISD = make(""); @@ -953,6 +949,8 @@ static bool compareByFilePosition(InputSection *A, InputSection *B) { template static void finalizeShtGroup(OutputSection *OS, ArrayRef Sections) { + assert(Config->Relocatable && Sections.size() == 1); + // sh_link field for SHT_GROUP sections should contain the section index of // the symbol table. OS->Link = InX::SymTab->getParent()->SectionIndex; @@ -960,7 +958,6 @@ static void finalizeShtGroup(OutputSection *OS, // sh_info then contain index of an entry in symbol table section which // provides signature of the section group. elf::ObjectFile *Obj = Sections[0]->getFile(); - assert(Config->Relocatable && Sections.size() == 1); ArrayRef Symbols = Obj->getSymbols(); OS->Info = InX::SymTab->getSymbolIndex(Symbols[Sections[0]->Info - 1]); } @@ -1044,8 +1041,9 @@ template void OutputSectionCommand::writeTo(uint8_t *Buf) { Sec->Loc = Buf; - // We may have already rendered compressed content when using - // -compress-debug-sections option. Write it together with header. + // If -compress-debug-section is specified and if this is a debug seciton, + // we've already compressed section contents. If that's the case, + // just write it down. if (!Sec->CompressedData.empty()) { memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), @@ -1109,18 +1107,27 @@ ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; } +static const size_t NoPhdr = -1; + // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. std::vector LinkerScript::getPhdrIndices(OutputSection *Sec) { if (OutputSectionCommand *Cmd = getCmd(Sec)) { std::vector Ret; - for (StringRef PhdrName : Cmd->Phdrs) - Ret.push_back(getPhdrIndex(Cmd->Location, PhdrName)); + for (StringRef PhdrName : Cmd->Phdrs) { + size_t Index = getPhdrIndex(Cmd->Location, PhdrName); + if (Index != NoPhdr) + Ret.push_back(Index); + } return Ret; } return {}; } +// Returns the index of the segment named PhdrName if found otherwise +// NoPhdr. When not found, if PhdrName is not the special case value 'NONE' +// (which can be used to explicitly specify that a section isn't assigned to a +// segment) then error. size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { size_t I = 0; for (PhdrsCommand &Cmd : Opt.PhdrsCommands) { @@ -1128,8 +1135,9 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { return I; ++I; } - error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); - return 0; + if (PhdrName != "NONE") + error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); + return NoPhdr; } template void OutputSectionCommand::writeTo(uint8_t *Buf); diff --git a/contrib/llvm/tools/lld/ELF/MarkLive.cpp b/contrib/llvm/tools/lld/ELF/MarkLive.cpp index 0b4a78f8da6b..bde3eefc6d5f 100644 --- a/contrib/llvm/tools/lld/ELF/MarkLive.cpp +++ b/contrib/llvm/tools/lld/ELF/MarkLive.cpp @@ -78,7 +78,7 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel, typename ELFT::uint Offset = D->Value; if (D->isSection()) Offset += getAddend(Sec, Rel); - Fn({cast(D->Section)->Repl, Offset}); + Fn({cast(D->Section), Offset}); } else if (auto *U = dyn_cast(&B)) { for (InputSectionBase *Sec : CNamedSections.lookup(U->getName())) Fn({Sec, 0}); diff --git a/contrib/llvm/tools/lld/ELF/Options.td b/contrib/llvm/tools/lld/ELF/Options.td index 335c7ade6db2..29e14c530c6a 100644 --- a/contrib/llvm/tools/lld/ELF/Options.td +++ b/contrib/llvm/tools/lld/ELF/Options.td @@ -92,6 +92,9 @@ def error_limit: S<"error-limit">, def error_unresolved_symbols: F<"error-unresolved-symbols">, HelpText<"Report unresolved symbols as errors">; +def exclude_libs: S<"exclude-libs">, + HelpText<"Exclude static libraries from automatic export">; + def export_dynamic: F<"export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; @@ -298,6 +301,7 @@ def alias_emit_relocs: Flag<["-"], "q">, Alias; def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias; def alias_entry_entry: J<"entry=">, Alias; def alias_error_limit: J<"error-limit=">, Alias; +def alias_exclude_libs: J<"exclude-libs=">, Alias; def alias_export_dynamic_E: Flag<["-"], "E">, Alias; def alias_export_dynamic_symbol: J<"export-dynamic-symbol=">, Alias; diff --git a/contrib/llvm/tools/lld/ELF/OutputSections.cpp b/contrib/llvm/tools/lld/ELF/OutputSections.cpp index 6f04a04be8d0..c0bf6b32e6e2 100644 --- a/contrib/llvm/tools/lld/ELF/OutputSections.cpp +++ b/contrib/llvm/tools/lld/ELF/OutputSections.cpp @@ -273,7 +273,7 @@ void elf::reportDiscarded(InputSectionBase *IS) { if (!Config->PrintGcSections) return; message("removing unused section from '" + IS->Name + "' in file '" + - IS->File->getName()); + IS->File->getName() + "'"); } void OutputSectionFactory::addInputSec(InputSectionBase *IS, @@ -305,7 +305,7 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS, SectionKey Key = createKey(IS, OutsecName); OutputSection *&Sec = Map[Key]; - return addInputSec(IS, OutsecName, Sec); + addInputSec(IS, OutsecName, Sec); } void OutputSectionFactory::addInputSec(InputSectionBase *IS, diff --git a/contrib/llvm/tools/lld/ELF/Relocations.cpp b/contrib/llvm/tools/lld/ELF/Relocations.cpp index 1ac3bce769ee..fd823fe0ed42 100644 --- a/contrib/llvm/tools/lld/ELF/Relocations.cpp +++ b/contrib/llvm/tools/lld/ELF/Relocations.cpp @@ -361,7 +361,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, // These expressions always compute a constant if (isRelExprOneOf(E)) return true; diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp index a223aec98624..ab8802c86d8e 100644 --- a/contrib/llvm/tools/lld/ELF/SymbolTable.cpp +++ b/contrib/llvm/tools/lld/ELF/SymbolTable.cpp @@ -167,8 +167,8 @@ template void SymbolTable::addSymbolWrap(StringRef Name) { // Tell LTO not to eliminate this symbol Wrap->IsUsedInRegularObj = true; - Config->RenamedSymbols[Real] = RenamedSymbol{Sym, Real->Binding}; - Config->RenamedSymbols[Sym] = RenamedSymbol{Wrap, Sym->Binding}; + Config->RenamedSymbols[Real] = {Sym, Real->Binding}; + Config->RenamedSymbols[Sym] = {Wrap, Sym->Binding}; } // Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. @@ -184,7 +184,7 @@ template void SymbolTable::addSymbolAlias(StringRef Alias, // Tell LTO not to eliminate this symbol Sym->IsUsedInRegularObj = true; - Config->RenamedSymbols[AliasSym] = RenamedSymbol{Sym, AliasSym->Binding}; + Config->RenamedSymbols[AliasSym] = {Sym, AliasSym->Binding}; } // Apply symbol renames created by -wrap and -defsym. The renames are created @@ -193,14 +193,16 @@ template void SymbolTable::addSymbolAlias(StringRef Alias, // symbols are finalized, we can perform the replacement. template void SymbolTable::applySymbolRenames() { for (auto &KV : Config->RenamedSymbols) { - Symbol *Sym = KV.first; - Symbol *Rename = KV.second.Target; - Sym->Binding = KV.second.OrigBinding; + Symbol *Dst = KV.first; + Symbol *Src = KV.second.Target; + Dst->Binding = KV.second.OriginalBinding; - // We rename symbols by replacing the old symbol's SymbolBody with the new - // symbol's SymbolBody. This causes all SymbolBody pointers referring to the - // old symbol to instead refer to the new symbol. - memcpy(Sym->Body.buffer, Rename->Body.buffer, sizeof(Sym->Body)); + // We rename symbols by replacing the old symbol's SymbolBody with + // the new symbol's SymbolBody. The only attribute we want to keep + // is the symbol name, so that two symbols don't have the same name. + StringRef S = Dst->body()->getName(); + memcpy(Dst->Body.buffer, Src->Body.buffer, sizeof(Symbol::Body)); + Dst->body()->setName(S); } } @@ -518,18 +520,18 @@ SymbolBody *SymbolTable::findInCurrentDSO(StringRef Name) { } template -void SymbolTable::addLazyArchive(ArchiveFile *F, - const object::Archive::Symbol Sym) { +Symbol *SymbolTable::addLazyArchive(ArchiveFile *F, + const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; StringRef Name = Sym.getName(); std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody(S, *F, Sym, SymbolBody::UnknownType); - return; + return S; } if (!S->body()->isUndefined()) - return; + return S; // Weak undefined symbols should not fetch members from archives. If we were // to keep old symbol we would not know that an archive member was available @@ -540,11 +542,12 @@ void SymbolTable::addLazyArchive(ArchiveFile *F, // to preserve its type. FIXME: Move the Type field to Symbol. if (S->isWeak()) { replaceBody(S, *F, Sym, S->body()->Type); - return; + return S; } std::pair MBInfo = F->getMember(&Sym); if (!MBInfo.first.getBuffer().empty()) addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); + return S; } template diff --git a/contrib/llvm/tools/lld/ELF/SymbolTable.h b/contrib/llvm/tools/lld/ELF/SymbolTable.h index f38d09760c7e..316d9c9bf373 100644 --- a/contrib/llvm/tools/lld/ELF/SymbolTable.h +++ b/contrib/llvm/tools/lld/ELF/SymbolTable.h @@ -66,7 +66,7 @@ template class SymbolTable { void addShared(SharedFile *F, StringRef Name, const Elf_Sym &Sym, const typename ELFT::Verdef *Verdef); - void addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S); + Symbol *addLazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S); void addLazyObject(StringRef Name, LazyObjectFile &Obj); Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File); diff --git a/contrib/llvm/tools/lld/ELF/Symbols.cpp b/contrib/llvm/tools/lld/ELF/Symbols.cpp index 8f9b20477b29..5dce71a32c9c 100644 --- a/contrib/llvm/tools/lld/ELF/Symbols.cpp +++ b/contrib/llvm/tools/lld/ELF/Symbols.cpp @@ -35,6 +35,7 @@ DefinedRegular *ElfSym::Edata1; DefinedRegular *ElfSym::Edata2; DefinedRegular *ElfSym::End1; DefinedRegular *ElfSym::End2; +DefinedRegular *ElfSym::GlobalOffsetTable; DefinedRegular *ElfSym::MipsGp; DefinedRegular *ElfSym::MipsGpDisp; DefinedRegular *ElfSym::MipsLocalGp; diff --git a/contrib/llvm/tools/lld/ELF/Symbols.h b/contrib/llvm/tools/lld/ELF/Symbols.h index 030527f63744..406fd8e0f57b 100644 --- a/contrib/llvm/tools/lld/ELF/Symbols.h +++ b/contrib/llvm/tools/lld/ELF/Symbols.h @@ -69,6 +69,7 @@ class SymbolBody { bool isLocal() const { return IsLocal; } bool isPreemptible() const; StringRef getName() const { return Name; } + void setName(StringRef S) { Name = S; } uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); @@ -317,6 +318,11 @@ struct ElfSym { static DefinedRegular *End1; static DefinedRegular *End2; + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to + // be at some offset from the base of the .got section, usually 0 or + // the end of the .got. + static DefinedRegular *GlobalOffsetTable; + // _gp, _gp_disp and __gnu_local_gp symbols. Only for MIPS. static DefinedRegular *MipsGp; static DefinedRegular *MipsGpDisp; diff --git a/contrib/llvm/tools/lld/ELF/Target.cpp b/contrib/llvm/tools/lld/ELF/Target.cpp index df3f4d6773f0..c1a85e165258 100644 --- a/contrib/llvm/tools/lld/ELF/Target.cpp +++ b/contrib/llvm/tools/lld/ELF/Target.cpp @@ -47,40 +47,40 @@ std::string lld::toString(uint32_t Type) { return S; } -TargetInfo *elf::createTarget() { +TargetInfo *elf::getTarget() { switch (Config->EMachine) { case EM_386: case EM_IAMCU: - return createX86TargetInfo(); + return getX86TargetInfo(); case EM_AARCH64: - return createAArch64TargetInfo(); + return getAArch64TargetInfo(); case EM_AMDGPU: - return createAMDGPUTargetInfo(); + return getAMDGPUTargetInfo(); case EM_ARM: - return createARMTargetInfo(); + return getARMTargetInfo(); case EM_AVR: - return createAVRTargetInfo(); + return getAVRTargetInfo(); case EM_MIPS: switch (Config->EKind) { case ELF32LEKind: - return createMipsTargetInfo(); + return getMipsTargetInfo(); case ELF32BEKind: - return createMipsTargetInfo(); + return getMipsTargetInfo(); case ELF64LEKind: - return createMipsTargetInfo(); + return getMipsTargetInfo(); case ELF64BEKind: - return createMipsTargetInfo(); + return getMipsTargetInfo(); default: fatal("unsupported MIPS target"); } case EM_PPC: - return createPPCTargetInfo(); + return getPPCTargetInfo(); case EM_PPC64: - return createPPC64TargetInfo(); + return getPPC64TargetInfo(); case EM_X86_64: if (Config->EKind == ELF32LEKind) - return createX32TargetInfo(); - return createX86_64TargetInfo(); + return getX32TargetInfo(); + return getX86_64TargetInfo(); } fatal("unknown target machine"); } diff --git a/contrib/llvm/tools/lld/ELF/Target.h b/contrib/llvm/tools/lld/ELF/Target.h index 79b03f876d0d..bf703fd0086a 100644 --- a/contrib/llvm/tools/lld/ELF/Target.h +++ b/contrib/llvm/tools/lld/ELF/Target.h @@ -66,6 +66,10 @@ class TargetInfo { // Given that, the smallest value that can be used in here is 0x10000. uint64_t DefaultImageBase = 0x10000; + // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for + // end of .got + uint64_t GotBaseSymOff = 0; + uint32_t CopyRel; uint32_t GotRel; uint32_t PltRel; @@ -102,16 +106,16 @@ class TargetInfo { virtual void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; }; -TargetInfo *createAArch64TargetInfo(); -TargetInfo *createAMDGPUTargetInfo(); -TargetInfo *createARMTargetInfo(); -TargetInfo *createAVRTargetInfo(); -TargetInfo *createPPC64TargetInfo(); -TargetInfo *createPPCTargetInfo(); -TargetInfo *createX32TargetInfo(); -TargetInfo *createX86TargetInfo(); -TargetInfo *createX86_64TargetInfo(); -template TargetInfo *createMipsTargetInfo(); +TargetInfo *getAArch64TargetInfo(); +TargetInfo *getAMDGPUTargetInfo(); +TargetInfo *getARMTargetInfo(); +TargetInfo *getAVRTargetInfo(); +TargetInfo *getPPC64TargetInfo(); +TargetInfo *getPPCTargetInfo(); +TargetInfo *getX32TargetInfo(); +TargetInfo *getX86TargetInfo(); +TargetInfo *getX86_64TargetInfo(); +template TargetInfo *getMipsTargetInfo(); std::string getErrorLocation(const uint8_t *Loc); @@ -119,7 +123,7 @@ uint64_t getPPC64TocBase(); uint64_t getAArch64Page(uint64_t Expr); extern TargetInfo *Target; -TargetInfo *createTarget(); +TargetInfo *getTarget(); template static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) { diff --git a/contrib/llvm/tools/lld/ELF/Writer.cpp b/contrib/llvm/tools/lld/ELF/Writer.cpp index 4ff06388ec78..4c12b18836bf 100644 --- a/contrib/llvm/tools/lld/ELF/Writer.cpp +++ b/contrib/llvm/tools/lld/ELF/Writer.cpp @@ -87,6 +87,8 @@ template class Writer { uint64_t FileSize; uint64_t SectionHeaderOff; + + bool HasGotBaseSym = false; }; } // anonymous namespace @@ -815,19 +817,13 @@ template void Writer::addReservedSymbols() { Symtab::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); } - // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol - // is magical and is used to produce a R_386_GOTPC relocation. - // The R_386_GOTPC relocation value doesn't actually depend on the - // symbol value, so it could use an index of STN_UNDEF which, according - // to the spec, means the symbol value is 0. - // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in - // the object file. - // The situation is even stranger on x86_64 where the assembly doesn't - // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as - // an undefined symbol in the .o files. - // Given that the symbol is effectively unused, we just create a dummy - // hidden one to avoid the undefined symbol error. - Symtab::X->addIgnored("_GLOBAL_OFFSET_TABLE_"); + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to + // be at some offset from the base of the .got section, usually 0 or the end + // of the .got + InputSection *GotSection = InX::MipsGot ? cast(InX::MipsGot) + : cast(InX::Got); + ElfSym::GlobalOffsetTable = addOptionalRegular( + "_GLOBAL_OFFSET_TABLE_", GotSection, Target->GotBaseSymOff); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to @@ -1147,6 +1143,8 @@ static void removeUnusedSyntheticSections(std::vector &V) { OutputSection *OS = SS->getParent(); if (!SS->empty() || !OS) continue; + if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable) + continue; OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS)); SS->Live = false; // If there are no other sections in the output section, remove it from the @@ -1231,6 +1229,13 @@ template void Writer::finalizeSections() { if (auto *Cmd = dyn_cast(Base)) OutputSectionCommands.push_back(Cmd); + // Prefer command line supplied address over other constraints. + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + auto I = Config->SectionStartMap.find(Cmd->Name); + if (I != Config->SectionStartMap.end()) + Cmd->AddrExpr = [=] { return I->second; }; + } + // This is a bit of a hack. A value of 0 means undef, so we set it // to 1 t make __ehdr_start defined. The section number is not // particularly relevant. diff --git a/contrib/llvm/tools/lld/README.md b/contrib/llvm/tools/lld/README.md index dc05cdea0a12..38a6b48b1841 100644 --- a/contrib/llvm/tools/lld/README.md +++ b/contrib/llvm/tools/lld/README.md @@ -8,3 +8,4 @@ infrastructure project. lld is open source software. You may freely distribute it under the terms of the license agreement found in LICENSE.txt. + diff --git a/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp b/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp index c859c9802349..f564d8cb8d7e 100644 --- a/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp +++ b/contrib/llvm/tools/lld/lib/Driver/DarwinLdDriver.cpp @@ -61,9 +61,9 @@ namespace { // Create enum with OPT_xxx values for each option in DarwinLdOptions.td enum { OPT_INVALID = 0, -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELP, META) \ - OPT_##ID, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELP, META, VALUES) \ + OPT_##ID, #include "DarwinLdOptions.inc" #undef OPTION }; @@ -75,10 +75,12 @@ enum { // Create table mapping all options defined in DarwinLdOptions.td static const llvm::opt::OptTable::Info infoTable[] = { -#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ - PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS }, +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + {PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, #include "DarwinLdOptions.inc" #undef OPTION }; diff --git a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 18fb71f16bcf..226a25d3c1ed 100644 --- a/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/contrib/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -906,6 +906,7 @@ readCompUnit(const NormalizedFile &normalizedFile, abbrevData.getU8(&abbrevOffset); uint32_t name; llvm::dwarf::Form form; + llvm::DWARFFormParams formParams = {version, addrSize, Format}; TranslationUnitSource tu; while ((name = abbrevData.getULEB128(&abbrevOffset)) | (form = static_cast( @@ -929,8 +930,7 @@ readCompUnit(const NormalizedFile &normalizedFile, break; } default: - llvm::DWARFFormValue::skipValue(form, infoData, &offset, version, - addrSize, Format); + llvm::DWARFFormValue::skipValue(form, infoData, &offset, formParams); } } return tu; diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/Host.h b/contrib/llvm/tools/lldb/include/lldb/Host/Host.h index c474dccab5db..bf48e207f1f2 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/Host.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/Host.h @@ -28,6 +28,27 @@ namespace lldb_private { class FileAction; class ProcessLaunchInfo; +//---------------------------------------------------------------------- +// Exit Type for inferior processes +//---------------------------------------------------------------------- +struct WaitStatus { + enum Type : uint8_t { + Exit, // The status represents the return code from normal + // program exit (i.e. WIFEXITED() was true) + Signal, // The status represents the signal number that caused + // the program to exit (i.e. WIFSIGNALED() was true) + Stop, // The status represents the signal number that caused the + // program to stop (i.e. WIFSTOPPED() was true) + }; + + Type type; + uint8_t status; + + WaitStatus(Type type, uint8_t status) : type(type), status(status) {} + + static WaitStatus Decode(int wstatus); +}; + //---------------------------------------------------------------------- /// @class Host Host.h "lldb/Host/Host.h" /// @brief A class that provides host computer information. @@ -111,15 +132,6 @@ class Host { static const char *GetSignalAsCString(int signo); - typedef void (*ThreadLocalStorageCleanupCallback)(void *p); - - static lldb::thread_key_t - ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback); - - static void *ThreadLocalStorageGet(lldb::thread_key_t key); - - static void ThreadLocalStorageSet(lldb::thread_key_t key, void *value); - //------------------------------------------------------------------ /// Given an address in the current process (the process that /// is running the LLDB code), return the name of the module that @@ -184,22 +196,6 @@ class Host { static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info); -#if (defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \ - defined(__GLIBC__) || defined(__NetBSD__) || defined(__OpenBSD__)) && \ - !defined(__ANDROID__) - - static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info); - - static Status LaunchProcessPosixSpawn(const char *exe_path, - const ProcessLaunchInfo &launch_info, - lldb::pid_t &pid); - - static bool AddPosixSpawnFileAction(void *file_actions, - const FileAction *info, Log *log, - Status &error); - -#endif - static const lldb::UnixSignalsSP &GetUnixSignals(); static Status LaunchProcess(ProcessLaunchInfo &launch_info); @@ -246,5 +242,14 @@ class Host { } // namespace lldb_private +namespace llvm { +template <> struct format_provider { + /// Options = "" gives a human readable description of the status + /// Options = "g" gives a gdb-remote protocol status (e.g., X09) + static void format(const lldb_private::WaitStatus &WS, raw_ostream &OS, + llvm::StringRef Options); +}; +} // namespace llvm + #endif // #if defined(__cplusplus) #endif // liblldb_Host_h_ diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h index 55eca0fa0b65..c43299a1df3d 100644 --- a/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ b/contrib/llvm/tools/lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -11,6 +11,7 @@ #define liblldb_NativeProcessProtocol_h_ #include "lldb/Core/TraceOptions.h" +#include "lldb/Host/Host.h" #include "lldb/Host/MainLoop.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-private-forward.h" @@ -158,12 +159,9 @@ class NativeProcessProtocol //---------------------------------------------------------------------- // Exit Status //---------------------------------------------------------------------- - virtual bool GetExitStatus(lldb_private::ExitType *exit_type, int *status, - std::string &exit_description); + virtual llvm::Optional GetExitStatus(); - virtual bool SetExitStatus(lldb_private::ExitType exit_type, int status, - const char *exit_description, - bool bNotifyStateChange); + virtual bool SetExitStatus(WaitStatus status, bool bNotifyStateChange); //---------------------------------------------------------------------- // Access to threads @@ -421,9 +419,8 @@ class NativeProcessProtocol lldb::StateType m_state; mutable std::recursive_mutex m_state_mutex; - lldb_private::ExitType m_exit_type; - int m_exit_status; - std::string m_exit_description; + llvm::Optional m_exit_status; + std::recursive_mutex m_delegates_mutex; std::vector m_delegates; NativeBreakpointList m_breakpoint_list; diff --git a/contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosix.h b/contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosix.h deleted file mode 100644 index 4800c4066049..000000000000 --- a/contrib/llvm/tools/lldb/include/lldb/Host/posix/ProcessLauncherPosix.h +++ /dev/null @@ -1,24 +0,0 @@ -//===-- ProcessLauncherPosix.h ----------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef lldb_Host_posix_ProcessLauncherPosix_h_ -#define lldb_Host_posix_ProcessLauncherPosix_h_ - -#include "lldb/Host/ProcessLauncher.h" - -namespace lldb_private { - -class ProcessLauncherPosix : public ProcessLauncher { -public: - HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, - Status &error) override; -}; -} - -#endif diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h b/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h index f62b3cc0b19b..3c60873f6796 100644 --- a/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h +++ b/contrib/llvm/tools/lldb/include/lldb/lldb-enumerations.h @@ -454,6 +454,8 @@ enum LanguageType { enum InstrumentationRuntimeType { eInstrumentationRuntimeTypeAddressSanitizer = 0x0000, eInstrumentationRuntimeTypeThreadSanitizer = 0x0001, + eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer = 0x0002, + eInstrumentationRuntimeTypeMainThreadChecker = 0x0003, eNumInstrumentationRuntimeTypes }; diff --git a/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h b/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h index 332265665237..983ddf3d23d6 100644 --- a/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h +++ b/contrib/llvm/tools/lldb/include/lldb/lldb-private-enumerations.h @@ -211,19 +211,6 @@ enum class LineStatus { Done // Lines are complete }; -//---------------------------------------------------------------------- -// Exit Type for inferior processes -//---------------------------------------------------------------------- -typedef enum ExitType { - eExitTypeInvalid, - eExitTypeExit, // The exit status represents the return code from normal - // program exit (i.e. WIFEXITED() was true) - eExitTypeSignal, // The exit status represents the signal number that caused - // the program to exit (i.e. WIFSIGNALED() was true) - eExitTypeStop, // The exit status represents the stop signal that caused the - // program to exit (i.e. WIFSTOPPED() was true) -} ExitType; - //---------------------------------------------------------------------- // Boolean result of running a Type Validator //---------------------------------------------------------------------- diff --git a/contrib/llvm/tools/lldb/source/API/SBThread.cpp b/contrib/llvm/tools/lldb/source/API/SBThread.cpp index 65ccb465c8da..d9ce6be3f893 100644 --- a/contrib/llvm/tools/lldb/source/API/SBThread.cpp +++ b/contrib/llvm/tools/lldb/source/API/SBThread.cpp @@ -293,10 +293,6 @@ SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) { ThreadCollectionSP threads; threads.reset(new ThreadCollection()); - // We currently only support ThreadSanitizer. - if (type != eInstrumentationRuntimeTypeThreadSanitizer) - return threads; - std::unique_lock lock; ExecutionContext exe_ctx(m_opaque_sp.get(), lock); diff --git a/contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp b/contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp index 64ea3575e5f4..f4cc4581960a 100644 --- a/contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp +++ b/contrib/llvm/tools/lldb/source/API/SystemInitializerFull.cpp @@ -49,8 +49,10 @@ #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" //#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h" #include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h" -#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h" -//#include "Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h" +#include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h" +//#include "Plugins/InstrumentationRuntime/TSan/TSanRuntime.h" +#include "Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h" +#include "Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h" #include "Plugins/JITLoader/GDB/JITLoaderGDB.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" //#include "Plugins/Language/Go/GoLanguage.h" @@ -310,6 +312,8 @@ void SystemInitializerFull::Initialize() { MemoryHistoryASan::Initialize(); AddressSanitizerRuntime::Initialize(); //ThreadSanitizerRuntime::Initialize(); + UndefinedBehaviorSanitizerRuntime::Initialize(); + MainThreadCheckerRuntime::Initialize(); SymbolVendorELF::Initialize(); SymbolFileDWARF::Initialize(); @@ -434,6 +438,8 @@ void SystemInitializerFull::Terminate() { MemoryHistoryASan::Terminate(); AddressSanitizerRuntime::Terminate(); //ThreadSanitizerRuntime::Terminate(); + UndefinedBehaviorSanitizerRuntime::Terminate(); + MainThreadCheckerRuntime::Terminate(); SymbolVendorELF::Terminate(); SymbolFileDWARF::Terminate(); //SymbolFilePDB::Terminate(); diff --git a/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp b/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp index 8b981a93ad7f..9e1805f2eed6 100644 --- a/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp +++ b/contrib/llvm/tools/lldb/source/Commands/CommandObjectFrame.cpp @@ -655,32 +655,30 @@ class CommandObjectFrameVariable : public CommandObjectParsed { if (num_variables > 0) { for (size_t i = 0; i < num_variables; i++) { var_sp = variable_list->GetVariableAtIndex(i); - switch (var_sp->GetScope()) - { - case eValueTypeVariableGlobal: - if (!m_option_variable.show_globals) - continue; - break; - case eValueTypeVariableStatic: - if (!m_option_variable.show_globals) - continue; - break; - case eValueTypeVariableArgument: - if (!m_option_variable.show_args) - continue; - break; - case eValueTypeVariableLocal: - if (!m_option_variable.show_locals) - continue; - break; - default: + switch (var_sp->GetScope()) { + case eValueTypeVariableGlobal: + if (!m_option_variable.show_globals) continue; - break; - + break; + case eValueTypeVariableStatic: + if (!m_option_variable.show_globals) + continue; + break; + case eValueTypeVariableArgument: + if (!m_option_variable.show_args) + continue; + break; + case eValueTypeVariableLocal: + if (!m_option_variable.show_locals) + continue; + break; + default: + continue; + break; } - std::string scope_string; - if (m_option_variable.show_scope) - scope_string = GetScopeString(var_sp).str(); + std::string scope_string; + if (m_option_variable.show_scope) + scope_string = GetScopeString(var_sp).str(); // Use the variable object code to make sure we are // using the same APIs as the public API will be diff --git a/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp b/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp index 3cb1ffab3a0e..194fec8a8798 100644 --- a/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp +++ b/contrib/llvm/tools/lldb/source/Core/IOHandler.cpp @@ -58,7 +58,7 @@ #include "llvm/ADT/StringRef.h" // for StringRef #ifdef _MSC_VER -#include +#include "lldb/Host/windows/windows.h" #endif #include // for shared_ptr diff --git a/contrib/llvm/tools/lldb/source/Core/Mangled.cpp b/contrib/llvm/tools/lldb/source/Core/Mangled.cpp index c2e9b8904a0a..4dac0b8f3bf1 100644 --- a/contrib/llvm/tools/lldb/source/Core/Mangled.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Mangled.cpp @@ -10,7 +10,7 @@ #include "lldb/Core/Mangled.h" #if defined(_WIN32) -#include +#include "lldb/Host/windows/windows.h" #include #pragma comment(lib, "dbghelp.lib") diff --git a/contrib/llvm/tools/lldb/source/Core/Timer.cpp b/contrib/llvm/tools/lldb/source/Core/Timer.cpp index 6de4516f721d..59c3e13a717e 100644 --- a/contrib/llvm/tools/lldb/source/Core/Timer.cpp +++ b/contrib/llvm/tools/lldb/source/Core/Timer.cpp @@ -38,20 +38,9 @@ static std::mutex &GetFileMutex() { return *g_file_mutex_ptr; } -static void ThreadSpecificCleanup(void *p) { - delete static_cast(p); -} - -static TimerStack *GetTimerStackForCurrentThread() { - static lldb::thread_key_t g_key = - Host::ThreadLocalStorageCreate(ThreadSpecificCleanup); - - void *timer_stack = Host::ThreadLocalStorageGet(g_key); - if (timer_stack == NULL) { - Host::ThreadLocalStorageSet(g_key, new TimerStack); - timer_stack = Host::ThreadLocalStorageGet(g_key); - } - return (TimerStack *)timer_stack; +static TimerStack &GetTimerStackForCurrentThread() { + static thread_local TimerStack g_stack; + return g_stack; } Timer::Category::Category(const char *cat) : m_name(cat) { @@ -66,16 +55,14 @@ void Timer::SetQuiet(bool value) { g_quiet = value; } Timer::Timer(Timer::Category &category, const char *format, ...) : m_category(category), m_total_start(std::chrono::steady_clock::now()) { - TimerStack *stack = GetTimerStackForCurrentThread(); - if (!stack) - return; + TimerStack &stack = GetTimerStackForCurrentThread(); - stack->push_back(this); - if (g_quiet && stack->size() <= g_display_depth) { + stack.push_back(this); + if (g_quiet && stack.size() <= g_display_depth) { std::lock_guard lock(GetFileMutex()); // Indent - ::fprintf(stdout, "%*s", int(stack->size() - 1) * TIMER_INDENT_AMOUNT, ""); + ::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, ""); // Print formatted string va_list args; va_start(args, format); @@ -90,26 +77,23 @@ Timer::Timer(Timer::Category &category, const char *format, ...) Timer::~Timer() { using namespace std::chrono; - TimerStack *stack = GetTimerStackForCurrentThread(); - if (!stack) - return; - auto stop_time = steady_clock::now(); auto total_dur = stop_time - m_total_start; auto timer_dur = total_dur - m_child_duration; - if (g_quiet && stack->size() <= g_display_depth) { + TimerStack &stack = GetTimerStackForCurrentThread(); + if (g_quiet && stack.size() <= g_display_depth) { std::lock_guard lock(GetFileMutex()); ::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n", - int(stack->size() - 1) * TIMER_INDENT_AMOUNT, "", + int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "", duration(total_dur).count(), duration(timer_dur).count()); } - assert(stack->back() == this); - stack->pop_back(); - if (!stack->empty()) - stack->back()->ChildDuration(total_dur); + assert(stack.back() == this); + stack.pop_back(); + if (!stack.empty()) + stack.back()->ChildDuration(total_dur); // Keep total results for each category so we can dump results. m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count(); diff --git a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp index d78961e5bffc..af0b57248922 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/Host.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/Host.cpp @@ -68,15 +68,14 @@ #include "lldb/Utility/Status.h" #include "lldb/lldb-private-forward.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" #if defined(_WIN32) #include "lldb/Host/windows/ProcessLauncherWindows.h" -#elif defined(__linux__) || defined(__NetBSD__) -#include "lldb/Host/posix/ProcessLauncherPosixFork.h" #else -#include "lldb/Host/posix/ProcessLauncherPosix.h" +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" #endif #if defined(__APPLE__) @@ -407,25 +406,6 @@ const char *Host::GetSignalAsCString(int signo) { #endif -#ifndef _WIN32 - -lldb::thread_key_t -Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) { - pthread_key_t key; - ::pthread_key_create(&key, callback); - return key; -} - -void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) { - return ::pthread_getspecific(key); -} - -void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) { - ::pthread_setspecific(key, value); -} - -#endif - #if !defined(__APPLE__) // see Host.mm bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) { @@ -602,359 +582,14 @@ Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir, return error; } -// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD, NetBSD and other GLIBC -// systems - -#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \ - defined(__GLIBC__) || defined(__NetBSD__) -#if !defined(__ANDROID__) -// this method needs to be visible to macosx/Host.cpp and -// common/Host.cpp. - -short Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { - short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; - -#if defined(__APPLE__) - if (launch_info.GetFlags().Test(eLaunchFlagExec)) - flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag - - if (launch_info.GetFlags().Test(eLaunchFlagDebug)) - flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag - - if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR)) - flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag - - if (launch_info.GetLaunchInSeparateProcessGroup()) - flags |= POSIX_SPAWN_SETPGROUP; - -#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT -#if defined(__APPLE__) && (defined(__x86_64__) || defined(__i386__)) - static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate; - if (g_use_close_on_exec_flag == eLazyBoolCalculate) { - g_use_close_on_exec_flag = eLazyBoolNo; - - uint32_t major, minor, update; - if (HostInfo::GetOSVersion(major, minor, update)) { - // Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or - // earlier - if (major > 10 || (major == 10 && minor > 7)) { - // Only enable for 10.8 and later OS versions - g_use_close_on_exec_flag = eLazyBoolYes; - } - } - } -#else - static LazyBool g_use_close_on_exec_flag = eLazyBoolYes; -#endif - // Close all files exception those with file actions if this is supported. - if (g_use_close_on_exec_flag == eLazyBoolYes) - flags |= POSIX_SPAWN_CLOEXEC_DEFAULT; -#endif -#endif // #if defined (__APPLE__) - return flags; -} - -Status Host::LaunchProcessPosixSpawn(const char *exe_path, - const ProcessLaunchInfo &launch_info, - lldb::pid_t &pid) { - Status error; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST | - LIBLLDB_LOG_PROCESS)); - - posix_spawnattr_t attr; - error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX); - - if (error.Fail()) { - LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error); - return error; - } - - // Make a quick class that will cleanup the posix spawn attributes in case - // we return in the middle of this function. - lldb_utility::CleanUp posix_spawnattr_cleanup( - &attr, posix_spawnattr_destroy); - - sigset_t no_signals; - sigset_t all_signals; - sigemptyset(&no_signals); - sigfillset(&all_signals); - ::posix_spawnattr_setsigmask(&attr, &no_signals); -#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) - ::posix_spawnattr_setsigdefault(&attr, &no_signals); -#else - ::posix_spawnattr_setsigdefault(&attr, &all_signals); -#endif - - short flags = GetPosixspawnFlags(launch_info); - - error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX); - if (error.Fail()) { - LLDB_LOG(log, - "error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )", - error, flags); - return error; - } - -// posix_spawnattr_setbinpref_np appears to be an Apple extension per: -// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/ -#if defined(__APPLE__) && !defined(__arm__) - - // Don't set the binpref if a shell was provided. After all, that's only - // going to affect what version of the shell - // is launched, not what fork of the binary is launched. We insert "arch - // --arch as part of the shell invocation - // to do that job on OSX. - - if (launch_info.GetShell() == nullptr) { - // We don't need to do this for ARM, and we really shouldn't now that we - // have multiple CPU subtypes and no posix_spawnattr call that allows us - // to set which CPU subtype to launch... - const ArchSpec &arch_spec = launch_info.GetArchitecture(); - cpu_type_t cpu = arch_spec.GetMachOCPUType(); - cpu_type_t sub = arch_spec.GetMachOCPUSubType(); - if (cpu != 0 && cpu != static_cast(UINT32_MAX) && - cpu != static_cast(LLDB_INVALID_CPUTYPE) && - !(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try - // to set the CPU type or we will fail - { - size_t ocount = 0; - error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount), - eErrorTypePOSIX); - if (error.Fail()) - LLDB_LOG(log, "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, " - "cpu_type = {1:x}, count => {2} )", - error, cpu, ocount); - - if (error.Fail() || ocount != 1) - return error; - } - } - -#endif - - const char *tmp_argv[2]; - char *const *argv = const_cast( - launch_info.GetArguments().GetConstArgumentVector()); - char *const *envp = const_cast( - launch_info.GetEnvironmentEntries().GetConstArgumentVector()); - if (argv == NULL) { - // posix_spawn gets very unhappy if it doesn't have at least the program - // name in argv[0]. One of the side affects I have noticed is the - // environment - // variables don't make it into the child process if "argv == NULL"!!! - tmp_argv[0] = exe_path; - tmp_argv[1] = NULL; - argv = const_cast(tmp_argv); - } - +// The functions below implement process launching for non-Apple-based platforms #if !defined(__APPLE__) - // manage the working directory - char current_dir[PATH_MAX]; - current_dir[0] = '\0'; -#endif - - FileSpec working_dir{launch_info.GetWorkingDirectory()}; - if (working_dir) { -#if defined(__APPLE__) - // Set the working directory on this thread only - if (__pthread_chdir(working_dir.GetCString()) < 0) { - if (errno == ENOENT) { - error.SetErrorStringWithFormat("No such file or directory: %s", - working_dir.GetCString()); - } else if (errno == ENOTDIR) { - error.SetErrorStringWithFormat("Path doesn't name a directory: %s", - working_dir.GetCString()); - } else { - error.SetErrorStringWithFormat("An unknown error occurred when " - "changing directory for process " - "execution."); - } - return error; - } -#else - if (::getcwd(current_dir, sizeof(current_dir)) == NULL) { - error.SetError(errno, eErrorTypePOSIX); - LLDB_LOG(log, "error: {0}, unable to save the current directory", error); - return error; - } - - if (::chdir(working_dir.GetCString()) == -1) { - error.SetError(errno, eErrorTypePOSIX); - LLDB_LOG(log, "error: {0}, unable to change working directory to {1}", - error, working_dir); - return error; - } -#endif - } - - ::pid_t result_pid = LLDB_INVALID_PROCESS_ID; - const size_t num_file_actions = launch_info.GetNumFileActions(); - if (num_file_actions > 0) { - posix_spawn_file_actions_t file_actions; - error.SetError(::posix_spawn_file_actions_init(&file_actions), - eErrorTypePOSIX); - if (error.Fail()) { - LLDB_LOG(log, - "error: {0}, ::posix_spawn_file_actions_init ( &file_actions )", - error); - return error; - } - - // Make a quick class that will cleanup the posix spawn attributes in case - // we return in the middle of this function. - lldb_utility::CleanUp - posix_spawn_file_actions_cleanup(&file_actions, - posix_spawn_file_actions_destroy); - - for (size_t i = 0; i < num_file_actions; ++i) { - const FileAction *launch_file_action = - launch_info.GetFileActionAtIndex(i); - if (launch_file_action) { - if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log, - error)) - return error; - } - } - - error.SetError( - ::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp), - eErrorTypePOSIX); - - if (error.Fail()) { - LLDB_LOG(log, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', " - "file_actions = {3}, " - "attr = {4}, argv = {5}, envp = {6} )", - error, result_pid, exe_path, &file_actions, &attr, argv, envp); - if (log) { - for (int ii = 0; argv[ii]; ++ii) - LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]); - } - } - - } else { - error.SetError( - ::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp), - eErrorTypePOSIX); - - if (error.Fail()) { - LLDB_LOG(log, "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', " - "file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )", - error, result_pid, exe_path, &attr, argv, envp); - if (log) { - for (int ii = 0; argv[ii]; ++ii) - LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]); - } - } - } - pid = result_pid; - - if (working_dir) { -#if defined(__APPLE__) - // No more thread specific current working directory - __pthread_fchdir(-1); -#else - if (::chdir(current_dir) == -1 && error.Success()) { - error.SetError(errno, eErrorTypePOSIX); - LLDB_LOG(log, - "error: {0}, unable to change current directory back to {1}", - error, current_dir); - } -#endif - } - - return error; -} - -bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info, - Log *log, Status &error) { - if (info == NULL) - return false; - - posix_spawn_file_actions_t *file_actions = - reinterpret_cast(_file_actions); - - switch (info->GetAction()) { - case FileAction::eFileActionNone: - error.Clear(); - break; - - case FileAction::eFileActionClose: - if (info->GetFD() == -1) - error.SetErrorString( - "invalid fd for posix_spawn_file_actions_addclose(...)"); - else { - error.SetError( - ::posix_spawn_file_actions_addclose(file_actions, info->GetFD()), - eErrorTypePOSIX); - if (error.Fail()) - LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_addclose " - "(action={1}, fd={2})", - error, file_actions, info->GetFD()); - } - break; - - case FileAction::eFileActionDuplicate: - if (info->GetFD() == -1) - error.SetErrorString( - "invalid fd for posix_spawn_file_actions_adddup2(...)"); - else if (info->GetActionArgument() == -1) - error.SetErrorString( - "invalid duplicate fd for posix_spawn_file_actions_adddup2(...)"); - else { - error.SetError( - ::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(), - info->GetActionArgument()), - eErrorTypePOSIX); - if (error.Fail()) - LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_adddup2 " - "(action={1}, fd={2}, dup_fd={3})", - error, file_actions, info->GetFD(), info->GetActionArgument()); - } - break; - - case FileAction::eFileActionOpen: - if (info->GetFD() == -1) - error.SetErrorString( - "invalid fd in posix_spawn_file_actions_addopen(...)"); - else { - int oflag = info->GetActionArgument(); - - mode_t mode = 0; - - if (oflag & O_CREAT) - mode = 0640; - - error.SetError(::posix_spawn_file_actions_addopen( - file_actions, info->GetFD(), - info->GetPath().str().c_str(), oflag, mode), - eErrorTypePOSIX); - if (error.Fail()) - LLDB_LOG( - log, "error: {0}, posix_spawn_file_actions_addopen (action={1}, " - "fd={2}, path='{3}', oflag={4}, mode={5})", - error, file_actions, info->GetFD(), info->GetPath(), oflag, mode); - } - break; - } - return error.Success(); -} -#endif // !defined(__ANDROID__) -#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) || - // defined (__GLIBC__) || defined(__NetBSD__) - -#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || \ - defined(__NetBSD__) || defined(_WIN32) -// The functions below implement process launching via posix_spawn() for Linux, -// FreeBSD and NetBSD. - Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) { std::unique_ptr delegate_launcher; #if defined(_WIN32) delegate_launcher.reset(new ProcessLauncherWindows()); -#elif defined(__linux__) || defined(__NetBSD__) - delegate_launcher.reset(new ProcessLauncherPosixFork()); #else - delegate_launcher.reset(new ProcessLauncherPosix()); + delegate_launcher.reset(new ProcessLauncherPosixFork()); #endif MonitoringProcessLauncher launcher(std::move(delegate_launcher)); @@ -968,7 +603,7 @@ Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) { return error; } -#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) +#endif // !defined(__APPLE__) #ifndef _WIN32 void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid, signo); } @@ -988,3 +623,51 @@ const UnixSignalsSP &Host::GetUnixSignals() { UnixSignals::Create(HostInfo::GetArchitecture()); return s_unix_signals_sp; } + +#if defined(LLVM_ON_UNIX) +WaitStatus WaitStatus::Decode(int wstatus) { + if (WIFEXITED(wstatus)) + return {Exit, uint8_t(WEXITSTATUS(wstatus))}; + else if (WIFSIGNALED(wstatus)) + return {Signal, uint8_t(WTERMSIG(wstatus))}; + else if (WIFSTOPPED(wstatus)) + return {Stop, uint8_t(WSTOPSIG(wstatus))}; + llvm_unreachable("Unknown wait status"); +} +#endif + +void llvm::format_provider::format(const WaitStatus &WS, + raw_ostream &OS, + StringRef Options) { + if (Options == "g") { + char type; + switch (WS.type) { + case WaitStatus::Exit: + type = 'W'; + break; + case WaitStatus::Signal: + type = 'X'; + break; + case WaitStatus::Stop: + type = 'S'; + break; + } + OS << formatv("{0}{1:x-2}", type, WS.status); + return; + } + + assert(Options.empty()); + const char *desc; + switch(WS.type) { + case WaitStatus::Exit: + desc = "Exited with status"; + break; + case WaitStatus::Signal: + desc = "Killed by signal"; + break; + case WaitStatus::Stop: + desc = "Stopped by signal"; + break; + } + OS << desc << " " << int(WS.status); +} diff --git a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp index 6f1a9f895b61..341c301dc9c5 100644 --- a/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp +++ b/contrib/llvm/tools/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -32,7 +32,6 @@ using namespace lldb_private; NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid) : m_pid(pid), m_threads(), m_current_thread_id(LLDB_INVALID_THREAD_ID), m_threads_mutex(), m_state(lldb::eStateInvalid), m_state_mutex(), - m_exit_type(eExitTypeInvalid), m_exit_status(0), m_exit_description(), m_delegates_mutex(), m_delegates(), m_breakpoint_list(), m_watchpoint_list(), m_terminal_fd(-1), m_stop_id(0) {} @@ -59,46 +58,29 @@ NativeProcessProtocol::GetMemoryRegionInfo(lldb::addr_t load_addr, return Status("not implemented"); } -bool NativeProcessProtocol::GetExitStatus(ExitType *exit_type, int *status, - std::string &exit_description) { - if (m_state == lldb::eStateExited) { - *exit_type = m_exit_type; - *status = m_exit_status; - exit_description = m_exit_description; - return true; - } +llvm::Optional NativeProcessProtocol::GetExitStatus() { + if (m_state == lldb::eStateExited) + return m_exit_status; - *status = 0; - return false; + return llvm::None; } -bool NativeProcessProtocol::SetExitStatus(ExitType exit_type, int status, - const char *exit_description, +bool NativeProcessProtocol::SetExitStatus(WaitStatus status, bool bNotifyStateChange) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("NativeProcessProtocol::%s(%d, %d, %s, %s) called", - __FUNCTION__, exit_type, status, - exit_description ? exit_description : "nullptr", - bNotifyStateChange ? "true" : "false"); + LLDB_LOG(log, "status = {0}, notify = {1}", status, bNotifyStateChange); // Exit status already set if (m_state == lldb::eStateExited) { - if (log) - log->Printf("NativeProcessProtocol::%s exit status already set to %d, " - "ignoring new set to %d", - __FUNCTION__, m_exit_status, status); + if (m_exit_status) + LLDB_LOG(log, "exit status already set to {0}", *m_exit_status); + else + LLDB_LOG(log, "state is exited, but status not set"); return false; } m_state = lldb::eStateExited; - - m_exit_type = exit_type; m_exit_status = status; - if (exit_description && exit_description[0]) - m_exit_description = exit_description; - else - m_exit_description.clear(); if (bNotifyStateChange) SynchronouslyNotifyProcessStateChanged(lldb::eStateExited); diff --git a/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp b/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp deleted file mode 100644 index 6d07be1eec64..000000000000 --- a/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosix.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//===-- ProcessLauncherPosix.cpp --------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/posix/ProcessLauncherPosix.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostProcess.h" - -#include "lldb/Target/ProcessLaunchInfo.h" - -#include - -using namespace lldb; -using namespace lldb_private; - -HostProcess -ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info, - Status &error) { - lldb::pid_t pid; - char exe_path[PATH_MAX]; - - launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path)); - - // TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make - // MacOSX re-use this - // ProcessLauncher when it wants a posix_spawn launch. - error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid); - return HostProcess(pid); -} diff --git a/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 1eace5cd24cd..0b40c24256ef 100644 --- a/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/contrib/llvm/tools/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -52,10 +52,10 @@ static void FixupEnvironment(Args &env) { static void LLVM_ATTRIBUTE_NORETURN ExitWithError(int error_fd, const char *operation) { - std::ostringstream os; - os << operation << " failed: " << strerror(errno); - write(error_fd, os.str().data(), os.str().size()); - close(error_fd); + int err = errno; + llvm::raw_fd_ostream os(error_fd, true); + os << operation << " failed: " << llvm::sys::StrError(err); + os.flush(); _exit(1); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp index b202c8395776..ce8f8a65e3e3 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ABI/SysV-arm64/ABISysV_arm64.cpp @@ -1951,22 +1951,20 @@ bool ABISysV_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { uint32_t lr_reg_num = arm64_dwarf::lr; uint32_t sp_reg_num = arm64_dwarf::sp; - uint32_t pc_reg_num = arm64_dwarf::pc; UnwindPlan::RowSP row(new UnwindPlan::Row); // Our previous Call Frame Address is the stack pointer row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0); - // Our previous PC is in the LR - row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true); - unwind_plan.AppendRow(row); + unwind_plan.SetReturnAddressRegister(lr_reg_num); // All other registers are the same. unwind_plan.SetSourceName("arm64 at-func-entry default"); unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); return true; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 5f56bfc027a4..0092535648bd 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/Section.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -484,6 +485,27 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, return thread_plan_sp; } +void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) { + if (m_vdso_base == LLDB_INVALID_ADDRESS) + return; + + FileSpec file("[vdso]", false); + + MemoryRegionInfo info; + Status status = m_process->GetMemoryRegionInfo(m_vdso_base, info); + if (status.Fail()) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + LLDB_LOG(log, "Failed to get vdso region info: {0}", status); + return; + } + + if (ModuleSP module_sp = m_process->ReadModuleFromMemory( + file, m_vdso_base, info.GetRange().GetByteSize())) { + UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_vdso_base, false); + m_process->GetTarget().GetImages().AppendIfNeeded(module_sp); + } +} + void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() { DYLDRendezvous::iterator I; DYLDRendezvous::iterator E; @@ -502,14 +524,7 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() { // that ourselves here. ModuleSP executable = GetTargetExecutable(); m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); - if (m_vdso_base != LLDB_INVALID_ADDRESS) { - FileSpec file_spec("[vdso]", false); - ModuleSP module_sp = LoadModuleAtAddress(file_spec, LLDB_INVALID_ADDRESS, - m_vdso_base, false); - if (module_sp.get()) { - module_list.Append(module_sp); - } - } + LoadVDSO(module_list); std::vector module_names; for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) diff --git a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index 86e0311c2919..2e9670587e66 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/contrib/llvm/tools/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -17,10 +17,10 @@ // Other libraries and framework includes // Project includes -#include "lldb/Breakpoint/StoppointCallbackContext.h" -#include "lldb/Target/DynamicLoader.h" - #include "DYLDRendezvous.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Target/DynamicLoader.h" class AuxVector; @@ -138,6 +138,8 @@ class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader { /// of all dependent modules. virtual void LoadAllCurrentModules(); + void LoadVDSO(lldb_private::ModuleList &modules); + /// Computes a value for m_load_offset returning the computed address on /// success and LLDB_INVALID_ADDRESS on failure. lldb::addr_t ComputeLoadOffset(); diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp similarity index 96% rename from contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp rename to contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp index 91c5d6ce3d60..af242d786a5f 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp @@ -1,4 +1,4 @@ -//===-- AddressSanitizerRuntime.cpp -----------------------------*- C++ -*-===// +//===-- ASanRuntime.cpp -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "AddressSanitizerRuntime.h" +#include "ASanRuntime.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" @@ -308,13 +308,6 @@ void AddressSanitizerRuntime::Activate() { breakpoint->SetBreakpointKind("address-sanitizer-report"); SetBreakpointID(breakpoint->GetID()); - StreamFileSP stream_sp(process_sp->GetTarget().GetDebugger().GetOutputFile()); - if (stream_sp) { - stream_sp->Printf("AddressSanitizer debugger support is active. Memory " - "error breakpoint has been installed and you can now use " - "the 'memory history' command.\n"); - } - SetActive(true); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h similarity index 100% rename from contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h rename to contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/ASanRuntime.h diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt new file mode 100644 index 000000000000..dc7464fd1939 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ASan/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginInstrumentationRuntimeASan PLUGIN + ASanRuntime.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbExpression + lldbInterpreter + lldbSymbol + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt new file mode 100644 index 000000000000..440b176b2709 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginInstrumentationRuntimeMainThreadChecker PLUGIN + MainThreadCheckerRuntime.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbExpression + lldbInterpreter + lldbSymbol + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp new file mode 100644 index 000000000000..3c22b81df7a4 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp @@ -0,0 +1,273 @@ +//===-- MainThreadCheckerRuntime.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MainThreadCheckerRuntime.h" + +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/InstrumentationRuntimeStopInfo.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/RegularExpression.h" +#include "Plugins/Process/Utility/HistoryThread.h" + +using namespace lldb; +using namespace lldb_private; + +MainThreadCheckerRuntime::~MainThreadCheckerRuntime() { + Deactivate(); +} + +lldb::InstrumentationRuntimeSP +MainThreadCheckerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) { + return InstrumentationRuntimeSP(new MainThreadCheckerRuntime(process_sp)); +} + +void MainThreadCheckerRuntime::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "MainThreadChecker instrumentation runtime plugin.", + CreateInstance, GetTypeStatic); +} + +void MainThreadCheckerRuntime::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +lldb_private::ConstString MainThreadCheckerRuntime::GetPluginNameStatic() { + return ConstString("MainThreadChecker"); +} + +lldb::InstrumentationRuntimeType MainThreadCheckerRuntime::GetTypeStatic() { + return eInstrumentationRuntimeTypeMainThreadChecker; +} + +const RegularExpression & +MainThreadCheckerRuntime::GetPatternForRuntimeLibrary() { + static RegularExpression regex(llvm::StringRef("libMainThreadChecker.dylib")); + return regex; +} + +bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid( + const lldb::ModuleSP module_sp) { + static ConstString test_sym("__main_thread_checker_on_report"); + const Symbol *symbol = + module_sp->FindFirstSymbolWithNameAndType(test_sym, lldb::eSymbolTypeAny); + return symbol != nullptr; +} + +StructuredData::ObjectSP +MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) { + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return StructuredData::ObjectSP(); + + ThreadSP thread_sp = exe_ctx_ref.GetThreadSP(); + StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); + ModuleSP runtime_module_sp = GetRuntimeModuleSP(); + Target &target = process_sp->GetTarget(); + + if (!frame_sp) + return StructuredData::ObjectSP(); + + RegisterContextSP regctx_sp = frame_sp->GetRegisterContext(); + if (!regctx_sp) + return StructuredData::ObjectSP(); + + const RegisterInfo *reginfo = regctx_sp->GetRegisterInfoByName("arg1"); + if (!reginfo) + return StructuredData::ObjectSP(); + + uint64_t apiname_ptr = regctx_sp->ReadRegisterAsUnsigned(reginfo, 0); + if (!apiname_ptr) + return StructuredData::ObjectSP(); + + std::string apiName = ""; + Status read_error; + target.ReadCStringFromMemory(apiname_ptr, apiName, read_error); + if (read_error.Fail()) + return StructuredData::ObjectSP(); + + std::string className = ""; + std::string selector = ""; + if (apiName.substr(0, 2) == "-[") { + size_t spacePos = apiName.find(" "); + if (spacePos != std::string::npos) { + className = apiName.substr(2, spacePos - 2); + selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2); + } + } + + // Gather the PCs of the user frames in the backtrace. + StructuredData::Array *trace = new StructuredData::Array(); + auto trace_sp = StructuredData::ObjectSP(trace); + StackFrameSP responsible_frame; + for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) { + StackFrameSP frame = thread_sp->GetStackFrameAtIndex(I); + Address addr = frame->GetFrameCodeAddress(); + if (addr.GetModule() == runtime_module_sp) // Skip PCs from the runtime. + continue; + + // The first non-runtime frame is responsible for the bug. + if (!responsible_frame) + responsible_frame = frame; + + // First frame in stacktrace should point to a real PC, not return address. + if (I != 0 && trace->GetSize() == 0) { + addr.Slide(-1); + } + + lldb::addr_t PC = addr.GetLoadAddress(&target); + trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC))); + } + + auto *d = new StructuredData::Dictionary(); + auto dict_sp = StructuredData::ObjectSP(d); + d->AddStringItem("instrumentation_class", "MainThreadChecker"); + d->AddStringItem("api_name", apiName); + d->AddStringItem("class_name", className); + d->AddStringItem("selector", selector); + d->AddStringItem("description", + apiName + " must be called from main thread only"); + d->AddIntegerItem("tid", thread_sp->GetIndexID()); + d->AddItem("trace", trace_sp); + return dict_sp; +} + +bool MainThreadCheckerRuntime::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + assert(baton && "null baton"); + if (!baton) + return false; //< false => resume execution. + + MainThreadCheckerRuntime *const instance = + static_cast(baton); + + ProcessSP process_sp = instance->GetProcessSP(); + ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); + if (!process_sp || !thread_sp || + process_sp != context->exe_ctx_ref.GetProcessSP()) + return false; + + StructuredData::ObjectSP report = + instance->RetrieveReportData(context->exe_ctx_ref); + + if (report) { + std::string description = report->GetAsDictionary() + ->GetValueForKey("description") + ->GetAsString() + ->GetValue(); + thread_sp->SetStopInfo( + InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData( + *thread_sp, description, report)); + return true; + } + + return false; +} + +void MainThreadCheckerRuntime::Activate() { + if (IsActive()) + return; + + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return; + + ModuleSP runtime_module_sp = GetRuntimeModuleSP(); + + ConstString symbol_name("__main_thread_checker_on_report"); + const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType( + symbol_name, eSymbolTypeCode); + + if (symbol == nullptr) + return; + + if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid()) + return; + + Target &target = process_sp->GetTarget(); + addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target); + + if (symbol_address == LLDB_INVALID_ADDRESS) + return; + + Breakpoint *breakpoint = + process_sp->GetTarget() + .CreateBreakpoint(symbol_address, /*internal=*/true, + /*hardware=*/false) + .get(); + breakpoint->SetCallback(MainThreadCheckerRuntime::NotifyBreakpointHit, this, + true); + breakpoint->SetBreakpointKind("main-thread-checker-report"); + SetBreakpointID(breakpoint->GetID()); + + SetActive(true); +} + +void MainThreadCheckerRuntime::Deactivate() { + SetActive(false); + + auto BID = GetBreakpointID(); + if (BID == LLDB_INVALID_BREAK_ID) + return; + + if (ProcessSP process_sp = GetProcessSP()) { + process_sp->GetTarget().RemoveBreakpointByID(BID); + SetBreakpointID(LLDB_INVALID_BREAK_ID); + } +} + +lldb::ThreadCollectionSP +MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo( + StructuredData::ObjectSP info) { + ThreadCollectionSP threads; + threads.reset(new ThreadCollection()); + + ProcessSP process_sp = GetProcessSP(); + + if (info->GetObjectForDotSeparatedPath("instrumentation_class") + ->GetStringValue() != "MainThreadChecker") + return threads; + + std::vector PCs; + auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray(); + trace->ForEach([&PCs](StructuredData::Object *PC) -> bool { + PCs.push_back(PC->GetAsInteger()->GetValue()); + return true; + }); + + if (PCs.empty()) + return threads; + + StructuredData::ObjectSP thread_id_obj = + info->GetObjectForDotSeparatedPath("tid"); + tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0; + + uint32_t stop_id = 0; + bool stop_id_is_valid = false; + HistoryThread *history_thread = + new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid); + ThreadSP new_thread_sp(history_thread); + + // Save this in the Process' ExtendedThreadList so a strong pointer + // retains the object + process_sp->GetExtendedThreadList().AddThread(new_thread_sp); + threads->AddThread(new_thread_sp); + + return threads; +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h new file mode 100644 index 000000000000..87440a2489e6 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h @@ -0,0 +1,68 @@ +//===-- MainThreadCheckerRuntime.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_MainThreadCheckerRuntime_h_ +#define liblldb_MainThreadCheckerRuntime_h_ + +#include "lldb/Core/StructuredData.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/InstrumentationRuntime.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + + class MainThreadCheckerRuntime : public lldb_private::InstrumentationRuntime { + public: + ~MainThreadCheckerRuntime() override; + + static lldb::InstrumentationRuntimeSP + CreateInstance(const lldb::ProcessSP &process_sp); + + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static lldb::InstrumentationRuntimeType GetTypeStatic(); + + lldb_private::ConstString GetPluginName() override { + return GetPluginNameStatic(); + } + + virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); } + + uint32_t GetPluginVersion() override { return 1; } + + lldb::ThreadCollectionSP + GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override; + + private: + MainThreadCheckerRuntime(const lldb::ProcessSP &process_sp) + : lldb_private::InstrumentationRuntime(process_sp) {} + + const RegularExpression &GetPatternForRuntimeLibrary() override; + + bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override; + + void Activate() override; + + void Deactivate(); + + static bool NotifyBreakpointHit(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref); + }; + +} // namespace lldb_private + +#endif // liblldb_MainThreadCheckerRuntime_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt new file mode 100644 index 000000000000..4dcd34131b8e --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/CMakeLists.txt @@ -0,0 +1,12 @@ +add_lldb_library(lldbPluginInstrumentationRuntimeTSan PLUGIN + TSanRuntime.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbExpression + lldbInterpreter + lldbSymbol + lldbTarget + lldbPluginProcessUtility + ) diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp similarity index 99% rename from contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp rename to contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp index d7b518982fcf..f60df0463346 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.cpp @@ -1,4 +1,4 @@ -//===-- ThreadSanitizerRuntime.cpp ------------------------------*- C++ -*-===// +//===-- TSanRuntime.cpp -----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "ThreadSanitizerRuntime.h" +#include "TSanRuntime.h" #include "Plugins/Process/Utility/HistoryThread.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -921,11 +921,6 @@ void ThreadSanitizerRuntime::Activate() { breakpoint->SetBreakpointKind("thread-sanitizer-report"); SetBreakpointID(breakpoint->GetID()); - StreamFileSP stream_sp(process_sp->GetTarget().GetDebugger().GetOutputFile()); - if (stream_sp) { - stream_sp->Printf("ThreadSanitizer debugger support is active.\n"); - } - SetActive(true); } diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h similarity index 100% rename from contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h rename to contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/TSan/TSanRuntime.h diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt new file mode 100644 index 000000000000..984bf86f83b5 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginInstrumentationRuntimeUBSan PLUGIN + UBSanRuntime.cpp + + LINK_LIBS + lldbBreakpoint + lldbCore + lldbExpression + lldbInterpreter + lldbSymbol + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp new file mode 100644 index 000000000000..023af84179aa --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp @@ -0,0 +1,340 @@ +//===-- UBSanRuntime.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UBSanRuntime.h" + +#include "Plugins/Process/Utility/HistoryThread.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginInterface.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/InstrumentationRuntimeStopInfo.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/RegularExpression.h" +#include "lldb/Utility/Stream.h" +#include + +using namespace lldb; +using namespace lldb_private; + +UndefinedBehaviorSanitizerRuntime::~UndefinedBehaviorSanitizerRuntime() { + Deactivate(); +} + +lldb::InstrumentationRuntimeSP +UndefinedBehaviorSanitizerRuntime::CreateInstance( + const lldb::ProcessSP &process_sp) { + return InstrumentationRuntimeSP( + new UndefinedBehaviorSanitizerRuntime(process_sp)); +} + +void UndefinedBehaviorSanitizerRuntime::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), + "UndefinedBehaviorSanitizer instrumentation runtime plugin.", + CreateInstance, GetTypeStatic); +} + +void UndefinedBehaviorSanitizerRuntime::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +lldb_private::ConstString +UndefinedBehaviorSanitizerRuntime::GetPluginNameStatic() { + return ConstString("UndefinedBehaviorSanitizer"); +} + +lldb::InstrumentationRuntimeType +UndefinedBehaviorSanitizerRuntime::GetTypeStatic() { + return eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer; +} + +static const char *ub_sanitizer_retrieve_report_data_prefix = R"( +extern "C" { +void +__ubsan_get_current_report_data(const char **OutIssueKind, + const char **OutMessage, const char **OutFilename, unsigned *OutLine, + unsigned *OutCol, char **OutMemoryAddr); +} + +struct data { + const char *issue_kind; + const char *message; + const char *filename; + unsigned line; + unsigned col; + char *memory_addr; +}; +)"; + +static const char *ub_sanitizer_retrieve_report_data_command = R"( +data t; +__ubsan_get_current_report_data(&t.issue_kind, &t.message, &t.filename, &t.line, + &t.col, &t.memory_addr); +t; +)"; + +static addr_t RetrieveUnsigned(ValueObjectSP return_value_sp, + ProcessSP process_sp, + const std::string &expression_path) { + return return_value_sp->GetValueForExpressionPath(expression_path.c_str()) + ->GetValueAsUnsigned(0); +} + +static std::string RetrieveString(ValueObjectSP return_value_sp, + ProcessSP process_sp, + const std::string &expression_path) { + addr_t ptr = RetrieveUnsigned(return_value_sp, process_sp, expression_path); + std::string str; + Status error; + process_sp->ReadCStringFromMemory(ptr, str, error); + return str; +} + +StructuredData::ObjectSP UndefinedBehaviorSanitizerRuntime::RetrieveReportData( + ExecutionContextRef exe_ctx_ref) { + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return StructuredData::ObjectSP(); + + ThreadSP thread_sp = exe_ctx_ref.GetThreadSP(); + StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); + ModuleSP runtime_module_sp = GetRuntimeModuleSP(); + Target &target = process_sp->GetTarget(); + + if (!frame_sp) + return StructuredData::ObjectSP(); + + StreamFileSP Stream(target.GetDebugger().GetOutputFile()); + + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetTryAllThreads(true); + options.SetStopOthers(true); + options.SetIgnoreBreakpoints(true); + options.SetTimeout(std::chrono::seconds(2)); + options.SetPrefix(ub_sanitizer_retrieve_report_data_prefix); + options.SetAutoApplyFixIts(false); + options.SetLanguage(eLanguageTypeObjC_plus_plus); + + ValueObjectSP main_value; + ExecutionContext exe_ctx; + Status eval_error; + frame_sp->CalculateExecutionContext(exe_ctx); + ExpressionResults result = UserExpression::Evaluate( + exe_ctx, options, ub_sanitizer_retrieve_report_data_command, "", + main_value, eval_error); + if (result != eExpressionCompleted) { + target.GetDebugger().GetAsyncOutputStream()->Printf( + "Warning: Cannot evaluate UndefinedBehaviorSanitizer expression:\n%s\n", + eval_error.AsCString()); + return StructuredData::ObjectSP(); + } + + // Gather the PCs of the user frames in the backtrace. + StructuredData::Array *trace = new StructuredData::Array(); + auto trace_sp = StructuredData::ObjectSP(trace); + for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) { + const Address FCA = + thread_sp->GetStackFrameAtIndex(I)->GetFrameCodeAddress(); + if (FCA.GetModule() == runtime_module_sp) // Skip PCs from the runtime. + continue; + + lldb::addr_t PC = FCA.GetLoadAddress(&target); + trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC))); + } + + std::string IssueKind = RetrieveString(main_value, process_sp, ".issue_kind"); + std::string ErrMessage = RetrieveString(main_value, process_sp, ".message"); + std::string Filename = RetrieveString(main_value, process_sp, ".filename"); + unsigned Line = RetrieveUnsigned(main_value, process_sp, ".line"); + unsigned Col = RetrieveUnsigned(main_value, process_sp, ".col"); + uintptr_t MemoryAddr = + RetrieveUnsigned(main_value, process_sp, ".memory_addr"); + + auto *d = new StructuredData::Dictionary(); + auto dict_sp = StructuredData::ObjectSP(d); + d->AddStringItem("instrumentation_class", "UndefinedBehaviorSanitizer"); + d->AddStringItem("description", IssueKind); + d->AddStringItem("summary", ErrMessage); + d->AddStringItem("filename", Filename); + d->AddIntegerItem("line", Line); + d->AddIntegerItem("col", Col); + d->AddIntegerItem("memory_address", MemoryAddr); + d->AddIntegerItem("tid", thread_sp->GetID()); + d->AddItem("trace", trace_sp); + return dict_sp; +} + +static std::string GetStopReasonDescription(StructuredData::ObjectSP report) { + llvm::StringRef stop_reason_description_ref; + report->GetAsDictionary()->GetValueForKeyAsString("description", + stop_reason_description_ref); + std::string stop_reason_description = stop_reason_description_ref; + + if (!stop_reason_description.size()) { + stop_reason_description = "Undefined behavior detected"; + } else { + stop_reason_description[0] = toupper(stop_reason_description[0]); + for (unsigned I = 1; I < stop_reason_description.size(); ++I) + if (stop_reason_description[I] == '-') + stop_reason_description[I] = ' '; + } + return stop_reason_description; +} + +bool UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + assert(baton && "null baton"); + if (!baton) + return false; //< false => resume execution. + + UndefinedBehaviorSanitizerRuntime *const instance = + static_cast(baton); + + ProcessSP process_sp = instance->GetProcessSP(); + ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP(); + if (!process_sp || !thread_sp || + process_sp != context->exe_ctx_ref.GetProcessSP()) + return false; + + StructuredData::ObjectSP report = + instance->RetrieveReportData(context->exe_ctx_ref); + + if (report) { + thread_sp->SetStopInfo( + InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData( + *thread_sp, GetStopReasonDescription(report), report)); + return true; + } + + return false; +} + +const RegularExpression & +UndefinedBehaviorSanitizerRuntime::GetPatternForRuntimeLibrary() { + static RegularExpression regex(llvm::StringRef("libclang_rt\\.(a|t|ub)san_")); + return regex; +} + +bool UndefinedBehaviorSanitizerRuntime::CheckIfRuntimeIsValid( + const lldb::ModuleSP module_sp) { + static ConstString ubsan_test_sym("__ubsan_on_report"); + const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( + ubsan_test_sym, lldb::eSymbolTypeAny); + return symbol != nullptr; +} + +// FIXME: Factor out all the logic we have in common with the {a,t}san plugins. +void UndefinedBehaviorSanitizerRuntime::Activate() { + if (IsActive()) + return; + + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return; + + ModuleSP runtime_module_sp = GetRuntimeModuleSP(); + + ConstString symbol_name("__ubsan_on_report"); + const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType( + symbol_name, eSymbolTypeCode); + + if (symbol == nullptr) + return; + + if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid()) + return; + + Target &target = process_sp->GetTarget(); + addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target); + + if (symbol_address == LLDB_INVALID_ADDRESS) + return; + + Breakpoint *breakpoint = + process_sp->GetTarget() + .CreateBreakpoint(symbol_address, /*internal=*/true, + /*hardware=*/false) + .get(); + breakpoint->SetCallback( + UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit, this, true); + breakpoint->SetBreakpointKind("undefined-behavior-sanitizer-report"); + SetBreakpointID(breakpoint->GetID()); + + SetActive(true); +} + +void UndefinedBehaviorSanitizerRuntime::Deactivate() { + SetActive(false); + + auto BID = GetBreakpointID(); + if (BID == LLDB_INVALID_BREAK_ID) + return; + + if (ProcessSP process_sp = GetProcessSP()) { + process_sp->GetTarget().RemoveBreakpointByID(BID); + SetBreakpointID(LLDB_INVALID_BREAK_ID); + } +} + +lldb::ThreadCollectionSP +UndefinedBehaviorSanitizerRuntime::GetBacktracesFromExtendedStopInfo( + StructuredData::ObjectSP info) { + ThreadCollectionSP threads; + threads.reset(new ThreadCollection()); + + ProcessSP process_sp = GetProcessSP(); + + if (info->GetObjectForDotSeparatedPath("instrumentation_class") + ->GetStringValue() != "UndefinedBehaviorSanitizer") + return threads; + + std::vector PCs; + auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray(); + trace->ForEach([&PCs](StructuredData::Object *PC) -> bool { + PCs.push_back(PC->GetAsInteger()->GetValue()); + return true; + }); + + if (PCs.empty()) + return threads; + + StructuredData::ObjectSP thread_id_obj = + info->GetObjectForDotSeparatedPath("tid"); + tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0; + + uint32_t stop_id = 0; + bool stop_id_is_valid = false; + HistoryThread *history_thread = + new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid); + ThreadSP new_thread_sp(history_thread); + std::string stop_reason_description = GetStopReasonDescription(info); + new_thread_sp->SetName(stop_reason_description.c_str()); + + // Save this in the Process' ExtendedThreadList so a strong pointer + // retains the object + process_sp->GetExtendedThreadList().AddThread(new_thread_sp); + threads->AddThread(new_thread_sp); + + return threads; +} diff --git a/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h new file mode 100644 index 000000000000..0c478bd57e82 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h @@ -0,0 +1,69 @@ +//===-- UndefinedBehaviorSanitizerRuntime.h ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_UndefinedBehaviorSanitizerRuntime_h_ +#define liblldb_UndefinedBehaviorSanitizerRuntime_h_ + +#include "lldb/Core/StructuredData.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/InstrumentationRuntime.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class UndefinedBehaviorSanitizerRuntime + : public lldb_private::InstrumentationRuntime { +public: + ~UndefinedBehaviorSanitizerRuntime() override; + + static lldb::InstrumentationRuntimeSP + CreateInstance(const lldb::ProcessSP &process_sp); + + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static lldb::InstrumentationRuntimeType GetTypeStatic(); + + lldb_private::ConstString GetPluginName() override { + return GetPluginNameStatic(); + } + + virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); } + + uint32_t GetPluginVersion() override { return 1; } + + lldb::ThreadCollectionSP + GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override; + +private: + UndefinedBehaviorSanitizerRuntime(const lldb::ProcessSP &process_sp) + : lldb_private::InstrumentationRuntime(process_sp) {} + + const RegularExpression &GetPatternForRuntimeLibrary() override; + + bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override; + + void Activate() override; + + void Deactivate(); + + static bool NotifyBreakpointHit(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref); +}; + +} // namespace lldb_private + +#endif // liblldb_UndefinedBehaviorSanitizerRuntime_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index dd3dc434f753..6aaf66cbb486 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -31,6 +31,8 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" +#include "llvm/ADT/APInt.h" + #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" #include "NSString.h" @@ -369,6 +371,28 @@ static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream, stream.Printf("%s%" PRId64 "%s", prefix.c_str(), value, suffix.c_str()); } +static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream, + const llvm::APInt &value, + lldb::LanguageType lang) { + static ConstString g_TypeHint("NSNumber:int128_t"); + + std::string prefix, suffix; + if (Language *language = Language::FindPlugin(lang)) { + if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, + suffix)) { + prefix.clear(); + suffix.clear(); + } + } + + stream.PutCString(prefix.c_str()); + const int radix = 10; + const bool isSigned = true; + std::string str = value.toString(radix, isSigned); + stream.PutCString(str.c_str()); + stream.PutCString(suffix.c_str()); +} + static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream, float value, lldb::LanguageType lang) { static ConstString g_TypeHint("NSNumber:float"); @@ -462,22 +486,72 @@ bool lldb_private::formatters::NSNumberSummaryProvider( return true; } else { Status error; - uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory( - valobj_addr + ptr_size, 1, 0, error) & - 0x1F); + + AppleObjCRuntime *runtime = + llvm::dyn_cast_or_null( + process_sp->GetObjCLanguageRuntime()); + + const bool new_format = + (runtime && runtime->GetFoundationVersion() >= 1400); + + enum class TypeCodes : int { + sint8 = 0x0, + sint16 = 0x1, + sint32 = 0x2, + sint64 = 0x3, + f32 = 0x4, + f64 = 0x5, + sint128 = 0x6 + }; + uint64_t data_location = valobj_addr + 2 * ptr_size; + TypeCodes type_code; + + if (new_format) { + uint64_t cfinfoa = + process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, + ptr_size, 0, error); + + if (error.Fail()) + return false; + + bool is_preserved_number = cfinfoa & 0x8; + if (is_preserved_number) { + lldbassert(!"We should handle preserved numbers!"); + return false; + } + + type_code = (TypeCodes)(cfinfoa & 0x7); + } else { + uint8_t data_type = + process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, + 0, error) & 0x1F; + + if (error.Fail()) + return false; + + switch (data_type) { + case 1: type_code = TypeCodes::sint8; break; + case 2: type_code = TypeCodes::sint16; break; + case 3: type_code = TypeCodes::sint32; break; + case 17: data_location += 8; LLVM_FALLTHROUGH; + case 4: type_code = TypeCodes::sint64; break; + case 5: type_code = TypeCodes::f32; break; + case 6: type_code = TypeCodes::f64; break; + default: return false; + } + } + uint64_t value = 0; - if (error.Fail()) - return false; - switch (data_type) { - case 1: // 0B00001 + switch (type_code) { + case TypeCodes::sint8: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error); if (error.Fail()) return false; NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); break; - case 2: // 0B0010 + case TypeCodes::sint16: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error); if (error.Fail()) @@ -485,24 +559,21 @@ bool lldb_private::formatters::NSNumberSummaryProvider( NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage()); break; - case 3: // 0B0011 + case TypeCodes::sint32: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); if (error.Fail()) return false; NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage()); break; - case 17: // 0B10001 - data_location += 8; - LLVM_FALLTHROUGH; - case 4: // 0B0100 + case TypeCodes::sint64: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); if (error.Fail()) return false; NSNumber_FormatLong(valobj, stream, value, options.GetLanguage()); break; - case 5: // 0B0101 + case TypeCodes::f32: { uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory( data_location, 4, 0, error); @@ -513,7 +584,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage()); break; } - case 6: // 0B0110 + case TypeCodes::f64: { uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory( data_location, 8, 0, error); @@ -524,6 +595,21 @@ bool lldb_private::formatters::NSNumberSummaryProvider( NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage()); break; } + case TypeCodes::sint128: // internally, this is the same + { + uint64_t words[2]; + words[1] = process_sp->ReadUnsignedIntegerFromMemory( + data_location, 8, 0, error); + if (error.Fail()) + return false; + words[0] = process_sp->ReadUnsignedIntegerFromMemory( + data_location + 8, 8, 0, error); + if (error.Fail()) + return false; + llvm::APInt i128_value(128, words); + NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage()); + break; + } default: return false; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp index b07b9ba5888f..27cb9558c482 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -160,11 +160,47 @@ class NSArrayMSyntheticFrontEnd_1010 : public NSArrayMSyntheticFrontEnd { DataDescriptor_64 *m_data_64; }; -class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd { +class NSArrayMSyntheticFrontEnd_1400 : public NSArrayMSyntheticFrontEnd { public: - NSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp); - ~NSArrayISyntheticFrontEnd() override = default; + ~NSArrayMSyntheticFrontEnd_1400() override; + + bool Update() override; + +protected: + lldb::addr_t GetDataAddress() override; + + uint64_t GetUsedCount() override; + + uint64_t GetOffset() override; + + uint64_t GetSize() override; + +private: + struct DataDescriptor_32 { + uint32_t used; + uint32_t offset; + uint32_t size; + uint32_t list; + }; + + struct DataDescriptor_64 { + uint64_t used; + uint64_t offset; + uint64_t size; + uint64_t list; + }; + + DataDescriptor_32 *m_data_32; + DataDescriptor_64 *m_data_64; +}; + +class NSArrayISyntheticFrontEnd_1300 : public SyntheticChildrenFrontEnd { +public: + NSArrayISyntheticFrontEnd_1300(lldb::ValueObjectSP valobj_sp); + + ~NSArrayISyntheticFrontEnd_1300() override = default; size_t CalculateNumChildren() override; @@ -184,6 +220,45 @@ class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd { CompilerType m_id_type; }; +class NSArrayISyntheticFrontEnd_1400 : public SyntheticChildrenFrontEnd { +public: + NSArrayISyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp); + + ~NSArrayISyntheticFrontEnd_1400() override; + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(const ConstString &name) override; + +private: + ExecutionContextRef m_exe_ctx_ref; + uint8_t m_ptr_size; + + struct DataDescriptor_32 { + uint32_t used; + uint32_t offset; + uint32_t size; + uint32_t list; + }; + + struct DataDescriptor_64 { + uint64_t used; + uint64_t offset; + uint64_t size; + uint64_t list; + }; + + DataDescriptor_32 *m_data_32; + DataDescriptor_64 *m_data_64; + CompilerType m_id_type; +}; + class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); @@ -257,6 +332,8 @@ bool lldb_private::formatters::NSArraySummaryProvider( static const ConstString g_NSArray0("__NSArray0"); static const ConstString g_NSArray1("__NSSingleObjectArrayI"); static const ConstString g_NSArrayCF("__NSCFArray"); + static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy"); + static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable"); if (class_name.IsEmpty()) return false; @@ -273,6 +350,18 @@ bool lldb_private::formatters::NSArraySummaryProvider( ptr_size, 0, error); if (error.Fail()) return false; + } else if (class_name == g_NSArrayMLegacy) { + Status error; + value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, + ptr_size, 0, error); + if (error.Fail()) + return false; + } else if (class_name == g_NSArrayMImmutable) { + Status error; + value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, + ptr_size, 0, error); + if (error.Fail()) + return false; } else if (class_name == g_NSArray0) { value = 0; } else if (class_name == g_NSArray1) { @@ -332,6 +421,11 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010:: : NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr), m_data_64(nullptr) {} +lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400:: + NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp) + : NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr), + m_data_64(nullptr) {} + size_t lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren() { return GetUsedCount(); @@ -416,6 +510,37 @@ bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::Update() { return false; } +bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::Update() { + ValueObjectSP valobj_sp = m_backend.GetSP(); + m_ptr_size = 0; + delete m_data_32; + m_data_32 = nullptr; + delete m_data_64; + m_data_64 = nullptr; + if (!valobj_sp) + return false; + m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); + Status error; + error.Clear(); + lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); + if (!process_sp) + return false; + m_ptr_size = process_sp->GetAddressByteSize(); + uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; + if (m_ptr_size == 4) { + m_data_32 = new DataDescriptor_32(); + process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), + error); + } else { + m_data_64 = new DataDescriptor_64(); + process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), + error); + } + if (error.Fail()) + return false; + return false; +} + bool lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren() { return true; } @@ -498,7 +623,42 @@ uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize() { return m_data_32 ? m_data_32->_size : m_data_64->_size; } -lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd( +lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400:: + ~NSArrayMSyntheticFrontEnd_1400() { + delete m_data_32; + m_data_32 = nullptr; + delete m_data_64; + m_data_64 = nullptr; +} + +lldb::addr_t +lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetDataAddress() { + if (!m_data_32 && !m_data_64) + return LLDB_INVALID_ADDRESS; + return m_data_32 ? m_data_32->list : m_data_64->list; +} + +uint64_t +lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetUsedCount() { + if (!m_data_32 && !m_data_64) + return 0; + return m_data_32 ? m_data_32->used : m_data_64->used; +} + +uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetOffset() { + if (!m_data_32 && !m_data_64) + return 0; + return m_data_32 ? m_data_32->offset : m_data_64->offset; +} + +uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetSize() { + if (!m_data_32 && !m_data_64) + return 0; + return m_data_32 ? m_data_32->size : m_data_64->size; +} + + +lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::NSArrayISyntheticFrontEnd_1300( lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), m_items(0), m_data_ptr(0) { @@ -516,7 +676,7 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd( } size_t -lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName( +lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetIndexOfChildWithName( const ConstString &name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); @@ -526,11 +686,11 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName( } size_t -lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren() { +lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::CalculateNumChildren() { return m_items; } -bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() { +bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::Update() { m_ptr_size = 0; m_items = 0; m_data_ptr = 0; @@ -552,12 +712,12 @@ bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() { return false; } -bool lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren() { +bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::MightHaveChildren() { return true; } lldb::ValueObjectSP -lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex( +lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetChildAtIndex( size_t idx) { if (idx >= CalculateNumChildren()) return lldb::ValueObjectSP(); @@ -575,6 +735,99 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex( m_exe_ctx_ref, m_id_type); } +lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::NSArrayISyntheticFrontEnd_1400( + lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), + m_data_32(nullptr), m_data_64(nullptr) { + if (valobj_sp) { + CompilerType type = valobj_sp->GetCompilerType(); + if (type) { + ClangASTContext *ast = valobj_sp->GetExecutionContextRef() + .GetTargetSP() + ->GetScratchClangASTContext(); + if (ast) + m_id_type = CompilerType(ast->getASTContext(), + ast->getASTContext()->ObjCBuiltinIdTy); + } + } +} + +lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::~NSArrayISyntheticFrontEnd_1400() { + delete m_data_32; + m_data_32 = nullptr; + delete m_data_64; + m_data_64 = nullptr; +} + +size_t +lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetIndexOfChildWithName( + const ConstString &name) { + const char *item_name = name.GetCString(); + uint32_t idx = ExtractIndexFromString(item_name); + if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + return UINT32_MAX; + return idx; +} + +size_t +lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::CalculateNumChildren() { + return m_data_32 ? m_data_32->used : m_data_64->used; +} + +bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::Update() { + ValueObjectSP valobj_sp = m_backend.GetSP(); + m_ptr_size = 0; + delete m_data_32; + m_data_32 = nullptr; + delete m_data_64; + m_data_64 = nullptr; + if (!valobj_sp) + return false; + m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); + Status error; + error.Clear(); + lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); + if (!process_sp) + return false; + m_ptr_size = process_sp->GetAddressByteSize(); + uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; + if (m_ptr_size == 4) { + m_data_32 = new DataDescriptor_32(); + process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), + error); + } else { + m_data_64 = new DataDescriptor_64(); + process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), + error); + } + if (error.Fail()) + return false; + return false; +} + +bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::MightHaveChildren() { + return true; +} + +lldb::ValueObjectSP +lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetChildAtIndex( + size_t idx) { + if (idx >= CalculateNumChildren()) + return lldb::ValueObjectSP(); + lldb::addr_t object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list; + object_at_idx += (idx * m_ptr_size); + ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + Status error; + if (error.Fail()) + return lldb::ValueObjectSP(); + StreamString idx_name; + idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx, + m_exe_ctx_ref, m_id_type); +} + lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd( lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp) {} @@ -683,17 +936,24 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator( static const ConstString g_NSArrayM("__NSArrayM"); static const ConstString g_NSArray0("__NSArray0"); static const ConstString g_NSArray1("__NSSingleObjectArrayI"); + static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy"); + static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable"); if (class_name.IsEmpty()) return nullptr; if (class_name == g_NSArrayI) { - return (new NSArrayISyntheticFrontEnd(valobj_sp)); + if (runtime->GetFoundationVersion() >= 1400) + return (new NSArrayISyntheticFrontEnd_1400(valobj_sp)); + else + return (new NSArrayISyntheticFrontEnd_1300(valobj_sp)); } else if (class_name == g_NSArray0) { return (new NSArray0SyntheticFrontEnd(valobj_sp)); } else if (class_name == g_NSArray1) { return (new NSArray1SyntheticFrontEnd(valobj_sp)); } else if (class_name == g_NSArrayM) { + if (runtime->GetFoundationVersion() >= 1400) + return (new NSArrayMSyntheticFrontEnd_1400(valobj_sp)); if (runtime->GetFoundationVersion() >= 1100) return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp)); else diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 6df83d52acca..50febbe39758 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -17,6 +17,8 @@ // Project includes #include "NSDictionary.h" +#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" + #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" @@ -179,6 +181,52 @@ class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd { size_t GetIndexOfChildWithName(const ConstString &name) override; +private: + struct DataDescriptor_32 { + uint32_t used : 26; + uint32_t kvo : 1; + uint32_t size; + uint32_t buffer; + }; + + struct DataDescriptor_64 { + uint64_t used : 58; + uint32_t kvo : 1; + uint64_t size; + uint64_t buffer; + }; + + struct DictionaryItemDescriptor { + lldb::addr_t key_ptr; + lldb::addr_t val_ptr; + lldb::ValueObjectSP valobj_sp; + }; + + ExecutionContextRef m_exe_ctx_ref; + uint8_t m_ptr_size; + lldb::ByteOrder m_order; + DataDescriptor_32 *m_data_32; + DataDescriptor_64 *m_data_64; + CompilerType m_pair_type; + std::vector m_children; +}; + +class NSDictionaryMLegacySyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + ~NSDictionaryMLegacySyntheticFrontEnd() override; + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(const ConstString &name) override; + private: struct DataDescriptor_32 { uint32_t _used : 26; @@ -250,19 +298,21 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( static const ConstString g_DictionaryI("__NSDictionaryI"); static const ConstString g_DictionaryM("__NSDictionaryM"); + static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); + static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable"); static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); if (class_name.IsEmpty()) return false; - if (class_name == g_DictionaryI) { + if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) { Status error; value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); if (error.Fail()) return false; value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); - } else if (class_name == g_DictionaryM) { + } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) { Status error; value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); @@ -311,9 +361,8 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) return nullptr; - ObjCLanguageRuntime *runtime = - (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime( - lldb::eLanguageTypeObjC); + AppleObjCRuntime *runtime = + llvm::dyn_cast_or_null(process_sp->GetObjCLanguageRuntime()); if (!runtime) return nullptr; @@ -338,6 +387,8 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( static const ConstString g_DictionaryI("__NSDictionaryI"); static const ConstString g_DictionaryM("__NSDictionaryM"); static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); + static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable"); + static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); if (class_name.IsEmpty()) return nullptr; @@ -345,7 +396,13 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( if (class_name == g_DictionaryI) { return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); } else if (class_name == g_DictionaryM) { - return (new NSDictionaryMSyntheticFrontEnd(valobj_sp)); + if (runtime->GetFoundationVersion() > 1400) { + return (new NSDictionaryMSyntheticFrontEnd(valobj_sp)); + } else { + return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp)); + } + } else if (class_name == g_DictionaryMLegacy) { + return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp)); } else if (class_name == g_Dictionary1) { return (new NSDictionary1SyntheticFrontEnd(valobj_sp)); } else { @@ -611,7 +668,7 @@ size_t lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: CalculateNumChildren() { if (!m_data_32 && !m_data_64) return 0; - return (m_data_32 ? m_data_32->_used : m_data_64->_used); + return (m_data_32 ? m_data_32->used : m_data_64->used); } bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() { @@ -655,6 +712,165 @@ bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd:: lldb::ValueObjectSP lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex( size_t idx) { + lldb::addr_t m_keys_ptr; + lldb::addr_t m_values_ptr; + if (m_data_32) { + uint32_t size = m_data_32->size; + m_keys_ptr = m_data_32->buffer; + m_values_ptr = m_data_32->buffer + (m_ptr_size * size); + } else { + uint32_t size = m_data_64->size; + m_keys_ptr = m_data_64->buffer; + m_values_ptr = m_data_64->buffer + (m_ptr_size * size); + } + + uint32_t num_children = CalculateNumChildren(); + + if (idx >= num_children) + return lldb::ValueObjectSP(); + + if (m_children.empty()) { + // do the scan phase + lldb::addr_t key_at_idx = 0, val_at_idx = 0; + + uint32_t tries = 0; + uint32_t test_idx = 0; + + while (tries < num_children) { + key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); + val_at_idx = m_values_ptr + (test_idx * m_ptr_size); + ; + ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + Status error; + key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); + if (error.Fail()) + return lldb::ValueObjectSP(); + val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); + if (error.Fail()) + return lldb::ValueObjectSP(); + + test_idx++; + + if (!key_at_idx || !val_at_idx) + continue; + tries++; + + DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx, + lldb::ValueObjectSP()}; + + m_children.push_back(descriptor); + } + } + + if (idx >= m_children.size()) // should never happen + return lldb::ValueObjectSP(); + + DictionaryItemDescriptor &dict_item = m_children[idx]; + if (!dict_item.valobj_sp) { + if (!m_pair_type.IsValid()) { + TargetSP target_sp(m_backend.GetTargetSP()); + if (!target_sp) + return ValueObjectSP(); + m_pair_type = GetLLDBNSPairType(target_sp); + } + if (!m_pair_type.IsValid()) + return ValueObjectSP(); + + DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0)); + + if (m_ptr_size == 8) { + uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes(); + *data_ptr = dict_item.key_ptr; + *(data_ptr + 1) = dict_item.val_ptr; + } else { + uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes(); + *data_ptr = dict_item.key_ptr; + *(data_ptr + 1) = dict_item.val_ptr; + } + + StreamString idx_name; + idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); + DataExtractor data(buffer_sp, m_order, m_ptr_size); + dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data, + m_exe_ctx_ref, m_pair_type); + } + return dict_item.valobj_sp; +} + + +lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: + NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), + m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr), + m_pair_type() {} + +lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: + ~NSDictionaryMLegacySyntheticFrontEnd() { + delete m_data_32; + m_data_32 = nullptr; + delete m_data_64; + m_data_64 = nullptr; +} + +size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: + GetIndexOfChildWithName(const ConstString &name) { + const char *item_name = name.GetCString(); + uint32_t idx = ExtractIndexFromString(item_name); + if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + return UINT32_MAX; + return idx; +} + +size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: + CalculateNumChildren() { + if (!m_data_32 && !m_data_64) + return 0; + return (m_data_32 ? m_data_32->_used : m_data_64->_used); +} + +bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::Update() { + m_children.clear(); + ValueObjectSP valobj_sp = m_backend.GetSP(); + m_ptr_size = 0; + delete m_data_32; + m_data_32 = nullptr; + delete m_data_64; + m_data_64 = nullptr; + if (!valobj_sp) + return false; + m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); + Status error; + error.Clear(); + lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); + if (!process_sp) + return false; + m_ptr_size = process_sp->GetAddressByteSize(); + m_order = process_sp->GetByteOrder(); + uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; + if (m_ptr_size == 4) { + m_data_32 = new DataDescriptor_32(); + process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), + error); + } else { + m_data_64 = new DataDescriptor_64(); + process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64), + error); + } + if (error.Fail()) + return false; + return false; +} + +bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +lldb::ValueObjectSP +lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::GetChildAtIndex( + size_t idx) { lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); lldb::addr_t m_values_ptr = diff --git a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp index 4d9227598cef..ea2eec7b33b7 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -1026,6 +1026,7 @@ bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj, static ConstString g_NSNumberShort("NSNumber:short"); static ConstString g_NSNumberInt("NSNumber:int"); static ConstString g_NSNumberLong("NSNumber:long"); + static ConstString g_NSNumberInt128("NSNumber:int128_t"); static ConstString g_NSNumberFloat("NSNumber:float"); static ConstString g_NSNumberDouble("NSNumber:double"); @@ -1061,6 +1062,10 @@ bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj, prefix = "(long)"; return true; } + if (type_hint == g_NSNumberInt128) { + prefix = "(int128_t)"; + return true; + } if (type_hint == g_NSNumberFloat) { prefix = "(float)"; return true; diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index b71d6fa4ebea..20e9a930b486 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -707,10 +707,7 @@ size_t ObjectFileELF::GetModuleSpecifications( SectionHeaderColl section_headers; lldb_private::UUID &uuid = spec.GetUUID(); - using namespace std::placeholders; - const SetDataFunction set_data = - std::bind(&ObjectFileELF::SetData, std::cref(data), _1, _2, _3); - GetSectionHeaderInfo(section_headers, set_data, header, uuid, + GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc, spec.GetArchitecture()); @@ -748,7 +745,7 @@ size_t ObjectFileELF::GetModuleSpecifications( data.SetData(data_sp); } ProgramHeaderColl program_headers; - GetProgramHeaderInfo(program_headers, set_data, header); + GetProgramHeaderInfo(program_headers, data, header); size_t segment_data_end = 0; for (ProgramHeaderCollConstIter I = program_headers.begin(); @@ -950,29 +947,7 @@ size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const { bool ObjectFileELF::ParseHeader() { lldb::offset_t offset = 0; - if (!m_header.Parse(m_data, &offset)) - return false; - - if (!IsInMemory()) - return true; - - // For in memory object files m_data might not contain the full object file. - // Try to load it - // until the end of the "Section header table" what is at the end of the ELF - // file. - addr_t file_size = m_header.e_shoff + m_header.e_shnum * m_header.e_shentsize; - if (m_data.GetByteSize() < file_size) { - ProcessSP process_sp(m_process_wp.lock()); - if (!process_sp) - return false; - - DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size); - if (!data_sp) - return false; - m_data.SetData(data_sp, 0, file_size); - } - - return true; + return m_header.Parse(m_data, &offset); } bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) { @@ -1188,7 +1163,7 @@ size_t ObjectFileELF::ParseDependentModules() { // GetProgramHeaderInfo //---------------------------------------------------------------------- size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, - const SetDataFunction &set_data, + DataExtractor &object_data, const ELFHeader &header) { // We have already parsed the program headers if (!program_headers.empty()) @@ -1205,7 +1180,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, const size_t ph_size = header.e_phnum * header.e_phentsize; const elf_off ph_offset = header.e_phoff; DataExtractor data; - if (set_data(data, ph_offset, ph_size) != ph_size) + if (data.SetData(object_data, ph_offset, ph_size) != ph_size) return 0; uint32_t idx; @@ -1225,12 +1200,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers, // ParseProgramHeaders //---------------------------------------------------------------------- size_t ObjectFileELF::ParseProgramHeaders() { - using namespace std::placeholders; - return GetProgramHeaderInfo( - m_program_headers, - std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2, - _3), - m_header); + return GetProgramHeaderInfo(m_program_headers, m_data, m_header); } lldb_private::Status @@ -1562,7 +1532,7 @@ void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length, // GetSectionHeaderInfo //---------------------------------------------------------------------- size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, - const SetDataFunction &set_data, + DataExtractor &object_data, const elf::ELFHeader &header, lldb_private::UUID &uuid, std::string &gnu_debuglink_file, @@ -1634,7 +1604,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, const size_t sh_size = header.e_shnum * header.e_shentsize; const elf_off sh_offset = header.e_shoff; DataExtractor sh_data; - if (set_data(sh_data, sh_offset, sh_size) != sh_size) + if (sh_data.SetData(object_data, sh_offset, sh_size) != sh_size) return 0; uint32_t idx; @@ -1653,7 +1623,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, const Elf64_Off offset = sheader.sh_offset; lldb_private::DataExtractor shstr_data; - if (set_data(shstr_data, offset, byte_size) == byte_size) { + if (shstr_data.SetData(object_data, offset, byte_size) == byte_size) { for (SectionHeaderCollIter I = section_headers.begin(); I != section_headers.end(); ++I) { static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink"); @@ -1669,8 +1639,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, DataExtractor data; if (sheader.sh_type == SHT_MIPS_ABIFLAGS) { - if (section_size && (set_data(data, sheader.sh_offset, - section_size) == section_size)) { + if (section_size && (data.SetData(object_data, sheader.sh_offset, + section_size) == section_size)) { // MIPS ASE Mask is at offset 12 in MIPS.abiflags section lldb::offset_t offset = 12; // MIPS ABI Flags Version: 0 arch_flags |= data.GetU32(&offset); @@ -1723,7 +1693,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, // ABI Mask doesn't cover N32 and N64 ABI. if (header.e_ident[EI_CLASS] == llvm::ELF::ELFCLASS64) arch_flags |= lldb_private::ArchSpec::eMIPSABI_N64; - else if (header.e_flags && llvm::ELF::EF_MIPS_ABI2) + else if (header.e_flags & llvm::ELF::EF_MIPS_ABI2) arch_flags |= lldb_private::ArchSpec::eMIPSABI_N32; break; } @@ -1735,14 +1705,14 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, DataExtractor data; if (sheader.sh_type == SHT_ARM_ATTRIBUTES && section_size != 0 && - set_data(data, sheader.sh_offset, section_size) == section_size) + data.SetData(object_data, sheader.sh_offset, section_size) == section_size) ParseARMAttributes(data, section_size, arch_spec); } if (name == g_sect_name_gnu_debuglink) { DataExtractor data; - if (section_size && (set_data(data, sheader.sh_offset, - section_size) == section_size)) { + if (section_size && (data.SetData(object_data, sheader.sh_offset, + section_size) == section_size)) { lldb::offset_t gnu_debuglink_offset = 0; gnu_debuglink_file = data.GetCStr(&gnu_debuglink_offset); gnu_debuglink_offset = llvm::alignTo(gnu_debuglink_offset, 4); @@ -1762,8 +1732,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, if (is_note_header) { // Allow notes to refine module info. DataExtractor data; - if (section_size && (set_data(data, sheader.sh_offset, - section_size) == section_size)) { + if (section_size && (data.SetData(object_data, sheader.sh_offset, + section_size) == section_size)) { Status error = RefineModuleDetailsFromNote(data, arch_spec, uuid); if (error.Fail()) { if (log) @@ -1819,40 +1789,9 @@ ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const { // ParseSectionHeaders //---------------------------------------------------------------------- size_t ObjectFileELF::ParseSectionHeaders() { - using namespace std::placeholders; - - return GetSectionHeaderInfo( - m_section_headers, - std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2, - _3), - m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec); -} - -lldb::offset_t ObjectFileELF::SetData(const lldb_private::DataExtractor &src, - lldb_private::DataExtractor &dst, - lldb::offset_t offset, - lldb::offset_t length) { - return dst.SetData(src, offset, length); -} - -lldb::offset_t -ObjectFileELF::SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst, - lldb::offset_t offset, - lldb::offset_t length) { - if (offset + length <= m_data.GetByteSize()) - return dst.SetData(m_data, offset, length); - - const auto process_sp = m_process_wp.lock(); - if (process_sp != nullptr) { - addr_t file_size = offset + length; - - DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size); - if (!data_sp) - return false; - m_data.SetData(data_sp, 0, file_size); - } - - return dst.SetData(m_data, offset, length); + return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, + m_gnu_debuglink_file, m_gnu_debuglink_crc, + m_arch_spec); } const ObjectFileELF::ELFSectionHeaderInfo * diff --git a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 06f1a4d22d2d..6d8717b0ef25 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/contrib/llvm/tools/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -14,7 +14,6 @@ #include // C++ Includes -#include #include // Other libraries and framework includes @@ -182,9 +181,6 @@ class ObjectFileELF : public lldb_private::ObjectFile { typedef std::map FileAddressToAddressClassMap; - typedef std::function - SetDataFunction; /// Version of this reader common to all plugins based on this class. static const uint32_t m_plugin_version = 1; @@ -230,7 +226,7 @@ class ObjectFileELF : public lldb_private::ObjectFile { // Parses the ELF program headers. static size_t GetProgramHeaderInfo(ProgramHeaderColl &program_headers, - const SetDataFunction &set_data, + lldb_private::DataExtractor &object_data, const elf::ELFHeader &header); // Finds PT_NOTE segments and calculates their crc sum. @@ -255,7 +251,7 @@ class ObjectFileELF : public lldb_private::ObjectFile { /// Parses the elf section headers and returns the uuid, debug link name, crc, /// archspec. static size_t GetSectionHeaderInfo(SectionHeaderColl §ion_headers, - const SetDataFunction &set_data, + lldb_private::DataExtractor &object_data, const elf::ELFHeader &header, lldb_private::UUID &uuid, std::string &gnu_debuglink_file, @@ -379,14 +375,6 @@ class ObjectFileELF : public lldb_private::ObjectFile { RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch_spec, lldb_private::UUID &uuid); - - static lldb::offset_t SetData(const lldb_private::DataExtractor &src, - lldb_private::DataExtractor &dst, - lldb::offset_t offset, lldb::offset_t length); - - lldb::offset_t SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst, - lldb::offset_t offset, - lldb::offset_t length); }; #endif // liblldb_ObjectFileELF_h_ diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp index f6c8c78ccb73..518f0d2da4f2 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp @@ -1085,8 +1085,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() { "waitpid exiting pid from the pipe. Will notify " "as if parent process died with exit status -1.", __FUNCTION__); - SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result", - notify_status); + SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status); return error; } @@ -1099,8 +1098,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() { "waitpid exit status from the pipe. Will notify " "as if parent process died with exit status -1.", __FUNCTION__); - SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result", - notify_status); + SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status); return error; } @@ -1111,18 +1109,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() { __FUNCTION__, pid, (pid == m_pid) ? "the inferior" : "not the inferior", status); - ExitType exit_type = eExitTypeInvalid; - int exit_status = -1; - - if (WIFEXITED(status)) { - exit_type = eExitTypeExit; - exit_status = WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { - exit_type = eExitTypeSignal; - exit_status = WTERMSIG(status); - } - - SetExitStatus(exit_type, exit_status, nullptr, notify_status); + SetExitStatus(WaitStatus::Decode(status), notify_status); return error; } diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index efb19fc414f9..a4d775860a65 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -40,32 +40,6 @@ using namespace lldb_private; using namespace lldb_private::process_netbsd; using namespace llvm; -static ExitType convert_pid_status_to_exit_type(int status) { - if (WIFEXITED(status)) - return ExitType::eExitTypeExit; - else if (WIFSIGNALED(status)) - return ExitType::eExitTypeSignal; - else if (WIFSTOPPED(status)) - return ExitType::eExitTypeStop; - else { - // We don't know what this is. - return ExitType::eExitTypeInvalid; - } -} - -static int convert_pid_status_to_return_code(int status) { - if (WIFEXITED(status)) - return WEXITSTATUS(status); - else if (WIFSIGNALED(status)) - return WTERMSIG(status); - else if (WIFSTOPPED(status)) - return WSTOPSIG(status); - else { - // We don't know what this is. - return ExitType::eExitTypeInvalid; - } -} - // Simple helper function to ensure flags are enabled on the given file // descriptor. static Status EnsureFDFlags(int fd, int flags) { @@ -177,17 +151,15 @@ void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) { } } -void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, int signal, - int status) { +void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - LLDB_LOG(log, "got exit signal({0}) , pid = {1}", signal, pid); + LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid); /* Stop Tracking All Threads attached to Process */ m_threads.clear(); - SetExitStatus(convert_pid_status_to_exit_type(status), - convert_pid_status_to_return_code(status), nullptr, true); + SetExitStatus(status, true); // Notify delegate that our process has exited. SetState(StateType::eStateExited, true); @@ -861,36 +833,21 @@ void NativeProcessNetBSD::SigchldHandler() { LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error); } - bool exited = false; - int signal = 0; - int exit_status = 0; - const char *status_cstr = nullptr; - if (WIFSTOPPED(status)) { - signal = WSTOPSIG(status); - status_cstr = "STOPPED"; - } else if (WIFEXITED(status)) { - exit_status = WEXITSTATUS(status); - status_cstr = "EXITED"; - exited = true; - } else if (WIFSIGNALED(status)) { - signal = WTERMSIG(status); - status_cstr = "SIGNALED"; - if (wait_pid == static_cast<::pid_t>(GetID())) { - exited = true; - exit_status = -1; - } - } else - status_cstr = "(\?\?\?)"; + WaitStatus wait_status = WaitStatus::Decode(status); + bool exited = wait_status.type == WaitStatus::Exit || + (wait_status.type == WaitStatus::Signal && + wait_pid == static_cast<::pid_t>(GetID())); LLDB_LOG(log, - "waitpid ({0}, &status, _) => pid = {1}, status = {2:x} " - "({3}), signal = {4}, exit_state = {5}", - GetID(), wait_pid, status, status_cstr, signal, exit_status); + "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}", + GetID(), wait_pid, status, exited); if (exited) - MonitorExited(wait_pid, signal, exit_status); - else - MonitorCallback(wait_pid, signal); + MonitorExited(wait_pid, wait_status); + else { + assert(wait_status.type == WaitStatus::Stop); + MonitorCallback(wait_pid, wait_status.status); + } } bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) { diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 758956e3dca1..7a1303faea68 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -123,7 +123,7 @@ class NativeProcessNetBSD : public NativeProcessProtocol { void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error); void MonitorCallback(lldb::pid_t pid, int signal); - void MonitorExited(lldb::pid_t pid, int signal, int status); + void MonitorExited(lldb::pid_t pid, WaitStatus status); void MonitorSIGSTOP(lldb::pid_t pid); void MonitorSIGTRAP(lldb::pid_t pid); void MonitorSignal(lldb::pid_t pid, int signal); diff --git a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index d318c35366f1..d34a79453fed 100644 --- a/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/contrib/llvm/tools/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -370,53 +370,23 @@ GDBRemoteCommunicationServerLLGS::SendWResponse( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // send W notification - ExitType exit_type = ExitType::eExitTypeInvalid; - int return_code = 0; - std::string exit_description; - - const bool got_exit_info = - process->GetExitStatus(&exit_type, &return_code, exit_description); - if (!got_exit_info) { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - ", failed to retrieve process exit status", - __FUNCTION__, process->GetID()); + auto wait_status = process->GetExitStatus(); + if (!wait_status) { + LLDB_LOG(log, "pid = {0}, failed to retrieve process exit status", + process->GetID()); StreamGDBRemote response; response.PutChar('E'); response.PutHex8(GDBRemoteServerError::eErrorExitStatus); - return SendPacketNoLock(response.GetString()); - } else { - if (log) - log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 - ", returning exit type %d, return code %d [%s]", - __FUNCTION__, process->GetID(), exit_type, return_code, - exit_description.c_str()); - - StreamGDBRemote response; - - char return_type_code; - switch (exit_type) { - case ExitType::eExitTypeExit: - return_type_code = 'W'; - break; - case ExitType::eExitTypeSignal: - return_type_code = 'X'; - break; - case ExitType::eExitTypeStop: - return_type_code = 'S'; - break; - case ExitType::eExitTypeInvalid: - return_type_code = 'E'; - break; - } - response.PutChar(return_type_code); - - // POSIX exit status limited to unsigned 8 bits. - response.PutHex8(return_code); - return SendPacketNoLock(response.GetString()); } + + LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(), + *wait_status); + + StreamGDBRemote response; + response.Format("{0:g}", *wait_status); + return SendPacketNoLock(response.GetString()); } static void AppendHexValue(StreamString &response, const uint8_t *buf, diff --git a/contrib/llvm/tools/lli/OrcLazyJIT.cpp b/contrib/llvm/tools/lli/OrcLazyJIT.cpp index ec61ce5e1545..2e15894152f9 100644 --- a/contrib/llvm/tools/lli/OrcLazyJIT.cpp +++ b/contrib/llvm/tools/lli/OrcLazyJIT.cpp @@ -1,4 +1,4 @@ -//===------ OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution -------===// +//===- OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution ------------===// // // The LLVM Compiler Infrastructure // @@ -8,51 +8,56 @@ //===----------------------------------------------------------------------===// #include "OrcLazyJIT.h" -#include "llvm/ExecutionEngine/Orc/OrcABISupport.h" -#include "llvm/Support/Debug.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include #include +#include #include using namespace llvm; namespace { - enum class DumpKind { NoDump, DumpFuncsToStdOut, DumpModsToStdOut, - DumpModsToDisk }; +enum class DumpKind { + NoDump, + DumpFuncsToStdOut, + DumpModsToStdOut, + DumpModsToDisk +}; - cl::opt OrcDumpKind("orc-lazy-debug", - cl::desc("Debug dumping for the orc-lazy JIT."), - cl::init(DumpKind::NoDump), - cl::values( - clEnumValN(DumpKind::NoDump, "no-dump", - "Don't dump anything."), - clEnumValN(DumpKind::DumpFuncsToStdOut, - "funcs-to-stdout", - "Dump function names to stdout."), - clEnumValN(DumpKind::DumpModsToStdOut, - "mods-to-stdout", - "Dump modules to stdout."), - clEnumValN(DumpKind::DumpModsToDisk, - "mods-to-disk", - "Dump modules to the current " - "working directory. (WARNING: " - "will overwrite existing files).")), - cl::Hidden); +} // end anonymous namespace - cl::opt OrcInlineStubs("orc-lazy-inline-stubs", - cl::desc("Try to inline stubs"), - cl::init(true), cl::Hidden); -} +static cl::opt OrcDumpKind( + "orc-lazy-debug", cl::desc("Debug dumping for the orc-lazy JIT."), + cl::init(DumpKind::NoDump), + cl::values(clEnumValN(DumpKind::NoDump, "no-dump", "Don't dump anything."), + clEnumValN(DumpKind::DumpFuncsToStdOut, "funcs-to-stdout", + "Dump function names to stdout."), + clEnumValN(DumpKind::DumpModsToStdOut, "mods-to-stdout", + "Dump modules to stdout."), + clEnumValN(DumpKind::DumpModsToDisk, "mods-to-disk", + "Dump modules to the current " + "working directory. (WARNING: " + "will overwrite existing files).")), + cl::Hidden); + +static cl::opt OrcInlineStubs("orc-lazy-inline-stubs", + cl::desc("Try to inline stubs"), + cl::init(true), cl::Hidden); OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { - switch (OrcDumpKind) { case DumpKind::NoDump: - return [](std::unique_ptr M) { return M; }; + return [](std::shared_ptr M) { return M; }; case DumpKind::DumpFuncsToStdOut: - return [](std::unique_ptr M) { + return [](std::shared_ptr M) { printf("[ "); for (const auto &F : *M) { @@ -71,7 +76,7 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { }; case DumpKind::DumpModsToStdOut: - return [](std::unique_ptr M) { + return [](std::shared_ptr M) { outs() << "----- Module Start -----\n" << *M << "----- Module End -----\n"; @@ -79,7 +84,7 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { }; case DumpKind::DumpModsToDisk: - return [](std::unique_ptr M) { + return [](std::shared_ptr M) { std::error_code EC; raw_fd_ostream Out(M->getModuleIdentifier() + ".ll", EC, sys::fs::F_Text); @@ -98,7 +103,6 @@ OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() { // Defined in lli.cpp. CodeGenOpt::Level getOptLevel(); - template static PtrTy fromTargetAddress(JITTargetAddress Addr) { return reinterpret_cast(static_cast(Addr)); @@ -143,7 +147,8 @@ int llvm::runOrcLazyJIT(std::vector> Ms, OrcInlineStubs); // Add the module, look up main and run it. - J.addModuleSet(std::move(Ms)); + for (auto &M : Ms) + J.addModule(std::shared_ptr(std::move(M))); auto MainSym = J.findSymbol("main"); if (!MainSym) { @@ -151,11 +156,10 @@ int llvm::runOrcLazyJIT(std::vector> Ms, return 1; } - typedef int (*MainFnPtr)(int, const char*[]); + using MainFnPtr = int (*)(int, const char*[]); std::vector ArgV; for (auto &Arg : Args) ArgV.push_back(Arg.c_str()); auto Main = fromTargetAddress(MainSym.getAddress()); return Main(ArgV.size(), (const char**)ArgV.data()); } - diff --git a/contrib/llvm/tools/lli/OrcLazyJIT.h b/contrib/llvm/tools/lli/OrcLazyJIT.h index 56e7d36d05fb..fc02a10b514e 100644 --- a/contrib/llvm/tools/lli/OrcLazyJIT.h +++ b/contrib/llvm/tools/lli/OrcLazyJIT.h @@ -1,4 +1,4 @@ -//===--- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution --*- C++ -*-===// +//===- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -15,38 +15,53 @@ #ifndef LLVM_TOOLS_LLI_ORCLAZYJIT_H #define LLVM_TOOLS_LLI_ORCLAZYJIT_H -#include "llvm/ADT/Triple.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" +#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/IRTransformLayer.h" +#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include +#include +#include +#include +#include +#include namespace llvm { class OrcLazyJIT { public: - typedef orc::JITCompileCallbackManager CompileCallbackMgr; - typedef orc::RTDyldObjectLinkingLayer<> ObjLayerT; - typedef orc::IRCompileLayer CompileLayerT; - typedef std::function(std::unique_ptr)> - TransformFtor; - typedef orc::IRTransformLayer IRDumpLayerT; - typedef orc::CompileOnDemandLayer CODLayerT; - typedef CODLayerT::IndirectStubsManagerBuilderT - IndirectStubsManagerBuilder; - typedef CODLayerT::ModuleSetHandleT ModuleSetHandleT; + using CompileCallbackMgr = orc::JITCompileCallbackManager; + using ObjLayerT = orc::RTDyldObjectLinkingLayer; + using CompileLayerT = orc::IRCompileLayer; + using TransformFtor = + std::function(std::shared_ptr)>; + using IRDumpLayerT = orc::IRTransformLayer; + using CODLayerT = orc::CompileOnDemandLayer; + using IndirectStubsManagerBuilder = CODLayerT::IndirectStubsManagerBuilderT; + using ModuleHandleT = CODLayerT::ModuleHandleT; OrcLazyJIT(std::unique_ptr TM, std::unique_ptr CCMgr, IndirectStubsManagerBuilder IndirectStubsMgrBuilder, bool InlineStubs) : TM(std::move(TM)), DL(this->TM->createDataLayout()), - CCMgr(std::move(CCMgr)), - ObjectLayer(), + CCMgr(std::move(CCMgr)), CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)), IRDumpLayer(CompileLayer, createDebugDumper()), CODLayer(IRDumpLayer, extractSingleFunction, *this->CCMgr, @@ -62,11 +77,9 @@ class OrcLazyJIT { DtorRunner.runViaLayer(CODLayer); } - ModuleSetHandleT addModuleSet(std::vector> Ms) { - // Attach a data-layouts if they aren't already present. - for (auto &M : Ms) - if (M->getDataLayout().isDefault()) - M->setDataLayout(DL); + void addModule(std::shared_ptr M) { + if (M->getDataLayout().isDefault()) + M->setDataLayout(DL); // Rename, bump linkage and record static constructors and destructors. // We have to do this before we hand over ownership of the module to the @@ -74,21 +87,19 @@ class OrcLazyJIT { std::vector CtorNames, DtorNames; { unsigned CtorId = 0, DtorId = 0; - for (auto &M : Ms) { - for (auto Ctor : orc::getConstructors(*M)) { - std::string NewCtorName = ("$static_ctor." + Twine(CtorId++)).str(); - Ctor.Func->setName(NewCtorName); - Ctor.Func->setLinkage(GlobalValue::ExternalLinkage); - Ctor.Func->setVisibility(GlobalValue::HiddenVisibility); - CtorNames.push_back(mangle(NewCtorName)); - } - for (auto Dtor : orc::getDestructors(*M)) { - std::string NewDtorName = ("$static_dtor." + Twine(DtorId++)).str(); - Dtor.Func->setLinkage(GlobalValue::ExternalLinkage); - Dtor.Func->setVisibility(GlobalValue::HiddenVisibility); - DtorNames.push_back(mangle(Dtor.Func->getName())); - Dtor.Func->setName(NewDtorName); - } + for (auto Ctor : orc::getConstructors(*M)) { + std::string NewCtorName = ("$static_ctor." + Twine(CtorId++)).str(); + Ctor.Func->setName(NewCtorName); + Ctor.Func->setLinkage(GlobalValue::ExternalLinkage); + Ctor.Func->setVisibility(GlobalValue::HiddenVisibility); + CtorNames.push_back(mangle(NewCtorName)); + } + for (auto Dtor : orc::getDestructors(*M)) { + std::string NewDtorName = ("$static_dtor." + Twine(DtorId++)).str(); + Dtor.Func->setLinkage(GlobalValue::ExternalLinkage); + Dtor.Func->setVisibility(GlobalValue::HiddenVisibility); + DtorNames.push_back(mangle(Dtor.Func->getName())); + Dtor.Func->setName(NewDtorName); } } @@ -96,46 +107,49 @@ class OrcLazyJIT { // 1) Search the JIT symbols. // 2) Check for C++ runtime overrides. // 3) Search the host process (LLI)'s symbol table. - auto Resolver = - orc::createLambdaResolver( - [this](const std::string &Name) -> JITSymbol { - if (auto Sym = CODLayer.findSymbol(Name, true)) - return Sym; - return CXXRuntimeOverrides.searchOverrides(Name); - }, - [](const std::string &Name) { - if (auto Addr = - RTDyldMemoryManager::getSymbolAddressInProcess(Name)) - return JITSymbol(Addr, JITSymbolFlags::Exported); - return JITSymbol(nullptr); - } - ); + if (ModulesHandle == CODLayerT::ModuleHandleT()) { + auto Resolver = + orc::createLambdaResolver( + [this](const std::string &Name) -> JITSymbol { + if (auto Sym = CODLayer.findSymbol(Name, true)) + return Sym; + return CXXRuntimeOverrides.searchOverrides(Name); + }, + [](const std::string &Name) { + if (auto Addr = + RTDyldMemoryManager::getSymbolAddressInProcess(Name)) + return JITSymbol(Addr, JITSymbolFlags::Exported); + return JITSymbol(nullptr); + } + ); - // Add the module to the JIT. - auto H = CODLayer.addModuleSet(std::move(Ms), - llvm::make_unique(), - std::move(Resolver)); + // Add the module to the JIT. + ModulesHandle = + CODLayer.addModule(std::move(M), + llvm::make_unique(), + std::move(Resolver)); + } else + CODLayer.addExtraModule(ModulesHandle, std::move(M)); // Run the static constructors, and save the static destructor runner for // execution when the JIT is torn down. - orc::CtorDtorRunner CtorRunner(std::move(CtorNames), H); + orc::CtorDtorRunner CtorRunner(std::move(CtorNames), + ModulesHandle); CtorRunner.runViaLayer(CODLayer); - IRStaticDestructorRunners.emplace_back(std::move(DtorNames), H); - - return H; + IRStaticDestructorRunners.emplace_back(std::move(DtorNames), + ModulesHandle); } JITSymbol findSymbol(const std::string &Name) { return CODLayer.findSymbol(mangle(Name), true); } - JITSymbol findSymbolIn(ModuleSetHandleT H, const std::string &Name) { + JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) { return CODLayer.findSymbolIn(H, mangle(Name), true); } private: - std::string mangle(const std::string &Name) { std::string MangledName; { @@ -165,6 +179,7 @@ class OrcLazyJIT { orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides; std::vector> IRStaticDestructorRunners; + CODLayerT::ModuleHandleT ModulesHandle; }; int runOrcLazyJIT(std::vector> Ms, @@ -172,4 +187,4 @@ int runOrcLazyJIT(std::vector> Ms, } // end namespace llvm -#endif +#endif // LLVM_TOOLS_LLI_ORCLAZYJIT_H diff --git a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp index 722cb9e7e449..513e1b87558f 100644 --- a/contrib/llvm/tools/llvm-nm/llvm-nm.cpp +++ b/contrib/llvm/tools/llvm-nm/llvm-nm.cpp @@ -48,6 +48,7 @@ #include #include #include +#include using namespace llvm; using namespace object; @@ -167,6 +168,15 @@ cl::list SegSect("s", cl::Positional, cl::ZeroOrMore, cl::opt FormatMachOasHex("x", cl::desc("Print symbol entry in hex, " "Mach-O only"), cl::Grouping); +cl::opt AddDyldInfo("add-dyldinfo", + cl::desc("Add symbols from the dyldinfo not already " + "in the symbol table, Mach-O only")); +cl::opt NoDyldInfo("no-dyldinfo", + cl::desc("Don't add any symbols from the dyldinfo, " + "Mach-O only")); +cl::opt DyldInfoOnly("dyldinfo-only", + cl::desc("Show only symbols from the dyldinfo, " + "Mach-O only")); cl::opt NoLLVMBitcode("no-llvm-bc", cl::desc("Disable LLVM bitcode reader")); @@ -247,6 +257,17 @@ struct NMSymbol { char TypeChar; StringRef Name; BasicSymbolRef Sym; + // The Sym field above points to the native symbol in the object file, + // for Mach-O when we are creating symbols from the dyld info the above + // pointer is null as there is no native symbol. In these cases the fields + // below are filled in to represent what would have been a Mach-O nlist + // native symbol. + uint32_t SymFlags; + SectionRef Section; + uint8_t NType; + uint8_t NSect; + uint16_t NDesc; + StringRef IndirectName; }; } // anonymous namespace @@ -331,22 +352,38 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I, H_64 = MachO->MachOObjectFile::getHeader64(); Filetype = H_64.filetype; Flags = H_64.flags; - MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI); - NType = STE_64.n_type; - NSect = STE_64.n_sect; - NDesc = STE_64.n_desc; - NStrx = STE_64.n_strx; - NValue = STE_64.n_value; + if (SymDRI.p){ + MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI); + NType = STE_64.n_type; + NSect = STE_64.n_sect; + NDesc = STE_64.n_desc; + NStrx = STE_64.n_strx; + NValue = STE_64.n_value; + } else { + NType = I->NType; + NSect = I->NSect; + NDesc = I->NDesc; + NStrx = 0; + NValue = I->Address; + } } else { H = MachO->MachOObjectFile::getHeader(); Filetype = H.filetype; Flags = H.flags; - MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI); - NType = STE.n_type; - NSect = STE.n_sect; - NDesc = STE.n_desc; - NStrx = STE.n_strx; - NValue = STE.n_value; + if (SymDRI.p){ + MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI); + NType = STE.n_type; + NSect = STE.n_sect; + NDesc = STE.n_desc; + NStrx = STE.n_strx; + NValue = STE.n_value; + } else { + NType = I->NType; + NSect = I->NSect; + NDesc = I->NDesc; + NStrx = 0; + NValue = I->Address; + } } } @@ -363,7 +400,22 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I, outs() << Str << ' '; format("%08x", NStrx).print(Str, sizeof(Str)); outs() << Str << ' '; - outs() << I->Name << "\n"; + outs() << I->Name; + if ((NType & MachO::N_TYPE) == MachO::N_INDR) { + outs() << " (indirect for "; + format(printFormat, NValue).print(Str, sizeof(Str)); + outs() << Str << ' '; + StringRef IndirectName; + if (I->Sym.getRawDataRefImpl().p) { + if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName)) + outs() << "?)"; + else + outs() << IndirectName << ")"; + } + else + outs() << I->IndirectName << ")"; + } + outs() << "\n"; return; } @@ -419,14 +471,19 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I, outs() << "(?,?) "; break; } - Expected SecOrErr = - MachO->getSymbolSection(I->Sym.getRawDataRefImpl()); - if (!SecOrErr) { - consumeError(SecOrErr.takeError()); - outs() << "(?,?) "; - break; + section_iterator Sec = SectionRef(); + if (I->Sym.getRawDataRefImpl().p) { + Expected SecOrErr = + MachO->getSymbolSection(I->Sym.getRawDataRefImpl()); + if (!SecOrErr) { + consumeError(SecOrErr.takeError()); + outs() << "(?,?) "; + break; + } + Sec = *SecOrErr; + } else { + Sec = I->Section; } - section_iterator Sec = *SecOrErr; DataRefImpl Ref = Sec->getRawDataRefImpl(); StringRef SectionName; MachO->getSectionName(Ref, SectionName); @@ -485,11 +542,17 @@ static void darwinPrintSymbol(SymbolicFile &Obj, SymbolListT::iterator I, if ((NType & MachO::N_TYPE) == MachO::N_INDR) { outs() << I->Name << " (for "; StringRef IndirectName; - if (!MachO || - MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName)) + if (MachO) { + if (I->Sym.getRawDataRefImpl().p) { + if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName)) + outs() << "?)"; + else + outs() << IndirectName << ")"; + } + else + outs() << I->IndirectName << ")"; + } else outs() << "?)"; - else - outs() << IndirectName << ")"; } else outs() << I->Name; @@ -660,7 +723,12 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, for (SymbolListT::iterator I = SymbolList.begin(), E = SymbolList.end(); I != E; ++I) { - uint32_t SymFlags = I->Sym.getFlags(); + uint32_t SymFlags; + if (I->Sym.getRawDataRefImpl().p) + SymFlags = I->Sym.getFlags(); + else + SymFlags = I->SymFlags; + bool Undefined = SymFlags & SymbolRef::SF_Undefined; bool Global = SymFlags & SymbolRef::SF_Global; if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) || @@ -699,10 +767,13 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, } } + MachOObjectFile *MachO = dyn_cast(&Obj); // Otherwise, print the symbol address and size. if (symbolIsDefined(*I)) { if (Obj.isIR()) strcpy(SymbolAddrStr, printDashes); + else if(MachO && I->TypeChar == 'I') + strcpy(SymbolAddrStr, printBlanks); else format(printFormat, I->Address) .print(SymbolAddrStr, sizeof(SymbolAddrStr)); @@ -714,7 +785,6 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, // nm(1) -m output or hex, else if OutputFormat is darwin or we are // printing Mach-O symbols in hex and not a Mach-O object fall back to // OutputFormat bsd (see below). - MachOObjectFile *MachO = dyn_cast(&Obj); if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) { darwinPrintSymbol(Obj, I, SymbolAddrStr, printBlanks, printDashes, printFormat); @@ -734,7 +804,19 @@ static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName, outs() << I->TypeChar; if (I->TypeChar == '-' && MachO) darwinPrintStab(MachO, I); - outs() << " " << I->Name << "\n"; + outs() << " " << I->Name; + if (I->TypeChar == 'I' && MachO) { + outs() << " (indirect for "; + if (I->Sym.getRawDataRefImpl().p) { + StringRef IndirectName; + if (MachO->getIndirectName(I->Sym.getRawDataRefImpl(), IndirectName)) + outs() << "?)"; + else + outs() << IndirectName << ")"; + } else + outs() << I->IndirectName << ")"; + } + outs() << "\n"; } else if (OutputFormat == sysv) { std::string PaddedName(I->Name); while (PaddedName.length() < 20) @@ -1022,51 +1104,439 @@ dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, if (Nsect == 0) return; } - for (BasicSymbolRef Sym : Symbols) { - uint32_t SymFlags = Sym.getFlags(); - if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific)) - continue; - if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect)) - continue; - // If a "-s segname sectname" option was specified and this is a Mach-O - // file and this section appears in this file, Nsect will be non-zero then - // see if this symbol is a symbol from that section and if not skip it. - if (Nsect && Nsect != getNsectInMachO(*MachO, Sym)) - continue; - NMSymbol S; - S.Size = 0; - S.Address = 0; - if (PrintSize) { - if (isa(&Obj)) - S.Size = ELFSymbolRef(Sym).getSize(); - } - if (PrintAddress && isa(Obj)) { - SymbolRef SymRef(Sym); - Expected AddressOrErr = SymRef.getAddress(); - if (!AddressOrErr) { - consumeError(AddressOrErr.takeError()); - break; + if (!MachO || !DyldInfoOnly) { + for (BasicSymbolRef Sym : Symbols) { + uint32_t SymFlags = Sym.getFlags(); + if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific)) + continue; + if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect)) + continue; + // If a "-s segname sectname" option was specified and this is a Mach-O + // file and this section appears in this file, Nsect will be non-zero then + // see if this symbol is a symbol from that section and if not skip it. + if (Nsect && Nsect != getNsectInMachO(*MachO, Sym)) + continue; + NMSymbol S; + memset(&S, '\0', sizeof(S)); + S.Size = 0; + S.Address = 0; + if (PrintSize) { + if (isa(&Obj)) + S.Size = ELFSymbolRef(Sym).getSize(); } - S.Address = *AddressOrErr; + if (PrintAddress && isa(Obj)) { + SymbolRef SymRef(Sym); + Expected AddressOrErr = SymRef.getAddress(); + if (!AddressOrErr) { + consumeError(AddressOrErr.takeError()); + break; + } + S.Address = *AddressOrErr; + } + S.TypeChar = getNMTypeChar(Obj, Sym); + std::error_code EC = Sym.printName(OS); + if (EC && MachO) + OS << "bad string index"; + else + error(EC); + OS << '\0'; + S.Sym = Sym; + SymbolList.push_back(S); } - S.TypeChar = getNMTypeChar(Obj, Sym); - std::error_code EC = Sym.printName(OS); - if (EC && MachO) - OS << "bad string index"; - else - error(EC); - OS << '\0'; - S.Sym = Sym; - SymbolList.push_back(S); } OS.flush(); const char *P = NameBuffer.c_str(); - for (unsigned I = 0; I < SymbolList.size(); ++I) { + unsigned I; + for (I = 0; I < SymbolList.size(); ++I) { SymbolList[I].Name = P; P += strlen(P) + 1; } + // If this is a Mach-O file where the nlist symbol table is out of sync + // with the dyld export trie then look through exports and fake up symbols + // for the ones that are missing (also done with the -add-dyldinfo flag). + // This is needed if strip(1) -T is run on a binary containing swift + // language symbols for example. The option -only-dyldinfo will fake up + // all symbols from the dyld export trie as well as the bind info. + std::string ExportsNameBuffer; + raw_string_ostream EOS(ExportsNameBuffer); + std::string BindsNameBuffer; + raw_string_ostream BOS(BindsNameBuffer); + std::string LazysNameBuffer; + raw_string_ostream LOS(LazysNameBuffer); + std::string WeaksNameBuffer; + raw_string_ostream WOS(WeaksNameBuffer); + if (MachO && !NoDyldInfo) { + MachO::mach_header H; + MachO::mach_header_64 H_64; + uint32_t HFlags = 0; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + HFlags = H_64.flags; + } else { + H = MachO->MachOObjectFile::getHeader(); + HFlags = H.flags; + } + uint64_t BaseSegmentAddress = 0; + for (const auto &Command : MachO->load_commands()) { + if (Command.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = MachO->getSegmentLoadCommand(Command); + if (Seg.fileoff == 0 && Seg.filesize != 0) { + BaseSegmentAddress = Seg.vmaddr; + break; + } + } else if (Command.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Command); + if (Seg.fileoff == 0 && Seg.filesize != 0) { + BaseSegmentAddress = Seg.vmaddr; + break; + } + } + } + if (DyldInfoOnly || AddDyldInfo || + HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) { + unsigned ExportsAdded = 0; + for (const llvm::object::ExportEntry &Entry : MachO->exports()) { + bool found = false; + bool ReExport = false; + if (!DyldInfoOnly) { + for (unsigned J = 0; J < SymbolList.size() && !found; ++J) { + if (SymbolList[J].Address == Entry.address() + BaseSegmentAddress && + SymbolList[J].Name == Entry.name()) + found = true; + } + } + if (!found) { + NMSymbol S; + memset(&S, '\0', sizeof(NMSymbol)); + S.Address = Entry.address() + BaseSegmentAddress; + S.Size = 0; + S.TypeChar = '\0'; + S.Name = Entry.name(); + // There is no symbol in the nlist symbol table for this so we set + // Sym effectivly to null and the rest of code in here must test for + // it and not do things like Sym.getFlags() for it. + S.Sym = BasicSymbolRef(); + S.SymFlags = SymbolRef::SF_Global; + S.Section = SectionRef(); + S.NType = 0; + S.NSect = 0; + S.NDesc = 0; + S.IndirectName = StringRef(); + + uint64_t EFlags = Entry.flags(); + bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) == + MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE); + bool Resolver = (EFlags & + MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER); + ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT); + bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION); + if (WeakDef) + S.NDesc |= MachO::N_WEAK_DEF; + if (Abs) { + S.NType = MachO::N_EXT | MachO::N_ABS; + S.TypeChar = 'A'; + } else if (ReExport) { + S.NType = MachO::N_EXT | MachO::N_INDR; + S.TypeChar = 'I'; + } else { + S.NType = MachO::N_EXT | MachO::N_SECT; + if (Resolver) { + S.Address = Entry.other() + BaseSegmentAddress; + if ((S.Address & 1) != 0 && + !MachO->is64Bit() && H.cputype == MachO::CPU_TYPE_ARM){ + S.Address &= ~1LL; + S.NDesc |= MachO::N_ARM_THUMB_DEF; + } + } else { + S.Address = Entry.address() + BaseSegmentAddress; + } + StringRef SegmentName = StringRef(); + StringRef SectionName = StringRef(); + for (const SectionRef &Section : MachO->sections()) { + S.NSect++; + Section.getName(SectionName); + SegmentName = MachO->getSectionFinalSegmentName( + Section.getRawDataRefImpl()); + if (S.Address >= Section.getAddress() && + S.Address < Section.getAddress() + Section.getSize()) { + S.Section = Section; + break; + } else if (Entry.name() == "__mh_execute_header" && + SegmentName == "__TEXT" && SectionName == "__text") { + S.Section = Section; + S.NDesc |= MachO::REFERENCED_DYNAMICALLY; + break; + } + } + if (SegmentName == "__TEXT" && SectionName == "__text") + S.TypeChar = 'T'; + else if (SegmentName == "__DATA" && SectionName == "__data") + S.TypeChar = 'D'; + else if (SegmentName == "__DATA" && SectionName == "__bss") + S.TypeChar = 'B'; + else + S.TypeChar = 'S'; + } + SymbolList.push_back(S); + + EOS << Entry.name(); + EOS << '\0'; + ExportsAdded++; + + // For ReExports there are a two more things to do, first add the + // indirect name and second create the undefined symbol using the + // referened dynamic library. + if (ReExport) { + + // Add the indirect name. + if (Entry.otherName().empty()) + EOS << Entry.name(); + else + EOS << Entry.otherName(); + EOS << '\0'; + + // Now create the undefined symbol using the referened dynamic + // library. + NMSymbol U; + memset(&U, '\0', sizeof(NMSymbol)); + U.Address = 0; + U.Size = 0; + U.TypeChar = 'U'; + if (Entry.otherName().empty()) + U.Name = Entry.name(); + else + U.Name = Entry.otherName(); + // Again there is no symbol in the nlist symbol table for this so + // we set Sym effectivly to null and the rest of code in here must + // test for it and not do things like Sym.getFlags() for it. + U.Sym = BasicSymbolRef(); + U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined; + U.Section = SectionRef(); + U.NType = MachO::N_EXT | MachO::N_UNDF; + U.NSect = 0; + U.NDesc = 0; + // The library ordinal for this undefined symbol is in the export + // trie Entry.other(). + MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other()); + U.IndirectName = StringRef(); + SymbolList.push_back(U); + + // Finally add the undefined symbol's name. + if (Entry.otherName().empty()) + EOS << Entry.name(); + else + EOS << Entry.otherName(); + EOS << '\0'; + ExportsAdded++; + } + } + } + // Set the symbol names and indirect names for the added symbols. + if (ExportsAdded) { + EOS.flush(); + const char *Q = ExportsNameBuffer.c_str(); + for (unsigned K = 0; K < ExportsAdded; K++) { + SymbolList[I].Name = Q; + Q += strlen(Q) + 1; + if (SymbolList[I].TypeChar == 'I') { + SymbolList[I].IndirectName = Q; + Q += strlen(Q) + 1; + } + I++; + } + } + + // Add the undefined symbols from the bind entries. + unsigned BindsAdded = 0; + Error BErr = Error::success(); + StringRef LastSymbolName = StringRef(); + for (const llvm::object::MachOBindEntry &Entry : MachO->bindTable(BErr)) { + bool found = false; + if (LastSymbolName == Entry.symbolName()) + found = true; + else if(!DyldInfoOnly) { + for (unsigned J = 0; J < SymbolList.size() && !found; ++J) { + if (SymbolList[J].Name == Entry.symbolName()) + found = true; + } + } + if (!found) { + LastSymbolName = Entry.symbolName(); + NMSymbol B; + memset(&B, '\0', sizeof(NMSymbol)); + B.Address = 0; + B.Size = 0; + B.TypeChar = 'U'; + // There is no symbol in the nlist symbol table for this so we set + // Sym effectivly to null and the rest of code in here must test for + // it and not do things like Sym.getFlags() for it. + B.Sym = BasicSymbolRef(); + B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined; + B.NType = MachO::N_EXT | MachO::N_UNDF; + B.NSect = 0; + B.NDesc = 0; + B.NDesc = 0; + MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal()); + B.IndirectName = StringRef(); + B.Name = Entry.symbolName(); + SymbolList.push_back(B); + BOS << Entry.symbolName(); + BOS << '\0'; + BindsAdded++; + } + } + if (BErr) + error(std::move(BErr), MachO->getFileName()); + // Set the symbol names and indirect names for the added symbols. + if (BindsAdded) { + BOS.flush(); + const char *Q = BindsNameBuffer.c_str(); + for (unsigned K = 0; K < BindsAdded; K++) { + SymbolList[I].Name = Q; + Q += strlen(Q) + 1; + if (SymbolList[I].TypeChar == 'I') { + SymbolList[I].IndirectName = Q; + Q += strlen(Q) + 1; + } + I++; + } + } + + // Add the undefined symbols from the lazy bind entries. + unsigned LazysAdded = 0; + Error LErr = Error::success(); + LastSymbolName = StringRef(); + for (const llvm::object::MachOBindEntry &Entry : + MachO->lazyBindTable(LErr)) { + bool found = false; + if (LastSymbolName == Entry.symbolName()) + found = true; + else { + // Here we must check to see it this symbol is already in the + // SymbolList as it might have already have been added above via a + // non-lazy (bind) entry. + for (unsigned J = 0; J < SymbolList.size() && !found; ++J) { + if (SymbolList[J].Name == Entry.symbolName()) + found = true; + } + } + if (!found) { + LastSymbolName = Entry.symbolName(); + NMSymbol L; + memset(&L, '\0', sizeof(NMSymbol)); + L.Name = Entry.symbolName(); + L.Address = 0; + L.Size = 0; + L.TypeChar = 'U'; + // There is no symbol in the nlist symbol table for this so we set + // Sym effectivly to null and the rest of code in here must test for + // it and not do things like Sym.getFlags() for it. + L.Sym = BasicSymbolRef(); + L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined; + L.NType = MachO::N_EXT | MachO::N_UNDF; + L.NSect = 0; + // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it + // makes sence since we are creating this from a lazy bind entry. + L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY; + MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal()); + L.IndirectName = StringRef(); + SymbolList.push_back(L); + LOS << Entry.symbolName(); + LOS << '\0'; + LazysAdded++; + } + } + if (LErr) + error(std::move(LErr), MachO->getFileName()); + // Set the symbol names and indirect names for the added symbols. + if (LazysAdded) { + LOS.flush(); + const char *Q = LazysNameBuffer.c_str(); + for (unsigned K = 0; K < LazysAdded; K++) { + SymbolList[I].Name = Q; + Q += strlen(Q) + 1; + if (SymbolList[I].TypeChar == 'I') { + SymbolList[I].IndirectName = Q; + Q += strlen(Q) + 1; + } + I++; + } + } + + // Add the undefineds symbol from the weak bind entries which are not + // strong symbols. + unsigned WeaksAdded = 0; + Error WErr = Error::success(); + LastSymbolName = StringRef(); + for (const llvm::object::MachOBindEntry &Entry : + MachO->weakBindTable(WErr)) { + bool found = false; + unsigned J = 0; + if (LastSymbolName == Entry.symbolName() || + Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) { + found = true; + } else { + for (J = 0; J < SymbolList.size() && !found; ++J) { + if (SymbolList[J].Name == Entry.symbolName()) { + found = true; + break; + } + } + } + if (!found) { + LastSymbolName = Entry.symbolName(); + NMSymbol W; + memset(&W, '\0', sizeof(NMSymbol)); + W.Name = Entry.symbolName(); + W.Address = 0; + W.Size = 0; + W.TypeChar = 'U'; + // There is no symbol in the nlist symbol table for this so we set + // Sym effectivly to null and the rest of code in here must test for + // it and not do things like Sym.getFlags() for it. + W.Sym = BasicSymbolRef(); + W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined; + W.NType = MachO::N_EXT | MachO::N_UNDF; + W.NSect = 0; + // Odd that we are using N_WEAK_DEF on an undefined symbol but that is + // what is created in this case by the linker when there are real + // symbols in the nlist structs. + W.NDesc = MachO::N_WEAK_DEF; + W.IndirectName = StringRef(); + SymbolList.push_back(W); + WOS << Entry.symbolName(); + WOS << '\0'; + WeaksAdded++; + } else { + // This is the case the symbol was previously been found and it could + // have been added from a bind or lazy bind symbol. If so and not + // a definition also mark it as weak. + if (SymbolList[J].TypeChar == 'U') + // See comment above about N_WEAK_DEF. + SymbolList[J].NDesc |= MachO::N_WEAK_DEF; + } + } + if (WErr) + error(std::move(WErr), MachO->getFileName()); + // Set the symbol names and indirect names for the added symbols. + if (WeaksAdded) { + WOS.flush(); + const char *Q = WeaksNameBuffer.c_str(); + for (unsigned K = 0; K < WeaksAdded; K++) { + SymbolList[I].Name = Q; + Q += strlen(Q) + 1; + if (SymbolList[I].TypeChar == 'I') { + SymbolList[I].IndirectName = Q; + Q += strlen(Q) + 1; + } + I++; + } + } + } + } + CurrentFilename = Obj.getFileName(); sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName); } @@ -1456,6 +1926,9 @@ int main(int argc, char **argv) { error("bad number of arguments (must be two arguments)", "for the -s option"); + if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly)) + error("-no-dyldinfo can't be used with -add-dyldinfo or -dyldinfo-only"); + std::for_each(InputFilenames.begin(), InputFilenames.end(), dumpSymbolNamesFromFile); diff --git a/contrib/llvm/tools/llvm-objdump/MachODump.cpp b/contrib/llvm/tools/llvm-objdump/MachODump.cpp index 8927f57cc97f..05c2c3f7c4cb 100644 --- a/contrib/llvm/tools/llvm-objdump/MachODump.cpp +++ b/contrib/llvm/tools/llvm-objdump/MachODump.cpp @@ -1135,7 +1135,8 @@ static void DumpInfoPlistSectionContents(StringRef Filename, DataRefImpl Ref = Section.getRawDataRefImpl(); StringRef SegName = O->getSectionFinalSegmentName(Ref); if (SegName == "__TEXT" && SectName == "__info_plist") { - outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; + if (!NoLeadingHeaders) + outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; StringRef BytesStr; Section.getContents(BytesStr); const char *sect = reinterpret_cast(BytesStr.data()); @@ -1223,8 +1224,13 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF, if (Error Err = MachOOF->checkSymbolTable()) report_error(ArchiveName, FileName, std::move(Err), ArchitectureName); - if (Disassemble) - DisassembleMachO(FileName, MachOOF, "__TEXT", "__text"); + if (Disassemble) { + if (MachOOF->getHeader().filetype == MachO::MH_KEXT_BUNDLE && + MachOOF->getHeader().cputype == MachO::CPU_TYPE_ARM64) + DisassembleMachO(FileName, MachOOF, "__TEXT_EXEC", "__text"); + else + DisassembleMachO(FileName, MachOOF, "__TEXT", "__text"); + } if (IndirectSymbols) PrintIndirectSymbols(MachOOF, !NonVerbose); if (DataInCode) @@ -1920,11 +1926,45 @@ static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, if (Arch == Triple::x86_64) { if (Size != 1 && Size != 2 && Size != 4 && Size != 0) return 0; + // For non MH_OBJECT types, like MH_KEXT_BUNDLE, Search the external + // relocation entries of a linked image (if any) for an entry that matches + // this segment offset. if (info->O->getHeader().filetype != MachO::MH_OBJECT) { - // TODO: - // Search the external relocation entries of a fully linked image - // (if any) for an entry that matches this segment offset. - // uint64_t seg_offset = (Pc + Offset); + uint64_t seg_offset = Pc + Offset; + bool reloc_found = false; + DataRefImpl Rel; + MachO::any_relocation_info RE; + bool isExtern = false; + SymbolRef Symbol; + for (const RelocationRef &Reloc : info->O->external_relocations()) { + uint64_t RelocOffset = Reloc.getOffset(); + if (RelocOffset == seg_offset) { + Rel = Reloc.getRawDataRefImpl(); + RE = info->O->getRelocation(Rel); + // external relocation entries should always be external. + isExtern = info->O->getPlainRelocationExternal(RE); + if (isExtern) { + symbol_iterator RelocSym = Reloc.getSymbol(); + Symbol = *RelocSym; + } + reloc_found = true; + break; + } + } + if (reloc_found && isExtern) { + // The Value passed in will be adjusted by the Pc if the instruction + // adds the Pc. But for x86_64 external relocation entries the Value + // is the offset from the external symbol. + if (info->O->getAnyRelocationPCRel(RE)) + op_info->Value -= Pc + Offset + Size; + Expected SymName = Symbol.getName(); + if (!SymName) + report_error(info->O->getFileName(), SymName.takeError()); + const char *name = SymName->data(); + op_info->AddSymbol.Present = 1; + op_info->AddSymbol.Name = name; + return 1; + } return 0; } // In MH_OBJECT filetypes search the section's relocation entries (if any) @@ -4572,6 +4612,12 @@ static void print_class64_t(uint64_t p, struct DisassembleInfo *info) { n_value, c.superclass); if (name != nullptr) outs() << " " << name; + else { + name = get_dyld_bind_info_symbolname(S.getAddress() + + offset + offsetof(struct class64_t, superclass), info); + if (name != nullptr) + outs() << " " << name; + } outs() << "\n"; outs() << " cache " << format("0x%" PRIx64, c.cache); @@ -7634,6 +7680,10 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype, outs() << " APP_EXTENSION_SAFE"; f &= ~MachO::MH_APP_EXTENSION_SAFE; } + if (f & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) { + outs() << " NLIST_OUTOFSYNC_WITH_DYLDINFO"; + f &= ~MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO; + } if (f != 0 || flags == 0) outs() << format(" 0x%08" PRIx32, f); } else { @@ -9336,6 +9386,22 @@ void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) { //===----------------------------------------------------------------------===// void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) { + uint64_t BaseSegmentAddress = 0; + for (const auto &Command : Obj->load_commands()) { + if (Command.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = Obj->getSegmentLoadCommand(Command); + if (Seg.fileoff == 0 && Seg.filesize != 0) { + BaseSegmentAddress = Seg.vmaddr; + break; + } + } else if (Command.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = Obj->getSegment64LoadCommand(Command); + if (Seg.fileoff == 0 && Seg.filesize != 0) { + BaseSegmentAddress = Seg.vmaddr; + break; + } + } + } for (const llvm::object::ExportEntry &Entry : Obj->exports()) { uint64_t Flags = Entry.flags(); bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT); @@ -9349,7 +9415,7 @@ void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) { outs() << "[re-export] "; else outs() << format("0x%08llX ", - Entry.address()); // FIXME:add in base address + Entry.address() + BaseSegmentAddress); outs() << Entry.name(); if (WeakDef || ThreadLocal || Resolver || Abs) { bool NeedsComma = false; diff --git a/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp b/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp index b503cdcbf1ea..6c603dd8542b 100644 --- a/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp +++ b/contrib/llvm/tools/llvm-pdbutil/Analyze.cpp @@ -12,10 +12,8 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" @@ -73,16 +71,14 @@ Error AnalysisStyle::dump() { if (!Tpi) return Tpi.takeError(); - TypeDatabase TypeDB(Tpi->getNumTypeRecords()); - TypeDatabaseVisitor DBV(TypeDB); - TypeVisitorCallbackPipeline Pipeline; HashLookupVisitor Hasher(*Tpi); - // Add them to the database - Pipeline.addCallbackToPipeline(DBV); - // Store their hash values - Pipeline.addCallbackToPipeline(Hasher); - if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline)) + uint32_t RecordCount = Tpi->getNumTypeRecords(); + auto Offsets = Tpi->getTypeIndexOffsets(); + auto Types = llvm::make_unique( + Tpi->typeArray(), RecordCount, Offsets); + + if (auto EC = codeview::visitTypeStream(*Types, Hasher)) return EC; auto &Adjusters = Tpi->getHashAdjusters(); @@ -109,7 +105,7 @@ Error AnalysisStyle::dump() { } StringRef LeafName = getLeafTypeName(R.Record.Type); uint32_t TI = R.TI.getIndex(); - StringRef TypeName = TypeDB.getTypeName(R.TI); + StringRef TypeName = Types->getTypeName(R.TI); outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI, TypeName); } @@ -119,8 +115,8 @@ Error AnalysisStyle::dump() { outs() << "Dumping hash adjustment chains\n"; for (const auto &A : Tpi->getHashAdjusters()) { TypeIndex TI(A.second); - StringRef TypeName = TypeDB.getTypeName(TI); - const CVType &HeadRecord = TypeDB.getTypeRecord(TI); + StringRef TypeName = Types->getTypeName(TI); + const CVType &HeadRecord = Types->getType(TI); assert(HeadRecord.Hash.hasValue()); auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash); @@ -134,10 +130,10 @@ Error AnalysisStyle::dump() { for (const auto &Chain : Collisions) { if (Chain.TI == TI) continue; - const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI); + const CVType &TailRecord = Types->getType(Chain.TI); outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(), getLeafTypeName(TailRecord.Type), - TypeDB.getTypeName(Chain.TI)); + Types->getTypeName(Chain.TI)); } } outs() << formatv("There are {0} orphaned hash adjusters\n", diff --git a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp new file mode 100644 index 000000000000..9e5a28c2b98b --- /dev/null +++ b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.cpp @@ -0,0 +1,501 @@ +//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BytesOutputStyle.h" + +#include "FormatUtil.h" +#include "StreamUtil.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/CodeView/Formatters.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace { +struct StreamSpec { + uint32_t SI = 0; + uint32_t Begin = 0; + uint32_t Size = 0; +}; +} // namespace + +static Expected parseStreamSpec(StringRef Str) { + StreamSpec Result; + if (Str.consumeInteger(0, Result.SI)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + if (Str.consume_front(":")) { + if (Str.consumeInteger(0, Result.Begin)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + if (Str.consume_front("@")) { + if (Str.consumeInteger(0, Result.Size)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + + if (!Str.empty()) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + return Result; +} + +static SmallVector parseStreamSpecs(LinePrinter &P) { + SmallVector Result; + + for (auto &Str : opts::bytes::DumpStreamData) { + auto ESS = parseStreamSpec(Str); + if (!ESS) { + P.formatLine("Error parsing stream spec {0}: {1}", Str, + toString(ESS.takeError())); + continue; + } + Result.push_back(*ESS); + } + return Result; +} + +static void printHeader(LinePrinter &P, const Twine &S) { + P.NewLine(); + P.formatLine("{0,=60}", S); + P.formatLine("{0}", fmt_repeat('=', 60)); +} + +BytesOutputStyle::BytesOutputStyle(PDBFile &File) + : File(File), P(2, false, outs()) {} + +Error BytesOutputStyle::dump() { + + if (opts::bytes::DumpBlockRange.hasValue()) { + auto &R = *opts::bytes::DumpBlockRange; + uint32_t Max = R.Max.getValueOr(R.Min); + + if (Max < R.Min) + return make_error( + "Invalid block range specified. Max < Min", + inconvertibleErrorCode()); + if (Max >= File.getBlockCount()) + return make_error( + "Invalid block range specified. Requested block out of bounds", + inconvertibleErrorCode()); + + dumpBlockRanges(R.Min, Max); + P.NewLine(); + } + + if (opts::bytes::DumpByteRange.hasValue()) { + auto &R = *opts::bytes::DumpByteRange; + uint32_t Max = R.Max.getValueOr(File.getFileSize()); + + if (Max < R.Min) + return make_error("Invalid byte range specified. Max < Min", + inconvertibleErrorCode()); + if (Max >= File.getFileSize()) + return make_error( + "Invalid byte range specified. Requested byte larger than file size", + inconvertibleErrorCode()); + + dumpByteRanges(R.Min, Max); + P.NewLine(); + } + + if (!opts::bytes::DumpStreamData.empty()) { + dumpStreamBytes(); + P.NewLine(); + } + + if (opts::bytes::NameMap) { + dumpNameMap(); + P.NewLine(); + } + + if (opts::bytes::SectionContributions) { + dumpSectionContributions(); + P.NewLine(); + } + + if (opts::bytes::SectionMap) { + dumpSectionMap(); + P.NewLine(); + } + + if (opts::bytes::ModuleInfos) { + dumpModuleInfos(); + P.NewLine(); + } + + if (opts::bytes::FileInfo) { + dumpFileInfo(); + P.NewLine(); + } + + if (opts::bytes::TypeServerMap) { + dumpTypeServerMap(); + P.NewLine(); + } + + if (opts::bytes::ECData) { + dumpECData(); + P.NewLine(); + } + + if (!opts::bytes::TypeIndex.empty()) { + dumpTypeIndex(StreamTPI, opts::bytes::TypeIndex); + P.NewLine(); + } + + if (!opts::bytes::IdIndex.empty()) { + dumpTypeIndex(StreamIPI, opts::bytes::IdIndex); + P.NewLine(); + } + + if (opts::bytes::ModuleSyms) { + dumpModuleSyms(); + P.NewLine(); + } + + if (opts::bytes::ModuleC11) { + dumpModuleC11(); + P.NewLine(); + } + + if (opts::bytes::ModuleC13) { + dumpModuleC13(); + P.NewLine(); + } + + return Error::success(); +} + +void BytesOutputStyle::dumpNameMap() { + printHeader(P, "Named Stream Map"); + + AutoIndent Indent(P); + + auto &InfoS = Err(File.getPDBInfoStream()); + BinarySubstreamRef NS = InfoS.getNamedStreamsBuffer(); + auto Layout = File.getStreamLayout(StreamPDB); + P.formatMsfStreamData("Named Stream Map", File, Layout, NS); +} + +void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) { + printHeader(P, "MSF Blocks"); + + AutoIndent Indent(P); + for (uint32_t I = Min; I <= Max; ++I) { + uint64_t Base = I; + Base *= File.getBlockSize(); + + auto ExpectedData = File.getBlockData(I, File.getBlockSize()); + if (!ExpectedData) { + P.formatLine("Could not get block {0}. Reason = {1}", I, + toString(ExpectedData.takeError())); + continue; + } + std::string Label = formatv("Block {0}", I).str(); + P.formatBinary(Label, *ExpectedData, Base, 0); + } +} + +void BytesOutputStyle::dumpSectionContributions() { + printHeader(P, "Section Contributions"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getSectionContributionData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Section Contributions", File, Layout, NS); +} + +void BytesOutputStyle::dumpSectionMap() { + printHeader(P, "Section Map"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getSecMapSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Section Map", File, Layout, NS); +} + +void BytesOutputStyle::dumpModuleInfos() { + printHeader(P, "Module Infos"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getModiSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Module Infos", File, Layout, NS); +} + +void BytesOutputStyle::dumpFileInfo() { + printHeader(P, "File Info"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getFileInfoSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("File Info", File, Layout, NS); +} + +void BytesOutputStyle::dumpTypeServerMap() { + printHeader(P, "Type Server Map"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getTypeServerMapSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Type Server Map", File, Layout, NS); +} + +void BytesOutputStyle::dumpECData() { + printHeader(P, "Edit and Continue Data"); + + AutoIndent Indent(P); + + auto &DbiS = Err(File.getPDBDbiStream()); + BinarySubstreamRef NS = DbiS.getECSubstreamData(); + auto Layout = File.getStreamLayout(StreamDBI); + P.formatMsfStreamData("Edit and Continue Data", File, Layout, NS); +} + +void BytesOutputStyle::dumpTypeIndex(uint32_t StreamIdx, + ArrayRef Indices) { + assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); + assert(!Indices.empty()); + + bool IsTpi = (StreamIdx == StreamTPI); + + StringRef Label = IsTpi ? "Type (TPI) Records" : "Index (IPI) Records"; + printHeader(P, Label); + auto &Stream = Err(IsTpi ? File.getPDBTpiStream() : File.getPDBIpiStream()); + + AutoIndent Indent(P); + + auto Substream = Stream.getTypeRecordsSubstream(); + auto &Types = Err(initializeTypes(StreamIdx)); + auto Layout = File.getStreamLayout(StreamIdx); + for (const auto &Id : Indices) { + TypeIndex TI(Id); + if (TI.toArrayIndex() >= Types.capacity()) { + P.formatLine("Error: TypeIndex {0} does not exist", TI); + continue; + } + + auto Type = Types.getType(TI); + uint32_t Offset = Types.getOffsetOfType(TI); + auto OneType = Substream.slice(Offset, Type.length()); + P.formatMsfStreamData(formatv("Type {0}", TI).str(), File, Layout, OneType); + } +} + +template +static void iterateOneModule(PDBFile &File, LinePrinter &P, + const DbiModuleList &Modules, uint32_t I, + uint32_t Digits, uint32_t IndentLevel, + CallbackT Callback) { + if (I >= Modules.getModuleCount()) { + P.formatLine("Mod {0:4} | Invalid module index ", + fmt_align(I, AlignStyle::Right, std::max(Digits, 4U))); + return; + } + + auto Modi = Modules.getModuleDescriptor(I); + P.formatLine("Mod {0:4} | `{1}`: ", + fmt_align(I, AlignStyle::Right, std::max(Digits, 4U)), + Modi.getModuleName()); + + uint16_t ModiStream = Modi.getModuleStreamIndex(); + AutoIndent Indent2(P, IndentLevel); + if (ModiStream == kInvalidStreamIndex) + return; + + auto ModStreamData = MappedBlockStream::createIndexedStream( + File.getMsfLayout(), File.getMsfBuffer(), ModiStream, + File.getAllocator()); + ModuleDebugStreamRef ModStream(Modi, std::move(ModStreamData)); + if (auto EC = ModStream.reload()) { + P.formatLine("Could not parse debug information."); + return; + } + auto Layout = File.getStreamLayout(ModiStream); + Callback(I, ModStream, Layout); +} + +template +static void iterateModules(PDBFile &File, LinePrinter &P, uint32_t IndentLevel, + CallbackT Callback) { + AutoIndent Indent(P); + if (!File.hasPDBDbiStream()) { + P.formatLine("DBI Stream not present"); + return; + } + + ExitOnError Err("Unexpected error processing modules"); + + auto &Stream = Err(File.getPDBDbiStream()); + + const DbiModuleList &Modules = Stream.modules(); + + if (opts::bytes::ModuleIndex.getNumOccurrences() > 0) { + iterateOneModule(File, P, Modules, opts::bytes::ModuleIndex, 1, IndentLevel, + Callback); + } else { + uint32_t Count = Modules.getModuleCount(); + uint32_t Digits = NumDigits(Count); + for (uint32_t I = 0; I < Count; ++I) { + iterateOneModule(File, P, Modules, I, Digits, IndentLevel, Callback); + } + } +} + +void BytesOutputStyle::dumpModuleSyms() { + printHeader(P, "Module Symbols"); + + AutoIndent Indent(P); + + iterateModules(File, P, 2, + [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, + const MSFStreamLayout &Layout) { + auto Symbols = Stream.getSymbolsSubstream(); + P.formatMsfStreamData("Symbols", File, Layout, Symbols); + }); +} + +void BytesOutputStyle::dumpModuleC11() { + printHeader(P, "C11 Debug Chunks"); + + AutoIndent Indent(P); + + iterateModules(File, P, 2, + [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, + const MSFStreamLayout &Layout) { + auto Chunks = Stream.getC11LinesSubstream(); + P.formatMsfStreamData("C11 Debug Chunks", File, Layout, + Chunks); + }); +} + +static std::string formatChunkKind(DebugSubsectionKind Kind) { + switch (Kind) { + RETURN_CASE(DebugSubsectionKind, None, "none"); + RETURN_CASE(DebugSubsectionKind, Symbols, "symbols"); + RETURN_CASE(DebugSubsectionKind, Lines, "lines"); + RETURN_CASE(DebugSubsectionKind, StringTable, "strings"); + RETURN_CASE(DebugSubsectionKind, FileChecksums, "checksums"); + RETURN_CASE(DebugSubsectionKind, FrameData, "frames"); + RETURN_CASE(DebugSubsectionKind, InlineeLines, "inlinee lines"); + RETURN_CASE(DebugSubsectionKind, CrossScopeImports, "xmi"); + RETURN_CASE(DebugSubsectionKind, CrossScopeExports, "xme"); + RETURN_CASE(DebugSubsectionKind, ILLines, "il lines"); + RETURN_CASE(DebugSubsectionKind, FuncMDTokenMap, "func md token map"); + RETURN_CASE(DebugSubsectionKind, TypeMDTokenMap, "type md token map"); + RETURN_CASE(DebugSubsectionKind, MergedAssemblyInput, + "merged assembly input"); + RETURN_CASE(DebugSubsectionKind, CoffSymbolRVA, "coff symbol rva"); + } + return formatUnknownEnum(Kind); +} + +void BytesOutputStyle::dumpModuleC13() { + printHeader(P, "Debug Chunks"); + + AutoIndent Indent(P); + + iterateModules( + File, P, 2, + [this](uint32_t Modi, const ModuleDebugStreamRef &Stream, + const MSFStreamLayout &Layout) { + auto Chunks = Stream.getC13LinesSubstream(); + if (opts::bytes::SplitChunks) { + for (const auto &SS : Stream.subsections()) { + BinarySubstreamRef ThisChunk; + std::tie(ThisChunk, Chunks) = Chunks.split(SS.getRecordLength()); + P.formatMsfStreamData(formatChunkKind(SS.kind()), File, Layout, + ThisChunk); + } + } else { + P.formatMsfStreamData("Debug Chunks", File, Layout, Chunks); + } + }); +} + +void BytesOutputStyle::dumpByteRanges(uint32_t Min, uint32_t Max) { + printHeader(P, "MSF Bytes"); + + AutoIndent Indent(P); + + BinaryStreamReader Reader(File.getMsfBuffer()); + ArrayRef Data; + consumeError(Reader.skip(Min)); + uint32_t Size = Max - Min + 1; + auto EC = Reader.readBytes(Data, Size); + assert(!EC); + consumeError(std::move(EC)); + P.formatBinary("Bytes", Data, Min); +} + +Expected +BytesOutputStyle::initializeTypes(uint32_t StreamIdx) { + auto &TypeCollection = (StreamIdx == StreamTPI) ? TpiTypes : IpiTypes; + if (TypeCollection) + return *TypeCollection; + + auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() + : File.getPDBIpiStream(); + if (!Tpi) + return Tpi.takeError(); + + auto &Types = Tpi->typeArray(); + uint32_t Count = Tpi->getNumTypeRecords(); + auto Offsets = Tpi->getTypeIndexOffsets(); + TypeCollection = + llvm::make_unique(Types, Count, Offsets); + + return *TypeCollection; +} + +void BytesOutputStyle::dumpStreamBytes() { + if (StreamPurposes.empty()) + discoverStreamPurposes(File, StreamPurposes); + + printHeader(P, "Stream Data"); + ExitOnError Err("Unexpected error reading stream data"); + + auto Specs = parseStreamSpecs(P); + + for (const auto &Spec : Specs) { + AutoIndent Indent(P); + if (Spec.SI >= StreamPurposes.size()) { + P.formatLine("Stream {0}: Not present", Spec.SI); + continue; + } + P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI], + Spec.Begin, Spec.Size); + } +} diff --git a/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h new file mode 100644 index 000000000000..c162163fdd01 --- /dev/null +++ b/contrib/llvm/tools/llvm-pdbutil/BytesOutputStyle.h @@ -0,0 +1,67 @@ +//===- BytesOutputStyle.h ------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H + +#include "LinePrinter.h" +#include "OutputStyle.h" + +#include "llvm/Support/Error.h" + +namespace llvm { + +namespace codeview { +class LazyRandomTypeCollection; +} + +namespace pdb { + +class PDBFile; + +class BytesOutputStyle : public OutputStyle { +public: + BytesOutputStyle(PDBFile &File); + + Error dump() override; + +private: + void dumpNameMap(); + void dumpBlockRanges(uint32_t Min, uint32_t Max); + void dumpByteRanges(uint32_t Min, uint32_t Max); + void dumpStreamBytes(); + + void dumpSectionContributions(); + void dumpSectionMap(); + void dumpModuleInfos(); + void dumpFileInfo(); + void dumpTypeServerMap(); + void dumpECData(); + + void dumpModuleSyms(); + void dumpModuleC11(); + void dumpModuleC13(); + + void dumpTypeIndex(uint32_t StreamIdx, ArrayRef Indices); + + Expected + initializeTypes(uint32_t StreamIdx); + + std::unique_ptr TpiTypes; + std::unique_ptr IpiTypes; + + PDBFile &File; + LinePrinter P; + ExitOnError Err; + SmallVector StreamPurposes; +}; +} // namespace pdb +} // namespace llvm + +#endif diff --git a/contrib/llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp b/contrib/llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp deleted file mode 100644 index 6dd54e0dbec1..000000000000 --- a/contrib/llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp +++ /dev/null @@ -1,59 +0,0 @@ -//===-- CompactTypeDumpVisitor.cpp - CodeView type info dumper --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "CompactTypeDumpVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/ScopedPrinter.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -static const EnumEntry LeafTypeNames[] = { -#define CV_TYPE(enum, val) {#enum, enum}, -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" -}; - -static StringRef getLeafName(TypeLeafKind K) { - for (const auto &E : LeafTypeNames) { - if (E.Value == K) - return E.Name; - } - return StringRef(); -} - -CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types, - ScopedPrinter *W) - : CompactTypeDumpVisitor(Types, TypeIndex(TypeIndex::FirstNonSimpleIndex), - W) {} - -CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types, - TypeIndex FirstTI, - ScopedPrinter *W) - : W(W), TI(FirstTI), Offset(0), Types(Types) {} - -Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { - return Error::success(); -} - -Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) { - uint32_t I = TI.getIndex(); - StringRef Leaf = getLeafName(Record.Type); - StringRef Name = Types.getTypeName(TI); - W->printString( - llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I, - Record.length(), Offset, Leaf, Name) - .str()); - - Offset += Record.length(); - TI.setIndex(TI.getIndex() + 1); - - return Error::success(); -} diff --git a/contrib/llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.h b/contrib/llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.h deleted file mode 100644 index 41ccea0c2e90..000000000000 --- a/contrib/llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.h +++ /dev/null @@ -1,49 +0,0 @@ -//===-- CompactTypeDumpVisitor.h - CodeView type info dumper ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H -#define LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H - -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" - -namespace llvm { -class ScopedPrinter; -namespace codeview { -class TypeCollection; -} - -namespace pdb { - -/// Dumper for CodeView type streams found in COFF object files and PDB files. -/// Dumps records on a single line, and ignores member records. -class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks { -public: - CompactTypeDumpVisitor(codeview::TypeCollection &Types, ScopedPrinter *W); - CompactTypeDumpVisitor(codeview::TypeCollection &Types, - codeview::TypeIndex FirstTI, ScopedPrinter *W); - - /// Paired begin/end actions for all types. Receives all record data, - /// including the fixed-length record prefix. - Error visitTypeBegin(codeview::CVType &Record) override; - Error visitTypeEnd(codeview::CVType &Record) override; - -private: - ScopedPrinter *W; - - codeview::TypeIndex TI; - uint32_t Offset; - codeview::TypeCollection &Types; -}; - -} // end namespace pdb -} // end namespace llvm - -#endif diff --git a/contrib/llvm/tools/llvm-pdbutil/Diff.cpp b/contrib/llvm/tools/llvm-pdbutil/Diff.cpp index 3fe6c511d35f..9b38ae1d603e 100644 --- a/contrib/llvm/tools/llvm-pdbutil/Diff.cpp +++ b/contrib/llvm/tools/llvm-pdbutil/Diff.cpp @@ -198,17 +198,6 @@ Error DiffStyle::diffSuperBlock() { File2.getBlockCount()); Diffs |= diffAndPrint("Unknown 1", File1, File2, File1.getUnknown1(), File2.getUnknown1()); - - if (opts::diff::Pedantic) { - Diffs |= diffAndPrint("Free Block Map", File1, File2, - File1.getFreeBlockMapBlock(), - File2.getFreeBlockMapBlock()); - Diffs |= diffAndPrint("Directory Size", File1, File2, - File1.getNumDirectoryBytes(), - File2.getNumDirectoryBytes()); - Diffs |= diffAndPrint("Block Map Addr", File1, File2, - File1.getBlockMapOffset(), File2.getBlockMapOffset()); - } if (!Diffs) outs() << "MSF Super Block: No differences detected...\n"; return Error::success(); @@ -222,115 +211,73 @@ Error DiffStyle::diffStreamDirectory() { outs() << "Stream Directory: Searching for differences...\n"; bool HasDifferences = false; - if (opts::diff::Pedantic) { - size_t Min = std::min(P.size(), Q.size()); - for (size_t I = 0; I < Min; ++I) { - StringRef Names[] = {P[I], Q[I]}; - uint32_t Sizes[] = {File1.getStreamByteSize(I), - File2.getStreamByteSize(I)}; - bool NamesDiffer = Names[0] != Names[1]; - bool SizesDiffer = Sizes[0] != Sizes[1]; - if (NamesDiffer) { - HasDifferences = true; - outs().indent(2) << formatv("Stream {0} - {1}: {2}, {3}: {4}\n", I, - File1.getFilePath(), Names[0], - File2.getFilePath(), Names[1]); - continue; - } - if (SizesDiffer) { - HasDifferences = true; - outs().indent(2) << formatv( - "Stream {0} ({1}): {2}: {3} bytes, {4}: {5} bytes\n", I, Names[0], - File1.getFilePath(), Sizes[0], File2.getFilePath(), Sizes[1]); - continue; - } + auto PI = to_vector<32>(enumerate(P)); + auto QI = to_vector<32>(enumerate(Q)); + + typedef decltype(PI) ContainerType; + typedef typename ContainerType::value_type value_type; + + auto Comparator = [](const value_type &I1, const value_type &I2) { + return I1.value() < I2.value(); + }; + + decltype(PI) OnlyP; + decltype(QI) OnlyQ; + decltype(PI) Common; + + set_differences(PI, QI, &OnlyP, &OnlyQ, &Common, Comparator); + + if (!OnlyP.empty()) { + HasDifferences = true; + outs().indent(2) << formatv("{0} Stream(s) only in ({1})\n", OnlyP.size(), + File1.getFilePath()); + for (auto &Item : OnlyP) { + outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(), + Item.value()); } - - ArrayRef MaxNames = (P.size() > Q.size() ? P : Q); - size_t Max = std::max(P.size(), Q.size()); - PDBFile &MaxFile = (P.size() > Q.size() ? File1 : File2); - StringRef MinFileName = - (P.size() < Q.size() ? File1.getFilePath() : File2.getFilePath()); - for (size_t I = Min; I < Max; ++I) { - HasDifferences = true; - StringRef StreamName = MaxNames[I]; - - outs().indent(2) << formatv( - "Stream {0} - {1}: , {2}: Index {3}, {4} bytes\n", - StreamName, MinFileName, MaxFile.getFilePath(), I, - MaxFile.getStreamByteSize(I)); - } - if (!HasDifferences) - outs() << "Stream Directory: No differences detected...\n"; - } else { - auto PI = to_vector<32>(enumerate(P)); - auto QI = to_vector<32>(enumerate(Q)); - - typedef decltype(PI) ContainerType; - typedef typename ContainerType::value_type value_type; - - auto Comparator = [](const value_type &I1, const value_type &I2) { - return I1.value() < I2.value(); - }; - - decltype(PI) OnlyP; - decltype(QI) OnlyQ; - decltype(PI) Common; - - set_differences(PI, QI, &OnlyP, &OnlyQ, &Common, Comparator); - - if (!OnlyP.empty()) { - HasDifferences = true; - outs().indent(2) << formatv("{0} Stream(s) only in ({1})\n", OnlyP.size(), - File1.getFilePath()); - for (auto &Item : OnlyP) { - outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(), - Item.value()); - } - } - - if (!OnlyQ.empty()) { - HasDifferences = true; - outs().indent(2) << formatv("{0} Streams(s) only in ({1})\n", - OnlyQ.size(), File2.getFilePath()); - for (auto &Item : OnlyQ) { - outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(), - Item.value()); - } - } - if (!Common.empty()) { - outs().indent(2) << formatv("Found {0} common streams. Searching for " - "intra-stream differences.\n", - Common.size()); - bool HasCommonDifferences = false; - for (const auto &Left : Common) { - // Left was copied from the first range so its index refers to a stream - // index in the first file. Find the corresponding stream index in the - // second file. - auto Range = - std::equal_range(QI.begin(), QI.end(), Left, - [](const value_type &L, const value_type &R) { - return L.value() < R.value(); - }); - const auto &Right = *Range.first; - assert(Left.value() == Right.value()); - uint32_t LeftSize = File1.getStreamByteSize(Left.index()); - uint32_t RightSize = File2.getStreamByteSize(Right.index()); - if (LeftSize != RightSize) { - HasDifferences = true; - HasCommonDifferences = true; - outs().indent(4) << formatv("{0} ({1}: {2} bytes, {3}: {4} bytes)\n", - Left.value(), File1.getFilePath(), - LeftSize, File2.getFilePath(), RightSize); - } - } - if (!HasCommonDifferences) - outs().indent(2) << "Common Streams: No differences detected!\n"; - } - if (!HasDifferences) - outs() << "Stream Directory: No differences detected!\n"; } + if (!OnlyQ.empty()) { + HasDifferences = true; + outs().indent(2) << formatv("{0} Streams(s) only in ({1})\n", OnlyQ.size(), + File2.getFilePath()); + for (auto &Item : OnlyQ) { + outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(), + Item.value()); + } + } + if (!Common.empty()) { + outs().indent(2) << formatv("Found {0} common streams. Searching for " + "intra-stream differences.\n", + Common.size()); + bool HasCommonDifferences = false; + for (const auto &Left : Common) { + // Left was copied from the first range so its index refers to a stream + // index in the first file. Find the corresponding stream index in the + // second file. + auto Range = + std::equal_range(QI.begin(), QI.end(), Left, + [](const value_type &L, const value_type &R) { + return L.value() < R.value(); + }); + const auto &Right = *Range.first; + assert(Left.value() == Right.value()); + uint32_t LeftSize = File1.getStreamByteSize(Left.index()); + uint32_t RightSize = File2.getStreamByteSize(Right.index()); + if (LeftSize != RightSize) { + HasDifferences = true; + HasCommonDifferences = true; + outs().indent(4) << formatv("{0} ({1}: {2} bytes, {3}: {4} bytes)\n", + Left.value(), File1.getFilePath(), LeftSize, + File2.getFilePath(), RightSize); + } + } + if (!HasCommonDifferences) + outs().indent(2) << "Common Streams: No differences detected!\n"; + } + if (!HasDifferences) + outs() << "Stream Directory: No differences detected!\n"; + return Error::success(); } @@ -384,77 +331,39 @@ Error DiffStyle::diffStringTable() { auto IdList1 = ST1.name_ids(); auto IdList2 = ST2.name_ids(); - if (opts::diff::Pedantic) { - // In pedantic mode, we compare index by index (i.e. the strings are in the - // same order - // in both tables. - uint32_t Max = std::max(IdList1.size(), IdList2.size()); - for (uint32_t I = 0; I < Max; ++I) { - Optional Id1, Id2; - StringRef S1, S2; - if (I < IdList1.size()) { - Id1 = IdList1[I]; - if (auto Result = ST1.getStringForID(*Id1)) - S1 = *Result; - else - return Result.takeError(); - } - if (I < IdList2.size()) { - Id2 = IdList2[I]; - if (auto Result = ST2.getStringForID(*Id2)) - S2 = *Result; - else - return Result.takeError(); - } - if (Id1 == Id2 && S1 == S2) - continue; + std::vector Strings1, Strings2; + Strings1.reserve(IdList1.size()); + Strings2.reserve(IdList2.size()); + for (auto ID : IdList1) { + auto S = ST1.getStringForID(ID); + if (!S) + return S.takeError(); + Strings1.push_back(*S); + } + for (auto ID : IdList2) { + auto S = ST2.getStringForID(ID); + if (!S) + return S.takeError(); + Strings2.push_back(*S); + } - std::string OutId1 = - Id1 ? formatv("{0}", *Id1).str() : "(index not present)"; - std::string OutId2 = - Id2 ? formatv("{0}", *Id2).str() : "(index not present)"; - outs() << formatv(" String {0}\n", I); - outs() << formatv(" {0}: Hash - {1}, Value - {2}\n", - File1.getFilePath(), OutId1, S1); - outs() << formatv(" {0}: Hash - {1}, Value - {2}\n", - File2.getFilePath(), OutId2, S2); - HasDiff = true; - } - } else { - std::vector Strings1, Strings2; - Strings1.reserve(IdList1.size()); - Strings2.reserve(IdList2.size()); - for (auto ID : IdList1) { - auto S = ST1.getStringForID(ID); - if (!S) - return S.takeError(); - Strings1.push_back(*S); - } - for (auto ID : IdList2) { - auto S = ST2.getStringForID(ID); - if (!S) - return S.takeError(); - Strings2.push_back(*S); - } + SmallVector OnlyP; + SmallVector OnlyQ; + auto End1 = std::remove(Strings1.begin(), Strings1.end(), ""); + auto End2 = std::remove(Strings2.begin(), Strings2.end(), ""); + uint32_t Empty1 = std::distance(End1, Strings1.end()); + uint32_t Empty2 = std::distance(End2, Strings2.end()); + Strings1.erase(End1, Strings1.end()); + Strings2.erase(End2, Strings2.end()); + set_differences(Strings1, Strings2, &OnlyP, &OnlyQ); + printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "String"); - SmallVector OnlyP; - SmallVector OnlyQ; - auto End1 = std::remove(Strings1.begin(), Strings1.end(), ""); - auto End2 = std::remove(Strings2.begin(), Strings2.end(), ""); - uint32_t Empty1 = std::distance(End1, Strings1.end()); - uint32_t Empty2 = std::distance(End2, Strings2.end()); - Strings1.erase(End1, Strings1.end()); - Strings2.erase(End2, Strings2.end()); - set_differences(Strings1, Strings2, &OnlyP, &OnlyQ); - printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "String"); - - if (Empty1 != Empty2) { - PDBFile &MoreF = (Empty1 > Empty2) ? File1 : File2; - PDBFile &LessF = (Empty1 < Empty2) ? File1 : File2; - uint32_t Difference = AbsoluteDifference(Empty1, Empty2); - outs() << formatv(" {0} had {1} more empty strings than {2}\n", - MoreF.getFilePath(), Difference, LessF.getFilePath()); - } + if (Empty1 != Empty2) { + PDBFile &MoreF = (Empty1 > Empty2) ? File1 : File2; + PDBFile &LessF = (Empty1 < Empty2) ? File1 : File2; + uint32_t Difference = AbsoluteDifference(Empty1, Empty2); + outs() << formatv(" {0} had {1} more empty strings than {2}\n", + MoreF.getFilePath(), Difference, LessF.getFilePath()); } if (!HasDiff) outs() << "String Table: No differences detected!\n"; diff --git a/contrib/llvm/tools/llvm-pdbutil/RawOutputStyle.cpp b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp similarity index 84% rename from contrib/llvm/tools/llvm-pdbutil/RawOutputStyle.cpp rename to contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp index b204a89ec317..f76635f9e511 100644 --- a/contrib/llvm/tools/llvm-pdbutil/RawOutputStyle.cpp +++ b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.cpp @@ -1,4 +1,4 @@ -//===- RawOutputStyle.cpp ------------------------------------ *- C++ --*-===// +//===- DumpOutputStyle.cpp ------------------------------------ *- C++ --*-===// // // The LLVM Compiler Infrastructure // @@ -7,9 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "RawOutputStyle.h" +#include "DumpOutputStyle.h" -#include "CompactTypeDumpVisitor.h" #include "FormatUtil.h" #include "MinimalSymbolDumper.h" #include "MinimalTypeDumper.h" @@ -65,96 +64,84 @@ using namespace llvm::codeview; using namespace llvm::msf; using namespace llvm::pdb; -RawOutputStyle::RawOutputStyle(PDBFile &File) +DumpOutputStyle::DumpOutputStyle(PDBFile &File) : File(File), P(2, false, outs()) {} -Error RawOutputStyle::dump() { - if (opts::raw::DumpSummary) { +Error DumpOutputStyle::dump() { + if (opts::dump::DumpSummary) { if (auto EC = dumpFileSummary()) return EC; P.NewLine(); } - if (opts::raw::DumpStreams) { + if (opts::dump::DumpStreams) { if (auto EC = dumpStreamSummary()) return EC; P.NewLine(); } - if (opts::raw::DumpBlockRange.hasValue()) { - if (auto EC = dumpBlockRanges()) - return EC; - P.NewLine(); - } - - if (!opts::raw::DumpStreamData.empty()) { - if (auto EC = dumpStreamBytes()) - return EC; - P.NewLine(); - } - - if (opts::raw::DumpStringTable) { + if (opts::dump::DumpStringTable) { if (auto EC = dumpStringTable()) return EC; P.NewLine(); } - if (opts::raw::DumpModules) { + if (opts::dump::DumpModules) { if (auto EC = dumpModules()) return EC; } - if (opts::raw::DumpModuleFiles) { + if (opts::dump::DumpModuleFiles) { if (auto EC = dumpModuleFiles()) return EC; } - if (opts::raw::DumpLines) { + if (opts::dump::DumpLines) { if (auto EC = dumpLines()) return EC; } - if (opts::raw::DumpInlineeLines) { + if (opts::dump::DumpInlineeLines) { if (auto EC = dumpInlineeLines()) return EC; } - if (opts::raw::DumpXmi) { + if (opts::dump::DumpXmi) { if (auto EC = dumpXmi()) return EC; } - if (opts::raw::DumpXme) { + if (opts::dump::DumpXme) { if (auto EC = dumpXme()) return EC; } - if (opts::raw::DumpTypes || opts::raw::DumpTypeExtras) { + if (opts::dump::DumpTypes || opts::dump::DumpTypeExtras) { if (auto EC = dumpTpiStream(StreamTPI)) return EC; } - if (opts::raw::DumpIds || opts::raw::DumpIdExtras) { + if (opts::dump::DumpIds || opts::dump::DumpIdExtras) { if (auto EC = dumpTpiStream(StreamIPI)) return EC; } - if (opts::raw::DumpPublics) { + if (opts::dump::DumpPublics) { if (auto EC = dumpPublics()) return EC; } - if (opts::raw::DumpSymbols) { + if (opts::dump::DumpSymbols) { if (auto EC = dumpModuleSyms()) return EC; } - if (opts::raw::DumpSectionContribs) { + if (opts::dump::DumpSectionContribs) { if (auto EC = dumpSectionContribs()) return EC; } - if (opts::raw::DumpSectionMap) { + if (opts::dump::DumpSectionMap) { if (auto EC = dumpSectionMap()) return EC; } @@ -168,7 +155,7 @@ static void printHeader(LinePrinter &P, const Twine &S) { P.formatLine("{0}", fmt_repeat('=', 60)); } -Error RawOutputStyle::dumpFileSummary() { +Error DumpOutputStyle::dumpFileSummary() { printHeader(P, "Summary"); ExitOnError Err("Invalid PDB Format"); @@ -198,7 +185,7 @@ Error RawOutputStyle::dumpFileSummary() { return Error::success(); } -Error RawOutputStyle::dumpStreamSummary() { +Error DumpOutputStyle::dumpStreamSummary() { printHeader(P, "Streams"); if (StreamPurposes.empty()) @@ -212,105 +199,15 @@ Error RawOutputStyle::dumpStreamSummary() { "Stream {0}: [{1}] ({2} bytes)", fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)), StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx)); - } - - return Error::success(); -} - -Error RawOutputStyle::dumpBlockRanges() { - printHeader(P, "MSF Blocks"); - - auto &R = *opts::raw::DumpBlockRange; - uint32_t Max = R.Max.getValueOr(R.Min); - - AutoIndent Indent(P); - if (Max < R.Min) - return make_error( - "Invalid block range specified. Max < Min", - std::make_error_code(std::errc::bad_address)); - if (Max >= File.getBlockCount()) - return make_error( - "Invalid block range specified. Requested block out of bounds", - std::make_error_code(std::errc::bad_address)); - - for (uint32_t I = R.Min; I <= Max; ++I) { - auto ExpectedData = File.getBlockData(I, File.getBlockSize()); - if (!ExpectedData) - return ExpectedData.takeError(); - std::string Label = formatv("Block {0}", I).str(); - P.formatBinary(Label, *ExpectedData, 0); - } - - return Error::success(); -} - -static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset, - uint32_t &Size) { - if (Str.consumeInteger(0, SI)) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - if (Str.consume_front(":")) { - if (Str.consumeInteger(0, Offset)) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - } - if (Str.consume_front("@")) { - if (Str.consumeInteger(0, Size)) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - } - if (!Str.empty()) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - return Error::success(); -} - -Error RawOutputStyle::dumpStreamBytes() { - if (StreamPurposes.empty()) - discoverStreamPurposes(File, StreamPurposes); - - printHeader(P, "Stream Data"); - ExitOnError Err("Unexpected error reading stream data"); - - for (auto &Str : opts::raw::DumpStreamData) { - uint32_t SI = 0; - uint32_t Begin = 0; - uint32_t Size = 0; - uint32_t End = 0; - - if (auto EC = parseStreamSpec(Str, SI, Begin, Size)) - return EC; - - AutoIndent Indent(P); - if (SI >= File.getNumStreams()) { - P.formatLine("Stream {0}: Not present", SI); - continue; + if (opts::dump::DumpStreamBlocks) { + auto Blocks = File.getStreamBlockList(StreamIdx); + std::vector BV(Blocks.begin(), Blocks.end()); + P.formatLine(" {0} Blocks: [{1}]", + fmt_repeat(' ', NumDigits(StreamCount)), + make_range(BV.begin(), BV.end())); } - - auto S = MappedBlockStream::createIndexedStream( - File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator()); - if (!S) { - P.NewLine(); - P.formatLine("Stream {0}: Not present", SI); - continue; - } - - if (Size == 0) - End = S->getLength(); - else - End = std::min(Begin + Size, S->getLength()); - - P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(), - StreamPurposes[SI]); - AutoIndent Indent2(P); - - BinaryStreamReader R(*S); - ArrayRef StreamData; - Err(R.readBytes(StreamData, S->getLength())); - Size = End - Begin; - StreamData = StreamData.slice(Begin, Size); - P.formatBinary("Data", StreamData, Begin); } + return Error::success(); } @@ -494,7 +391,7 @@ static void iterateModuleSubsections( }); } -Error RawOutputStyle::dumpModules() { +Error DumpOutputStyle::dumpModules() { printHeader(P, "Modules"); AutoIndent Indent(P); @@ -522,7 +419,7 @@ Error RawOutputStyle::dumpModules() { return Error::success(); } -Error RawOutputStyle::dumpModuleFiles() { +Error DumpOutputStyle::dumpModuleFiles() { printHeader(P, "Files"); ExitOnError Err("Unexpected error processing modules"); @@ -574,7 +471,7 @@ static void typesetLinesAndColumns(PDBFile &File, LinePrinter &P, } } -Error RawOutputStyle::dumpLines() { +Error DumpOutputStyle::dumpLines() { printHeader(P, "Lines"); uint32_t LastModi = UINT32_MAX; @@ -610,7 +507,7 @@ Error RawOutputStyle::dumpLines() { return Error::success(); } -Error RawOutputStyle::dumpInlineeLines() { +Error DumpOutputStyle::dumpInlineeLines() { printHeader(P, "Inlinee Lines"); iterateModuleSubsections( @@ -629,7 +526,7 @@ Error RawOutputStyle::dumpInlineeLines() { return Error::success(); } -Error RawOutputStyle::dumpXmi() { +Error DumpOutputStyle::dumpXmi() { printHeader(P, "Cross Module Imports"); iterateModuleSubsections( File, P, 2, @@ -664,7 +561,7 @@ Error RawOutputStyle::dumpXmi() { return Error::success(); } -Error RawOutputStyle::dumpXme() { +Error DumpOutputStyle::dumpXme() { printHeader(P, "Cross Module Exports"); iterateModuleSubsections( @@ -681,7 +578,7 @@ Error RawOutputStyle::dumpXme() { return Error::success(); } -Error RawOutputStyle::dumpStringTable() { +Error DumpOutputStyle::dumpStringTable() { printHeader(P, "String Table"); AutoIndent Indent(P); @@ -723,25 +620,30 @@ Error RawOutputStyle::dumpStringTable() { return Error::success(); } -Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) { +Error DumpOutputStyle::dumpTpiStream(uint32_t StreamIdx) { assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); bool Present = false; bool DumpTypes = false; bool DumpBytes = false; bool DumpExtras = false; + std::vector Indices; if (StreamIdx == StreamTPI) { printHeader(P, "Types (TPI Stream)"); Present = File.hasPDBTpiStream(); - DumpTypes = opts::raw::DumpTypes; - DumpBytes = opts::raw::DumpTypeData; - DumpExtras = opts::raw::DumpTypeExtras; + DumpTypes = opts::dump::DumpTypes; + DumpBytes = opts::dump::DumpTypeData; + DumpExtras = opts::dump::DumpTypeExtras; + Indices.assign(opts::dump::DumpTypeIndex.begin(), + opts::dump::DumpTypeIndex.end()); } else if (StreamIdx == StreamIPI) { printHeader(P, "Types (IPI Stream)"); Present = File.hasPDBIpiStream(); - DumpTypes = opts::raw::DumpIds; - DumpBytes = opts::raw::DumpIdData; - DumpExtras = opts::raw::DumpIdExtras; + DumpTypes = opts::dump::DumpIds; + DumpBytes = opts::dump::DumpIdData; + DumpExtras = opts::dump::DumpIdExtras; + Indices.assign(opts::dump::DumpIdIndex.begin(), + opts::dump::DumpIdIndex.end()); } AutoIndent Indent(P); @@ -755,7 +657,7 @@ Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) { auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream()); - auto &Types = Err(initializeTypeDatabase(StreamIdx)); + auto &Types = Err(initializeTypes(StreamIdx)); if (DumpTypes) { P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords()); @@ -765,10 +667,19 @@ Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) { MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, DumpExtras, Types, Stream.getHashValues()); - Optional I = Types.getFirst(); - if (auto EC = codeview::visitTypeStream(Types, V)) { - P.formatLine("An error occurred dumping type records: {0}", - toString(std::move(EC))); + if (Indices.empty()) { + if (auto EC = codeview::visitTypeStream(Types, V)) { + P.formatLine("An error occurred dumping type records: {0}", + toString(std::move(EC))); + } + } else { + for (const auto &I : Indices) { + TypeIndex TI(I); + CVType Type = Types.getType(TI); + if (auto EC = codeview::visitTypeRecord(Type, TI, V)) + P.formatLine("An error occurred dumping type record {0}: {1}", TI, + toString(std::move(EC))); + } } } @@ -801,7 +712,7 @@ Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) { } Expected -RawOutputStyle::initializeTypeDatabase(uint32_t SN) { +DumpOutputStyle::initializeTypes(uint32_t SN) { auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes; auto Tpi = (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream(); @@ -819,7 +730,7 @@ RawOutputStyle::initializeTypeDatabase(uint32_t SN) { return *TypeCollection; } -Error RawOutputStyle::dumpModuleSyms() { +Error DumpOutputStyle::dumpModuleSyms() { printHeader(P, "Symbols"); AutoIndent Indent(P); @@ -832,7 +743,7 @@ Error RawOutputStyle::dumpModuleSyms() { auto &Stream = Err(File.getPDBDbiStream()); - auto &Types = Err(initializeTypeDatabase(StreamTPI)); + auto &Types = Err(initializeTypes(StreamTPI)); const DbiModuleList &Modules = Stream.modules(); uint32_t Count = Modules.getModuleCount(); @@ -859,7 +770,7 @@ Error RawOutputStyle::dumpModuleSyms() { SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); - MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); @@ -873,7 +784,7 @@ Error RawOutputStyle::dumpModuleSyms() { return Error::success(); } -Error RawOutputStyle::dumpPublics() { +Error DumpOutputStyle::dumpPublics() { printHeader(P, "Public Symbols"); AutoIndent Indent(P); @@ -884,11 +795,11 @@ Error RawOutputStyle::dumpPublics() { ExitOnError Err("Error dumping publics stream"); - auto &Types = Err(initializeTypeDatabase(StreamTPI)); + auto &Types = Err(initializeTypes(StreamTPI)); auto &Publics = Err(File.getPDBPublicsStream()); SymbolVisitorCallbackPipeline Pipeline; SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); - MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types); + MinimalSymbolDumper Dumper(P, opts::dump::DumpSymRecordBytes, Types); Pipeline.addCallbackToPipeline(Deserializer); Pipeline.addCallbackToPipeline(Dumper); @@ -988,7 +899,7 @@ static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel, return typesetItemList(Opts, IndentLevel, 4, " | "); } -Error RawOutputStyle::dumpSectionContribs() { +Error DumpOutputStyle::dumpSectionContribs() { printHeader(P, "Section Contributions"); ExitOnError Err("Error dumping publics stream"); @@ -1034,7 +945,7 @@ Error RawOutputStyle::dumpSectionContribs() { return Error::success(); } -Error RawOutputStyle::dumpSectionMap() { +Error DumpOutputStyle::dumpSectionMap() { printHeader(P, "Section Map"); ExitOnError Err("Error dumping section map"); diff --git a/contrib/llvm/tools/llvm-pdbutil/RawOutputStyle.h b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h similarity index 75% rename from contrib/llvm/tools/llvm-pdbutil/RawOutputStyle.h rename to contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h index 803f588961bb..296a6c14942e 100644 --- a/contrib/llvm/tools/llvm-pdbutil/RawOutputStyle.h +++ b/contrib/llvm/tools/llvm-pdbutil/DumpOutputStyle.h @@ -1,4 +1,4 @@ -//===- RawOutputStyle.h -------------------------------------- *- C++ --*-===// +//===- DumpOutputStyle.h -------------------------------------- *- C++ --*-===// // // The LLVM Compiler Infrastructure // @@ -7,15 +7,14 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H -#define LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H +#ifndef LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_DUMPOUTPUTSTYLE_H #include "LinePrinter.h" #include "OutputStyle.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include @@ -27,15 +26,14 @@ class LazyRandomTypeCollection; } namespace pdb { -class RawOutputStyle : public OutputStyle { +class DumpOutputStyle : public OutputStyle { public: - RawOutputStyle(PDBFile &File); + DumpOutputStyle(PDBFile &File); Error dump() override; private: - Expected - initializeTypeDatabase(uint32_t SN); + Expected initializeTypes(uint32_t SN); Error dumpFileSummary(); Error dumpStreamSummary(); diff --git a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp index 718d3394e211..6e4d95af944a 100644 --- a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp +++ b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.cpp @@ -12,13 +12,21 @@ #include "llvm-pdbutil.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MSFStreamLayout.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Regex.h" #include using namespace llvm; +using namespace llvm::msf; using namespace llvm::pdb; namespace { @@ -106,6 +114,138 @@ void LinePrinter::formatBinary(StringRef Label, ArrayRef Data, OS << ")"; } +void LinePrinter::formatBinary(StringRef Label, ArrayRef Data, + uint64_t Base, uint32_t StartOffset) { + NewLine(); + OS << Label << " ("; + if (!Data.empty()) { + OS << "\n"; + Base += StartOffset; + OS << format_bytes_with_ascii(Data, Base, 32, 4, + CurrentIndent + IndentSpaces, true); + NewLine(); + } + OS << ")"; +} + +namespace { +struct Run { + Run() = default; + explicit Run(uint32_t Block) : Block(Block) {} + uint32_t Block = 0; + uint32_t ByteLen = 0; +}; +} // namespace + +static std::vector computeBlockRuns(uint32_t BlockSize, + const msf::MSFStreamLayout &Layout) { + std::vector Runs; + if (Layout.Length == 0) + return Runs; + + ArrayRef Blocks = Layout.Blocks; + assert(!Blocks.empty()); + uint32_t StreamBytesRemaining = Layout.Length; + uint32_t CurrentBlock = Blocks[0]; + Runs.emplace_back(CurrentBlock); + while (!Blocks.empty()) { + Run *CurrentRun = &Runs.back(); + uint32_t NextBlock = Blocks.front(); + if (NextBlock < CurrentBlock || (NextBlock - CurrentBlock > 1)) { + Runs.emplace_back(NextBlock); + CurrentRun = &Runs.back(); + } + uint32_t Used = std::min(BlockSize, StreamBytesRemaining); + CurrentRun->ByteLen += Used; + StreamBytesRemaining -= Used; + CurrentBlock = NextBlock; + Blocks = Blocks.drop_front(); + } + return Runs; +} + +static std::pair findRun(uint32_t Offset, ArrayRef Runs) { + for (const auto &R : Runs) { + if (Offset < R.ByteLen) + return std::make_pair(R, Offset); + Offset -= R.ByteLen; + } + llvm_unreachable("Invalid offset!"); +} + +void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File, + uint32_t StreamIdx, + StringRef StreamPurpose, uint32_t Offset, + uint32_t Size) { + if (StreamIdx >= File.getNumStreams()) { + formatLine("Stream {0}: Not present", StreamIdx); + return; + } + if (Size + Offset > File.getStreamByteSize(StreamIdx)) { + formatLine( + "Stream {0}: Invalid offset and size, range out of stream bounds", + StreamIdx); + return; + } + + auto S = MappedBlockStream::createIndexedStream( + File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator()); + if (!S) { + NewLine(); + formatLine("Stream {0}: Not present", StreamIdx); + return; + } + + uint32_t End = + (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength()); + Size = End - Offset; + + formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx, + StreamPurpose, Size, S->getLength()); + AutoIndent Indent(*this); + BinaryStreamRef Slice(*S); + BinarySubstreamRef Substream; + Substream.Offset = Offset; + Substream.StreamData = Slice.drop_front(Offset).keep_front(Size); + + auto Layout = File.getStreamLayout(StreamIdx); + formatMsfStreamData(Label, File, Layout, Substream); +} + +void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File, + const msf::MSFStreamLayout &Stream, + BinarySubstreamRef Substream) { + BinaryStreamReader Reader(Substream.StreamData); + + auto Runs = computeBlockRuns(File.getBlockSize(), Stream); + + NewLine(); + OS << Label << " ("; + while (Reader.bytesRemaining() > 0) { + OS << "\n"; + + Run FoundRun; + uint32_t RunOffset; + std::tie(FoundRun, RunOffset) = findRun(Substream.Offset, Runs); + assert(FoundRun.ByteLen >= RunOffset); + uint32_t Len = FoundRun.ByteLen - RunOffset; + Len = std::min(Len, Reader.bytesRemaining()); + uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset; + ArrayRef Data; + consumeError(Reader.readBytes(Data, Len)); + OS << format_bytes_with_ascii(Data, Base, 32, 4, + CurrentIndent + IndentSpaces, true); + if (Reader.bytesRemaining() > 0) { + NewLine(); + OS << formatv(" {0}", + fmt_align("", AlignStyle::Center, 114, '-')); + } + Substream.Offset += Len; + } + NewLine(); + OS << ")"; +} + bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) { if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters)) return true; diff --git a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h index f4fd22bcb6f4..68ce321a27ec 100644 --- a/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h +++ b/contrib/llvm/tools/llvm-pdbutil/LinePrinter.h @@ -13,6 +13,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Regex.h" #include "llvm/Support/raw_ostream.h" @@ -20,9 +21,14 @@ #include namespace llvm { +class BinaryStreamReader; +namespace msf { +class MSFStreamLayout; +} // namespace msf namespace pdb { class ClassLayout; +class PDBFile; class LinePrinter { friend class WithColor; @@ -45,6 +51,15 @@ class LinePrinter { void formatBinary(StringRef Label, ArrayRef Data, uint32_t StartOffset); + void formatBinary(StringRef Label, ArrayRef Data, uint64_t BaseAddr, + uint32_t StartOffset); + + void formatMsfStreamData(StringRef Label, PDBFile &File, uint32_t StreamIdx, + StringRef StreamPurpose, uint32_t Offset, + uint32_t Size); + void formatMsfStreamData(StringRef Label, PDBFile &File, + const msf::MSFStreamLayout &Stream, + BinarySubstreamRef Substream); bool hasColor() const { return UseColor; } raw_ostream &getStream() { return OS; } diff --git a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp index 8b36de0b7157..7f5412d59885 100644 --- a/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp +++ b/contrib/llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp @@ -146,6 +146,19 @@ static std::string formatFrameProcedureOptions(uint32_t IndentLevel, return typesetItemList(Opts, 4, IndentLevel, " | "); } +static std::string formatPublicSymFlags(uint32_t IndentLevel, + PublicSymFlags Flags) { + std::vector Opts; + if (Flags == PublicSymFlags::None) + return "none"; + + PUSH_FLAG(PublicSymFlags, Code, Flags, "code"); + PUSH_FLAG(PublicSymFlags, Function, Flags, "function"); + PUSH_FLAG(PublicSymFlags, Managed, Flags, "managed"); + PUSH_FLAG(PublicSymFlags, MSIL, Flags, "msil"); + return typesetItemList(Opts, 4, IndentLevel, " | "); +} + static std::string formatProcSymFlags(uint32_t IndentLevel, ProcSymFlags Flags) { std::vector Opts; @@ -659,7 +672,8 @@ Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) { P.format(" `{0}`", Public.Name); AutoIndent Indent(P); - P.formatLine("type = {0}, addr = {1}", typeIndex(Public.Index), + P.formatLine("flags = {0}, addr = {1}", + formatPublicSymFlags(P.getIndentLevel() + 9, Public.Flags), formatSegmentOffset(Public.Segment, Public.Offset)); return Error::success(); } diff --git a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp index 9088783876e0..4a176fb13590 100644 --- a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -14,7 +14,9 @@ #include "llvm-pdbutil.h" #include "Analyze.h" +#include "BytesOutputStyle.h" #include "Diff.h" +#include "DumpOutputStyle.h" #include "LinePrinter.h" #include "OutputStyle.h" #include "PrettyCompilandDumper.h" @@ -22,7 +24,6 @@ #include "PrettyFunctionDumper.h" #include "PrettyTypeDumper.h" #include "PrettyVariableDumper.h" -#include "RawOutputStyle.h" #include "YAMLOutputStyle.h" #include "llvm/ADT/ArrayRef.h" @@ -86,7 +87,9 @@ using namespace llvm::pdb; namespace opts { -cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file"); +cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info"); +cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file"); + cl::SubCommand PrettySubcommand("pretty", "Dump semantic information about types and symbols"); @@ -111,6 +114,31 @@ cl::OptionCategory TypeCategory("Symbol Type Options"); cl::OptionCategory FilterCategory("Filtering and Sorting Options"); cl::OptionCategory OtherOptions("Other Options"); +cl::ValuesClass ChunkValues = cl::values( + clEnumValN(ModuleSubsection::CrossScopeExports, "cme", + "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), + clEnumValN(ModuleSubsection::CrossScopeImports, "cmi", + "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), + clEnumValN(ModuleSubsection::FileChecksums, "fc", + "File checksums (DEBUG_S_CHECKSUMS subsection)"), + clEnumValN(ModuleSubsection::InlineeLines, "ilines", + "Inlinee lines (DEBUG_S_INLINEELINES subsection)"), + clEnumValN(ModuleSubsection::Lines, "lines", + "Lines (DEBUG_S_LINES subsection)"), + clEnumValN(ModuleSubsection::StringTable, "strings", + "String Table (DEBUG_S_STRINGTABLE subsection) (not " + "typically present in PDB file)"), + clEnumValN(ModuleSubsection::FrameData, "frames", + "Frame Data (DEBUG_S_FRAMEDATA subsection)"), + clEnumValN(ModuleSubsection::Symbols, "symbols", + "Symbols (DEBUG_S_SYMBOLS subsection) (not typically " + "present in PDB file)"), + clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas", + "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"), + clEnumValN(ModuleSubsection::Unknown, "unknown", + "Any subsection not covered by another option"), + clEnumValN(ModuleSubsection::All, "all", "All known subsections")); + namespace pretty { cl::list InputFilenames(cl::Positional, cl::desc(""), @@ -256,11 +284,6 @@ cl::opt NoEnumDefs("no-enum-definitions", } namespace diff { -cl::opt Pedantic("pedantic", - cl::desc("Finds all differences (even structural ones " - "that produce otherwise identical PDBs)"), - cl::sub(DiffSubcommand)); - cl::list InputFilenames(cl::Positional, cl::desc(" "), cl::OneOrMore, cl::sub(DiffSubcommand)); @@ -268,7 +291,83 @@ cl::list InputFilenames(cl::Positional, cl::OptionCategory FileOptions("Module & File Options"); -namespace raw { +namespace bytes { +cl::OptionCategory MsfBytes("MSF File Options"); +cl::OptionCategory DbiBytes("Dbi Stream Options"); +cl::OptionCategory PdbBytes("PDB Stream Options"); +cl::OptionCategory Types("Type Options"); +cl::OptionCategory ModuleCategory("Module Options"); + +llvm::Optional DumpBlockRange; +llvm::Optional DumpByteRange; + +cl::opt DumpBlockRangeOpt( + "block-range", cl::value_desc("start[-end]"), + cl::desc("Dump binary data from specified range of blocks."), + cl::sub(BytesSubcommand), cl::cat(MsfBytes)); + +cl::opt + DumpByteRangeOpt("byte-range", cl::value_desc("start[-end]"), + cl::desc("Dump binary data from specified range of bytes"), + cl::sub(BytesSubcommand), cl::cat(MsfBytes)); + +cl::list + DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, + cl::desc("Dump binary data from specified streams. Format " + "is SN[:Start][@Size]"), + cl::sub(BytesSubcommand), cl::cat(MsfBytes)); + +cl::opt NameMap("name-map", cl::desc("Dump bytes of PDB Name Map"), + cl::sub(BytesSubcommand), cl::cat(PdbBytes)); + +cl::opt SectionContributions("sc", cl::desc("Dump section contributions"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt SectionMap("sm", cl::desc("Dump section map"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt ModuleInfos("modi", cl::desc("Dump module info"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt FileInfo("files", cl::desc("Dump source file info"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt TypeServerMap("type-server", cl::desc("Dump type server map"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); +cl::opt ECData("ec", cl::desc("Dump edit and continue map"), + cl::sub(BytesSubcommand), cl::cat(DbiBytes)); + +cl::list + TypeIndex("type", + cl::desc("Dump the type record with the given type index"), + cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand), + cl::cat(TypeCategory)); +cl::list + IdIndex("id", cl::desc("Dump the id record with the given type index"), + cl::ZeroOrMore, cl::CommaSeparated, cl::sub(BytesSubcommand), + cl::cat(TypeCategory)); + +cl::opt ModuleIndex( + "mod", + cl::desc( + "Limit options in the Modules category to the specified module index"), + cl::Optional, cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::opt ModuleSyms("syms", cl::desc("Dump symbol record substream"), + cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::opt ModuleC11("c11-chunks", cl::Hidden, + cl::desc("Dump C11 CodeView debug chunks"), + cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::opt ModuleC13("chunks", + cl::desc("Dump C13 CodeView debug chunk subsection"), + cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::opt SplitChunks( + "split-chunks", + cl::desc( + "When dumping debug chunks, show a different section for each chunk"), + cl::sub(BytesSubcommand), cl::cat(ModuleCategory)); +cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::OneOrMore, cl::sub(BytesSubcommand)); + +} // namespace bytes + +namespace dump { cl::OptionCategory MsfOptions("MSF Container Options"); cl::OptionCategory TypeOptions("Type Record Options"); @@ -277,100 +376,103 @@ cl::OptionCategory MiscOptions("Miscellaneous Options"); // MSF OPTIONS cl::opt DumpSummary("summary", cl::desc("dump file summary"), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); cl::opt DumpStreams("streams", cl::desc("dump summary of the PDB streams"), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); -cl::opt - DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"), - cl::desc("Dump binary data from specified range."), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); -llvm::Optional DumpBlockRange; - -cl::list - DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, - cl::desc("Dump binary data from specified streams. Format " - "is SN[:Start][@Size]"), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); +cl::opt DumpStreamBlocks( + "stream-blocks", + cl::desc("Add block information to the output of -streams"), + cl::cat(MsfOptions), cl::sub(DumpSubcommand)); // TYPE OPTIONS cl::opt DumpTypes("types", cl::desc("dump CodeView type records from TPI stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); cl::opt DumpTypeData( "type-data", cl::desc("dump CodeView type record raw bytes from TPI stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); cl::opt DumpTypeExtras("type-extras", cl::desc("dump type hashes and index offsets"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); + +cl::list DumpTypeIndex( + "type-index", cl::ZeroOrMore, + cl::desc("only dump types with the specified hexadecimal type index"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); cl::opt DumpIds("ids", cl::desc("dump CodeView type records from IPI stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); cl::opt DumpIdData("id-data", cl::desc("dump CodeView type record raw bytes from IPI stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); cl::opt DumpIdExtras("id-extras", cl::desc("dump id hashes and index offsets"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); +cl::list DumpIdIndex( + "id-index", cl::ZeroOrMore, + cl::desc("only dump ids with the specified hexadecimal type index"), + cl::cat(TypeOptions), cl::sub(DumpSubcommand)); // SYMBOL OPTIONS cl::opt DumpPublics("publics", cl::desc("dump Publics stream data"), - cl::cat(SymbolOptions), cl::sub(RawSubcommand)); + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); cl::opt DumpSymbols("symbols", cl::desc("dump module symbols"), - cl::cat(SymbolOptions), cl::sub(RawSubcommand)); + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); cl::opt DumpSymRecordBytes("sym-data", cl::desc("dump CodeView symbol record raw bytes"), - cl::cat(SymbolOptions), cl::sub(RawSubcommand)); + cl::cat(SymbolOptions), cl::sub(DumpSubcommand)); // MODULE & FILE OPTIONS cl::opt DumpModules("modules", cl::desc("dump compiland information"), - cl::cat(FileOptions), cl::sub(RawSubcommand)); + cl::cat(FileOptions), cl::sub(DumpSubcommand)); cl::opt DumpModuleFiles( "files", cl::desc("Dump the source files that contribute to each module's."), - cl::cat(FileOptions), cl::sub(RawSubcommand)); + cl::cat(FileOptions), cl::sub(DumpSubcommand)); cl::opt DumpLines( "l", cl::desc("dump source file/line information (DEBUG_S_LINES subsection)"), - cl::cat(FileOptions), cl::sub(RawSubcommand)); + cl::cat(FileOptions), cl::sub(DumpSubcommand)); cl::opt DumpInlineeLines( "il", cl::desc("dump inlinee line information (DEBUG_S_INLINEELINES subsection)"), - cl::cat(FileOptions), cl::sub(RawSubcommand)); + cl::cat(FileOptions), cl::sub(DumpSubcommand)); cl::opt DumpXmi( "xmi", cl::desc( "dump cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), - cl::cat(FileOptions), cl::sub(RawSubcommand)); + cl::cat(FileOptions), cl::sub(DumpSubcommand)); cl::opt DumpXme( "xme", cl::desc( "dump cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), - cl::cat(FileOptions), cl::sub(RawSubcommand)); + cl::cat(FileOptions), cl::sub(DumpSubcommand)); // MISCELLANEOUS OPTIONS cl::opt DumpStringTable("string-table", cl::desc("dump PDB String Table"), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); cl::opt DumpSectionContribs("section-contribs", cl::desc("dump section contributions"), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); + cl::cat(MiscOptions), + cl::sub(DumpSubcommand)); cl::opt DumpSectionMap("section-map", cl::desc("dump section map"), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); cl::opt RawAll("all", cl::desc("Implies most other options."), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); + cl::cat(MiscOptions), cl::sub(DumpSubcommand)); cl::list InputFilenames(cl::Positional, cl::desc(""), - cl::OneOrMore, cl::sub(RawSubcommand)); + cl::OneOrMore, cl::sub(DumpSubcommand)); } namespace yaml2pdb { @@ -429,33 +531,7 @@ cl::opt DumpModuleFiles("module-files", cl::desc("dump file information"), cl::sub(PdbToYamlSubcommand)); cl::list DumpModuleSubsections( "subsections", cl::ZeroOrMore, cl::CommaSeparated, - cl::desc("dump subsections from each module's debug stream"), - cl::values( - clEnumValN( - ModuleSubsection::CrossScopeExports, "cme", - "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), - clEnumValN( - ModuleSubsection::CrossScopeImports, "cmi", - "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), - clEnumValN(ModuleSubsection::FileChecksums, "fc", - "File checksums (DEBUG_S_CHECKSUMS subsection)"), - clEnumValN(ModuleSubsection::InlineeLines, "ilines", - "Inlinee lines (DEBUG_S_INLINEELINES subsection)"), - clEnumValN(ModuleSubsection::Lines, "lines", - "Lines (DEBUG_S_LINES subsection)"), - clEnumValN(ModuleSubsection::StringTable, "strings", - "String Table (DEBUG_S_STRINGTABLE subsection) (not " - "typically present in PDB file)"), - clEnumValN(ModuleSubsection::FrameData, "frames", - "Frame Data (DEBUG_S_FRAMEDATA subsection)"), - clEnumValN(ModuleSubsection::Symbols, "symbols", - "Symbols (DEBUG_S_SYMBOLS subsection) (not typically " - "present in PDB file)"), - clEnumValN(ModuleSubsection::CoffSymbolRVAs, "rvas", - "COFF Symbol RVAs (DEBUG_S_COFF_SYMBOL_RVA subsection)"), - clEnumValN(ModuleSubsection::Unknown, "unknown", - "Any subsection not covered by another option"), - clEnumValN(ModuleSubsection::All, "all", "All known subsections")), + cl::desc("dump subsections from each module's debug stream"), ChunkValues, cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand)); cl::opt DumpModuleSyms("module-syms", cl::desc("dump module symbols"), cl::cat(FileOptions), @@ -616,7 +692,16 @@ static void dumpRaw(StringRef Path) { std::unique_ptr Session; auto &File = loadPDB(Path, Session); - auto O = llvm::make_unique(File); + auto O = llvm::make_unique(File); + + ExitOnErr(O->dump()); +} + +static void dumpBytes(StringRef Path) { + std::unique_ptr Session; + auto &File = loadPDB(Path, Session); + + auto O = llvm::make_unique(File); ExitOnErr(O->dump()); } @@ -877,6 +962,37 @@ static void mergePdbs() { ExitOnErr(Builder.commit(OutFile)); } +static bool parseRange(StringRef Str, + Optional &Parsed) { + if (Str.empty()) + return true; + + llvm::Regex R("^([^-]+)(-([^-]+))?$"); + llvm::SmallVector Matches; + if (!R.match(Str, &Matches)) + return false; + + Parsed.emplace(); + if (!to_integer(Matches[1], Parsed->Min)) + return false; + + if (!Matches[3].empty()) { + Parsed->Max.emplace(); + if (!to_integer(Matches[3], *Parsed->Max)) + return false; + } + return true; +} + +static void simplifyChunkList(llvm::cl::list &Chunks) { + // If this list contains "All" plus some other stuff, remove the other stuff + // and just keep "All" in the list. + if (!llvm::is_contained(Chunks, opts::ModuleSubsection::All)) + return; + Chunks.reset(); + Chunks.push_back(opts::ModuleSubsection::All); +} + int main(int argc_, const char *argv_[]) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(argv_[0]); @@ -892,43 +1008,45 @@ int main(int argc_, const char *argv_[]) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); - if (!opts::raw::DumpBlockRangeOpt.empty()) { - llvm::Regex R("^([0-9]+)(-([0-9]+))?$"); - llvm::SmallVector Matches; - if (!R.match(opts::raw::DumpBlockRangeOpt, &Matches)) { - errs() << "Argument '" << opts::raw::DumpBlockRangeOpt + + if (opts::BytesSubcommand) { + if (!parseRange(opts::bytes::DumpBlockRangeOpt, + opts::bytes::DumpBlockRange)) { + errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt << "' invalid format.\n"; errs().flush(); exit(1); } - opts::raw::DumpBlockRange.emplace(); - Matches[1].getAsInteger(10, opts::raw::DumpBlockRange->Min); - if (!Matches[3].empty()) { - opts::raw::DumpBlockRange->Max.emplace(); - Matches[3].getAsInteger(10, *opts::raw::DumpBlockRange->Max); + if (!parseRange(opts::bytes::DumpByteRangeOpt, + opts::bytes::DumpByteRange)) { + errs() << "Argument '" << opts::bytes::DumpByteRangeOpt + << "' invalid format.\n"; + errs().flush(); + exit(1); } } - if (opts::RawSubcommand) { - if (opts::raw::RawAll) { - opts::raw::DumpLines = true; - opts::raw::DumpInlineeLines = true; - opts::raw::DumpXme = true; - opts::raw::DumpXmi = true; - opts::raw::DumpIds = true; - opts::raw::DumpPublics = true; - opts::raw::DumpSectionContribs = true; - opts::raw::DumpSectionMap = true; - opts::raw::DumpStreams = true; - opts::raw::DumpStringTable = true; - opts::raw::DumpSummary = true; - opts::raw::DumpSymbols = true; - opts::raw::DumpIds = true; - opts::raw::DumpIdExtras = true; - opts::raw::DumpTypes = true; - opts::raw::DumpTypeExtras = true; - opts::raw::DumpModules = true; - opts::raw::DumpModuleFiles = true; + if (opts::DumpSubcommand) { + if (opts::dump::RawAll) { + opts::dump::DumpLines = true; + opts::dump::DumpInlineeLines = true; + opts::dump::DumpXme = true; + opts::dump::DumpXmi = true; + opts::dump::DumpIds = true; + opts::dump::DumpPublics = true; + opts::dump::DumpSectionContribs = true; + opts::dump::DumpSectionMap = true; + opts::dump::DumpStreams = true; + opts::dump::DumpStreamBlocks = true; + opts::dump::DumpStringTable = true; + opts::dump::DumpSummary = true; + opts::dump::DumpSymbols = true; + opts::dump::DumpIds = true; + opts::dump::DumpIdExtras = true; + opts::dump::DumpTypes = true; + opts::dump::DumpTypeExtras = true; + opts::dump::DumpModules = true; + opts::dump::DumpModuleFiles = true; } } if (opts::PdbToYamlSubcommand) { @@ -945,13 +1063,8 @@ int main(int argc_, const char *argv_[]) { opts::pdb2yaml::DumpModuleSyms = true; opts::pdb2yaml::DumpModuleSubsections.push_back( opts::ModuleSubsection::All); - if (llvm::is_contained(opts::pdb2yaml::DumpModuleSubsections, - opts::ModuleSubsection::All)) { - opts::pdb2yaml::DumpModuleSubsections.reset(); - opts::pdb2yaml::DumpModuleSubsections.push_back( - opts::ModuleSubsection::All); - } } + simplifyChunkList(opts::pdb2yaml::DumpModuleSubsections); if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles) opts::pdb2yaml::DumpModules = true; @@ -1010,9 +1123,12 @@ int main(int argc_, const char *argv_[]) { } std::for_each(opts::pretty::InputFilenames.begin(), opts::pretty::InputFilenames.end(), dumpPretty); - } else if (opts::RawSubcommand) { - std::for_each(opts::raw::InputFilenames.begin(), - opts::raw::InputFilenames.end(), dumpRaw); + } else if (opts::DumpSubcommand) { + std::for_each(opts::dump::InputFilenames.begin(), + opts::dump::InputFilenames.end(), dumpRaw); + } else if (opts::BytesSubcommand) { + std::for_each(opts::bytes::InputFilenames.begin(), + opts::bytes::InputFilenames.end(), dumpBytes); } else if (opts::DiffSubcommand) { if (opts::diff::InputFilenames.size() != 2) { errs() << "diff subcommand expects exactly 2 arguments.\n"; diff --git a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h index a41b032d2b13..837d8ebbaf9e 100644 --- a/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h +++ b/contrib/llvm/tools/llvm-pdbutil/llvm-pdbutil.h @@ -92,16 +92,39 @@ extern llvm::cl::opt ClassFormat; extern llvm::cl::opt ClassRecursionDepth; } -namespace raw { -struct BlockRange { - uint32_t Min; - llvm::Optional Max; +namespace bytes { +struct NumberRange { + uint64_t Min; + llvm::Optional Max; }; +extern llvm::Optional DumpBlockRange; +extern llvm::Optional DumpByteRange; +extern llvm::cl::list DumpStreamData; +extern llvm::cl::opt NameMap; + +extern llvm::cl::opt SectionContributions; +extern llvm::cl::opt SectionMap; +extern llvm::cl::opt ModuleInfos; +extern llvm::cl::opt FileInfo; +extern llvm::cl::opt TypeServerMap; +extern llvm::cl::opt ECData; + +extern llvm::cl::list TypeIndex; +extern llvm::cl::list IdIndex; + +extern llvm::cl::opt ModuleIndex; +extern llvm::cl::opt ModuleSyms; +extern llvm::cl::opt ModuleC11; +extern llvm::cl::opt ModuleC13; +extern llvm::cl::opt SplitChunks; +} // namespace bytes + +namespace dump { + extern llvm::cl::opt DumpSummary; extern llvm::cl::opt DumpStreams; -extern llvm::Optional DumpBlockRange; -extern llvm::cl::list DumpStreamData; +extern llvm::cl::opt DumpStreamBlocks; extern llvm::cl::opt DumpLines; extern llvm::cl::opt DumpInlineeLines; @@ -111,9 +134,12 @@ extern llvm::cl::opt DumpStringTable; extern llvm::cl::opt DumpTypes; extern llvm::cl::opt DumpTypeData; extern llvm::cl::opt DumpTypeExtras; +extern llvm::cl::list DumpTypeIndex; + extern llvm::cl::opt DumpIds; extern llvm::cl::opt DumpIdData; extern llvm::cl::opt DumpIdExtras; +extern llvm::cl::list DumpIdIndex; extern llvm::cl::opt DumpSymbols; extern llvm::cl::opt DumpSymRecordBytes; extern llvm::cl::opt DumpPublics; @@ -124,10 +150,6 @@ extern llvm::cl::opt DumpModuleFiles; extern llvm::cl::opt RawAll; } -namespace diff { -extern llvm::cl::opt Pedantic; -} - namespace pdb2yaml { extern llvm::cl::opt All; extern llvm::cl::opt NoFileHeaders; diff --git a/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp b/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp index 4867acf70983..e9bc2de82bdf 100644 --- a/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp +++ b/contrib/llvm/tools/llvm-profdata/llvm-profdata.cpp @@ -246,10 +246,12 @@ static void mergeInstrProfile(const WeightedFileVector &Inputs, exitWithError(std::move(WC->Err), WC->ErrWhence); InstrProfWriter &Writer = Contexts[0]->Writer; - if (OutputFormat == PF_Text) - Writer.writeText(Output); - else + if (OutputFormat == PF_Text) { + if (Error E = Writer.writeText(Output)) + exitWithError(std::move(E)); + } else { Writer.write(Output); + } } static sampleprof::SampleProfileFormat FormatMap[] = { diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp index 216c9adad9a7..daa7a643a72f 100644 --- a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -36,7 +36,6 @@ #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" @@ -69,6 +68,14 @@ using namespace llvm::Win64EH; namespace { +struct LoadConfigTables { + uint64_t SEHTableVA = 0; + uint64_t SEHTableCount = 0; + uint32_t GuardFlags = 0; + uint64_t GuardFidTableVA = 0; + uint64_t GuardFidTableCount = 0; +}; + class COFFDumper : public ObjDumper { public: friend class COFFObjectDumpDelegate; @@ -87,6 +94,7 @@ class COFFDumper : public ObjDumper { void printCOFFBaseReloc() override; void printCOFFDebugDirectory() override; void printCOFFResources() override; + void printCOFFLoadConfig() override; void printCodeViewDebugInfo() override; void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs, llvm::codeview::TypeTableBuilder &CVTypes) override; @@ -101,6 +109,11 @@ class COFFDumper : public ObjDumper { template void printPEHeader(const PEHeader *Hdr); void printBaseOfDataField(const pe32_header *Hdr); void printBaseOfDataField(const pe32plus_header *Hdr); + template + void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables); + typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *); + void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize, + PrintExtraCB PrintExtra = 0); void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section); void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section); @@ -746,6 +759,129 @@ void COFFDumper::printCOFFDebugDirectory() { } } +void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count, + uint64_t EntrySize, PrintExtraCB PrintExtra) { + uintptr_t TableStart, TableEnd; + error(Obj->getVaPtr(TableVA, TableStart)); + error(Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd)); + TableEnd++; + for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) { + uint32_t RVA = *reinterpret_cast(I); + raw_ostream &OS = W.startLine(); + OS << "0x" << utohexstr(Obj->getImageBase() + RVA); + if (PrintExtra) + PrintExtra(OS, reinterpret_cast(I)); + OS << '\n'; + } +} + +void COFFDumper::printCOFFLoadConfig() { + LoadConfigTables Tables; + if (Obj->is64()) + printCOFFLoadConfig(Obj->getLoadConfig64(), Tables); + else + printCOFFLoadConfig(Obj->getLoadConfig32(), Tables); + + if (Tables.SEHTableVA) { + ListScope LS(W, "SEHTable"); + printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4); + } + + if (Tables.GuardFidTableVA) { + ListScope LS(W, "GuardFidTable"); + if (Tables.GuardFlags & uint32_t(coff_guard_flags::FidTableHasFlags)) { + auto PrintGuardFlags = [](raw_ostream &OS, const uint8_t *Entry) { + uint8_t Flags = *reinterpret_cast(Entry + 4); + if (Flags) + OS << " flags " << utohexstr(Flags); + }; + printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 5, + PrintGuardFlags); + } else { + printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 4); + } + } +} + +template +void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) { + if (!Conf) + return; + + ListScope LS(W, "LoadConfig"); + char FormattedTime[20] = {}; + time_t TDS = Conf->TimeDateStamp; + strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); + W.printHex("Size", Conf->Size); + + // Print everything before SecurityCookie. The vast majority of images today + // have all these fields. + if (Conf->Size < offsetof(T, SEHandlerTable)) + return; + W.printHex("TimeDateStamp", FormattedTime, TDS); + W.printHex("MajorVersion", Conf->MajorVersion); + W.printHex("MinorVersion", Conf->MinorVersion); + W.printHex("GlobalFlagsClear", Conf->GlobalFlagsClear); + W.printHex("GlobalFlagsSet", Conf->GlobalFlagsSet); + W.printHex("CriticalSectionDefaultTimeout", + Conf->CriticalSectionDefaultTimeout); + W.printHex("DeCommitFreeBlockThreshold", Conf->DeCommitFreeBlockThreshold); + W.printHex("DeCommitTotalFreeThreshold", Conf->DeCommitTotalFreeThreshold); + W.printHex("LockPrefixTable", Conf->LockPrefixTable); + W.printHex("MaximumAllocationSize", Conf->MaximumAllocationSize); + W.printHex("VirtualMemoryThreshold", Conf->VirtualMemoryThreshold); + W.printHex("ProcessHeapFlags", Conf->ProcessHeapFlags); + W.printHex("ProcessAffinityMask", Conf->ProcessAffinityMask); + W.printHex("CSDVersion", Conf->CSDVersion); + W.printHex("DependentLoadFlags", Conf->DependentLoadFlags); + W.printHex("EditList", Conf->EditList); + W.printHex("SecurityCookie", Conf->SecurityCookie); + + // Print the safe SEH table if present. + if (Conf->Size < offsetof(coff_load_configuration32, GuardCFCheckFunction)) + return; + W.printHex("SEHandlerTable", Conf->SEHandlerTable); + W.printNumber("SEHandlerCount", Conf->SEHandlerCount); + + Tables.SEHTableVA = Conf->SEHandlerTable; + Tables.SEHTableCount = Conf->SEHandlerCount; + + // Print everything before CodeIntegrity. (2015) + if (Conf->Size < offsetof(T, CodeIntegrity)) + return; + W.printHex("GuardCFCheckFunction", Conf->GuardCFCheckFunction); + W.printHex("GuardCFCheckDispatch", Conf->GuardCFCheckDispatch); + W.printHex("GuardCFFunctionTable", Conf->GuardCFFunctionTable); + W.printNumber("GuardCFFunctionCount", Conf->GuardCFFunctionCount); + W.printHex("GuardFlags", Conf->GuardFlags); + + Tables.GuardFidTableVA = Conf->GuardCFFunctionTable; + Tables.GuardFidTableCount = Conf->GuardCFFunctionCount; + Tables.GuardFlags = Conf->GuardFlags; + + // Print the rest. (2017) + if (Conf->Size < sizeof(T)) + return; + W.printHex("GuardAddressTakenIatEntryTable", + Conf->GuardAddressTakenIatEntryTable); + W.printNumber("GuardAddressTakenIatEntryCount", + Conf->GuardAddressTakenIatEntryCount); + W.printHex("GuardLongJumpTargetTable", Conf->GuardLongJumpTargetTable); + W.printNumber("GuardLongJumpTargetCount", Conf->GuardLongJumpTargetCount); + W.printHex("DynamicValueRelocTable", Conf->DynamicValueRelocTable); + W.printHex("CHPEMetadataPointer", Conf->CHPEMetadataPointer); + W.printHex("GuardRFFailureRoutine", Conf->GuardRFFailureRoutine); + W.printHex("GuardRFFailureRoutineFunctionPointer", + Conf->GuardRFFailureRoutineFunctionPointer); + W.printHex("DynamicValueRelocTableOffset", + Conf->DynamicValueRelocTableOffset); + W.printNumber("DynamicValueRelocTableSection", + Conf->DynamicValueRelocTableSection); + W.printHex("GuardRFVerifyStackPointerFunctionPointer", + Conf->GuardRFVerifyStackPointerFunctionPointer); + W.printHex("HotPatchTableOffset", Conf->HotPatchTableOffset); +} + void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) { W.printHex("BaseOfData", Hdr->BaseOfData); } @@ -1100,7 +1236,7 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName, if (Magic != COFF::DEBUG_SECTION_MAGIC) return error(object_error::parse_failed); - Types.reset(Data); + Types.reset(Data, 100); TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes); error(codeview::visitTypeStream(Types, TDV)); diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h index 48f825c527c1..43883c2d2176 100644 --- a/contrib/llvm/tools/llvm-readobj/ObjDumper.h +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h @@ -68,6 +68,7 @@ class ObjDumper { virtual void printCOFFBaseReloc() { } virtual void printCOFFDebugDirectory() { } virtual void printCOFFResources() {} + virtual void printCOFFLoadConfig() { } virtual void printCodeViewDebugInfo() { } virtual void mergeCodeViewTypes(llvm::codeview::TypeTableBuilder &CVIDs, llvm::codeview::TypeTableBuilder &CVTypes) {} diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp index cd7244a8f970..51991a3f067b 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -218,6 +218,11 @@ namespace opts { cl::opt COFFResources("coff-resources", cl::desc("Display the PE/COFF .rsrc section")); + // -coff-load-config + cl::opt + COFFLoadConfig("coff-load-config", + cl::desc("Display the PE/COFF load config")); + // -macho-data-in-code cl::opt MachODataInCode("macho-data-in-code", @@ -444,6 +449,8 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printCOFFDebugDirectory(); if (opts::COFFResources) Dumper->printCOFFResources(); + if (opts::COFFLoadConfig) + Dumper->printCOFFLoadConfig(); if (opts::CodeView) Dumper->printCodeViewDebugInfo(); if (opts::CodeViewMergedTypes) diff --git a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp index 0ed7adb46ddc..3cf8b37bc2e2 100644 --- a/contrib/llvm/tools/llvm-stress/llvm-stress.cpp +++ b/contrib/llvm/tools/llvm-stress/llvm-stress.cpp @@ -96,17 +96,13 @@ class Random { return Seed & 0x7ffff; } - /// Return a random 32 bit integer. - uint32_t Rand32() { - uint32_t Val = Rand(); - Val &= 0xffff; - return Val | (Rand() << 16); - } - /// Return a random 64 bit integer. uint64_t Rand64() { - uint64_t Val = Rand32(); - return Val | (uint64_t(Rand32()) << 32); + uint64_t Val = Rand() & 0xffff; + Val |= uint64_t(Rand() & 0xffff) << 16; + Val |= uint64_t(Rand() & 0xffff) << 32; + Val |= uint64_t(Rand() & 0xffff) << 48; + return Val; } /// Rand operator for STL algorithms. @@ -116,10 +112,14 @@ class Random { /// Make this like a C++11 random device typedef uint32_t result_type; - uint32_t operator()() { return Rand32(); } static constexpr result_type min() { return 0; } static constexpr result_type max() { return 0x7ffff; } - + uint32_t operator()() { + uint32_t Val = Rand(); + assert(Val <= max() && "Random value out of range"); + return Val; + } + private: unsigned Seed; }; @@ -168,19 +168,24 @@ struct Modifier { } protected: + /// Return a random integer. + uint32_t getRandom() { + return Ran->Rand(); + } + /// Return a random value from the list of known values. Value *getRandomVal() { assert(PT->size()); - return PT->at(Ran->Rand() % PT->size()); + return PT->at(getRandom() % PT->size()); } Constant *getRandomConstant(Type *Tp) { if (Tp->isIntegerTy()) { - if (Ran->Rand() & 1) + if (getRandom() & 1) return ConstantInt::getAllOnesValue(Tp); return ConstantInt::getNullValue(Tp); } else if (Tp->isFloatingPointTy()) { - if (Ran->Rand() & 1) + if (getRandom() & 1) return ConstantFP::getAllOnesValue(Tp); return ConstantFP::getNullValue(Tp); } @@ -189,7 +194,7 @@ struct Modifier { /// Return a random value with a known type. Value *getRandomValue(Type *Tp) { - unsigned index = Ran->Rand(); + unsigned index = getRandom(); for (unsigned i=0; isize(); ++i) { Value *V = PT->at((index + i) % PT->size()); if (V->getType() == Tp) @@ -198,11 +203,11 @@ struct Modifier { // If the requested type was not found, generate a constant value. if (Tp->isIntegerTy()) { - if (Ran->Rand() & 1) + if (getRandom() & 1) return ConstantInt::getAllOnesValue(Tp); return ConstantInt::getNullValue(Tp); } else if (Tp->isFloatingPointTy()) { - if (Ran->Rand() & 1) + if (getRandom() & 1) return ConstantFP::getAllOnesValue(Tp); return ConstantFP::getNullValue(Tp); } else if (Tp->isVectorTy()) { @@ -222,7 +227,7 @@ struct Modifier { /// Return a random value of any pointer type. Value *getRandomPointerValue() { - unsigned index = Ran->Rand(); + unsigned index = getRandom(); for (unsigned i=0; isize(); ++i) { Value *V = PT->at((index + i) % PT->size()); if (V->getType()->isPointerTy()) @@ -233,7 +238,7 @@ struct Modifier { /// Return a random value of any vector type. Value *getRandomVectorValue() { - unsigned index = Ran->Rand(); + unsigned index = getRandom(); for (unsigned i=0; isize(); ++i) { Value *V = PT->at((index + i) % PT->size()); if (V->getType()->isVectorTy()) @@ -244,7 +249,7 @@ struct Modifier { /// Pick a random type. Type *pickType() { - return (Ran->Rand() & 1 ? pickVectorType() : pickScalarType()); + return (getRandom() & 1 ? pickVectorType() : pickScalarType()); } /// Pick a random pointer type. @@ -258,7 +263,7 @@ struct Modifier { // Pick a random vector width in the range 2**0 to 2**4. // by adding two randoms we are generating a normal-like distribution // around 2**3. - unsigned width = 1<<((Ran->Rand() % 3) + (Ran->Rand() % 3)); + unsigned width = 1<<((getRandom() % 3) + (getRandom() % 3)); Type *Ty; // Vectors of x86mmx are illegal; keep trying till we get something else. @@ -288,7 +293,7 @@ struct Modifier { AdditionalScalarTypes.begin(), AdditionalScalarTypes.end()); } - return ScalarTypes[Ran->Rand() % ScalarTypes.size()]; + return ScalarTypes[getRandom() % ScalarTypes.size()]; } /// Basic block to populate @@ -348,7 +353,7 @@ struct BinModifier: public Modifier { bool isFloat = Val0->getType()->getScalarType()->isFloatingPointTy(); Instruction* Term = BB->getTerminator(); - unsigned R = Ran->Rand() % (isFloat ? 7 : 13); + unsigned R = getRandom() % (isFloat ? 7 : 13); Instruction::BinaryOps Op; switch (R) { @@ -379,7 +384,7 @@ struct ConstModifier: public Modifier { Type *Ty = pickType(); if (Ty->isVectorTy()) { - switch (Ran->Rand() % 2) { + switch (getRandom() % 2) { case 0: if (Ty->getScalarType()->isIntegerTy()) return PT->push_back(ConstantVector::getAllOnesValue(Ty)); break; @@ -398,25 +403,27 @@ struct ConstModifier: public Modifier { APInt RandomInt(Ty->getPrimitiveSizeInBits(), makeArrayRef(RandomBits)); APFloat RandomFloat(Ty->getFltSemantics(), RandomInt); - if (Ran->Rand() & 1) + if (getRandom() & 1) return PT->push_back(ConstantFP::getNullValue(Ty)); return PT->push_back(ConstantFP::get(Ty->getContext(), RandomFloat)); } if (Ty->isIntegerTy()) { - switch (Ran->Rand() % 7) { + switch (getRandom() % 7) { case 0: return PT->push_back(ConstantInt::get( Ty, APInt::getAllOnesValue(Ty->getPrimitiveSizeInBits()))); case 1: return PT->push_back(ConstantInt::get( Ty, APInt::getNullValue(Ty->getPrimitiveSizeInBits()))); - case 2: case 3: case 4: case 5: + case 2: + case 3: + case 4: + case 5: case 6: - PT->push_back(ConstantInt::get(Ty, Ran->Rand())); + PT->push_back(ConstantInt::get(Ty, getRandom())); } } - } }; @@ -439,7 +446,7 @@ struct ExtractElementModifier: public Modifier { Value *Val0 = getRandomVectorValue(); Value *V = ExtractElementInst::Create(Val0, ConstantInt::get(Type::getInt32Ty(BB->getContext()), - Ran->Rand() % cast(Val0->getType())->getNumElements()), + getRandom() % cast(Val0->getType())->getNumElements()), "E", BB->getTerminator()); return PT->push_back(V); } @@ -457,9 +464,9 @@ struct ShuffModifier: public Modifier { Type *I32 = Type::getInt32Ty(BB->getContext()); for (unsigned i=0; iRand() % (Width*2)); + Constant *CI = ConstantInt::get(I32, getRandom() % (Width*2)); // Pick some undef values. - if (!(Ran->Rand() % 5)) + if (!(getRandom() % 5)) CI = UndefValue::get(I32); Idxs.push_back(CI); } @@ -482,7 +489,7 @@ struct InsertElementModifier: public Modifier { Value *V = InsertElementInst::Create(Val0, Val1, ConstantInt::get(Type::getInt32Ty(BB->getContext()), - Ran->Rand() % cast(Val0->getType())->getNumElements()), + getRandom() % cast(Val0->getType())->getNumElements()), "I", BB->getTerminator()); return PT->push_back(V); } @@ -518,7 +525,7 @@ struct CastModifier: public Modifier { unsigned DestSize = DestTy->getScalarType()->getPrimitiveSizeInBits(); // Generate lots of bitcasts. - if ((Ran->Rand() & 1) && VSize == DestSize) { + if ((getRandom() & 1) && VSize == DestSize) { return PT->push_back( new BitCastInst(V, DestTy, "BC", BB->getTerminator())); } @@ -531,7 +538,7 @@ struct CastModifier: public Modifier { new TruncInst(V, DestTy, "Tr", BB->getTerminator())); } else { assert(VSize < DestSize && "Different int types with the same size?"); - if (Ran->Rand() & 1) + if (getRandom() & 1) return PT->push_back( new ZExtInst(V, DestTy, "ZE", BB->getTerminator())); return PT->push_back(new SExtInst(V, DestTy, "Se", BB->getTerminator())); @@ -541,7 +548,7 @@ struct CastModifier: public Modifier { // Fp to int. if (VTy->getScalarType()->isFloatingPointTy() && DestTy->getScalarType()->isIntegerTy()) { - if (Ran->Rand() & 1) + if (getRandom() & 1) return PT->push_back( new FPToSIInst(V, DestTy, "FC", BB->getTerminator())); return PT->push_back(new FPToUIInst(V, DestTy, "FC", BB->getTerminator())); @@ -550,7 +557,7 @@ struct CastModifier: public Modifier { // Int to fp. if (VTy->getScalarType()->isIntegerTy() && DestTy->getScalarType()->isFloatingPointTy()) { - if (Ran->Rand() & 1) + if (getRandom() & 1) return PT->push_back( new SIToFPInst(V, DestTy, "FC", BB->getTerminator())); return PT->push_back(new UIToFPInst(V, DestTy, "FC", BB->getTerminator())); @@ -587,7 +594,7 @@ struct SelectModifier: public Modifier { // If the value type is a vector, and we allow vector select, then in 50% // of the cases generate a vector select. - if (Val0->getType()->isVectorTy() && (Ran->Rand() % 1)) { + if (Val0->getType()->isVectorTy() && (getRandom() % 1)) { unsigned NumElem = cast(Val0->getType())->getNumElements(); CondTy = VectorType::get(CondTy, NumElem); } @@ -611,11 +618,11 @@ struct CmpModifier: public Modifier { int op; if (fp) { - op = Ran->Rand() % + op = getRandom() % (CmpInst::LAST_FCMP_PREDICATE - CmpInst::FIRST_FCMP_PREDICATE) + CmpInst::FIRST_FCMP_PREDICATE; } else { - op = Ran->Rand() % + op = getRandom() % (CmpInst::LAST_ICMP_PREDICATE - CmpInst::FIRST_ICMP_PREDICATE) + CmpInst::FIRST_ICMP_PREDICATE; } diff --git a/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.cpp index 7c41d9fad696..03914ef98952 100644 --- a/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -2762,8 +2762,8 @@ class InstAnalyzer { AnalyzeNode(Pat->getTree(0)); } - void Analyze(const PatternToMatch *Pat) { - AnalyzeNode(Pat->getSrcPattern()); + void Analyze(const PatternToMatch &Pat) { + AnalyzeNode(Pat.getSrcPattern()); } private: @@ -3220,7 +3220,7 @@ static void FindNames(const TreePatternNode *P, } void CodeGenDAGPatterns::AddPatternToMatch(TreePattern *Pattern, - const PatternToMatch &PTM) { + PatternToMatch &&PTM) { // Do some sanity checking on the pattern we're about to match. std::string Reason; if (!PTM.getSrcPattern()->canPatternMatch(Reason, *this)) { @@ -3259,7 +3259,7 @@ void CodeGenDAGPatterns::AddPatternToMatch(TreePattern *Pattern, SrcNames[Entry.first].second == 1) Pattern->error("Pattern has dead named input: $" + Entry.first); - PatternsToMatch.push_back(PTM); + PatternsToMatch.push_back(std::move(PTM)); } @@ -3289,9 +3289,7 @@ void CodeGenDAGPatterns::InferInstructionFlags() { // Second, look for single-instruction patterns defined outside the // instruction. - for (ptm_iterator I = ptm_begin(), E = ptm_end(); I != E; ++I) { - const PatternToMatch &PTM = *I; - + for (const PatternToMatch &PTM : ptms()) { // We can only infer from single-instruction patterns, otherwise we won't // know which instruction should get the flags. SmallVector PatInstrs; @@ -3307,7 +3305,7 @@ void CodeGenDAGPatterns::InferInstructionFlags() { continue; InstAnalyzer PatInfo(*this); - PatInfo.Analyze(&PTM); + PatInfo.Analyze(PTM); Errors += InferFromPattern(InstInfo, PatInfo, PTM.getSrcRecord()); } @@ -3367,7 +3365,7 @@ void CodeGenDAGPatterns::VerifyInstructionFlags() { // Analyze the source pattern. InstAnalyzer PatInfo(*this); - PatInfo.Analyze(&PTM); + PatInfo.Analyze(PTM); // Collect error messages. SmallVector Msgs; @@ -3553,14 +3551,12 @@ void CodeGenDAGPatterns::ParsePatterns() { TreePattern Temp(Result.getRecord(), DstPattern, false, *this); Temp.InferAllTypes(); - - AddPatternToMatch(Pattern, - PatternToMatch(CurPattern, - CurPattern->getValueAsListInit("Predicates"), - Pattern->getTree(0), - Temp.getOnlyTree(), InstImpResults, - CurPattern->getValueAsInt("AddedComplexity"), - CurPattern->getID())); + AddPatternToMatch( + Pattern, + PatternToMatch( + CurPattern, CurPattern->getValueAsListInit("Predicates"), + Pattern->getTree(0), Temp.getOnlyTree(), std::move(InstImpResults), + CurPattern->getValueAsInt("AddedComplexity"), CurPattern->getID())); } } diff --git a/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.h b/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.h index 5c56fb644e7f..8b3e19142370 100644 --- a/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/contrib/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -684,12 +684,12 @@ class DAGInstruction { /// processed to produce isel. class PatternToMatch { public: - PatternToMatch(Record *srcrecord, ListInit *preds, - TreePatternNode *src, TreePatternNode *dst, - const std::vector &dstregs, + PatternToMatch(Record *srcrecord, ListInit *preds, TreePatternNode *src, + TreePatternNode *dst, std::vector dstregs, int complexity, unsigned uid) - : SrcRecord(srcrecord), Predicates(preds), SrcPattern(src), DstPattern(dst), - Dstregs(dstregs), AddedComplexity(complexity), ID(uid) {} + : SrcRecord(srcrecord), Predicates(preds), SrcPattern(src), + DstPattern(dst), Dstregs(std::move(dstregs)), + AddedComplexity(complexity), ID(uid) {} Record *SrcRecord; // Originating Record for the pattern. ListInit *Predicates; // Top level predicate conditions to match. @@ -853,7 +853,7 @@ class CodeGenDAGPatterns { void GenerateVariants(); void VerifyInstructionFlags(); - void AddPatternToMatch(TreePattern *Pattern, const PatternToMatch &PTM); + void AddPatternToMatch(TreePattern *Pattern, PatternToMatch &&PTM); void FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, std::map &InstInputs, diff --git a/contrib/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/contrib/llvm/utils/TableGen/DAGISelMatcherGen.cpp index aafc1157893e..d239f96d2a60 100644 --- a/contrib/llvm/utils/TableGen/DAGISelMatcherGen.cpp +++ b/contrib/llvm/utils/TableGen/DAGISelMatcherGen.cpp @@ -848,8 +848,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, if (II.HasOneImplicitDefWithKnownVT(CGT) != MVT::Other) HandledReg = II.ImplicitDefs[0]; - for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i) { - Record *Reg = Pattern.getDstRegs()[i]; + for (Record *Reg : Pattern.getDstRegs()) { if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue; ResultVTs.push_back(getRegisterValueType(Reg, CGT)); } @@ -972,8 +971,7 @@ void MatcherGen::EmitResultCode() { HandledReg = II.ImplicitDefs[0]; } - for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i) { - Record *Reg = Pattern.getDstRegs()[i]; + for (Record *Reg : Pattern.getDstRegs()) { if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue; ++NumSrcResults; } diff --git a/contrib/llvm/utils/TableGen/GlobalISelEmitter.cpp b/contrib/llvm/utils/TableGen/GlobalISelEmitter.cpp index 88ded1f25ffb..03d231a153dc 100644 --- a/contrib/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/contrib/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -158,6 +158,16 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) { return failedImport(Explanation); } +static Record *getInitValueAsRegClass(Init *V) { + if (DefInit *VDefInit = dyn_cast(V)) { + if (VDefInit->getDef()->isSubClassOf("RegisterOperand")) + return VDefInit->getDef()->getValueAsDef("RegClass"); + if (VDefInit->getDef()->isSubClassOf("RegisterClass")) + return VDefInit->getDef(); + } + return nullptr; +} + //===- Matchers -----------------------------------------------------------===// class OperandMatcher; @@ -973,6 +983,7 @@ class DebugCommentAction : public MatchAction { /// into the desired instruction when this is possible. class BuildMIAction : public MatchAction { private: + std::string Name; const CodeGenInstruction *I; const InstructionMatcher &Matched; std::vector> OperandRenderers; @@ -996,8 +1007,9 @@ class BuildMIAction : public MatchAction { } public: - BuildMIAction(const CodeGenInstruction *I, const InstructionMatcher &Matched) - : I(I), Matched(Matched) {} + BuildMIAction(const StringRef Name, const CodeGenInstruction *I, + const InstructionMatcher &Matched) + : Name(Name), I(I), Matched(Matched) {} template Kind &addRenderer(Args&&... args) { @@ -1032,7 +1044,7 @@ class BuildMIAction : public MatchAction { } } - OS << " MachineInstr &NewI = " << RecycleVarName << ";\n"; + OS << " MachineInstr &" << Name << " = " << RecycleVarName << ";\n"; return; } @@ -1050,7 +1062,40 @@ class BuildMIAction : public MatchAction { OS << " for (const auto &MMO : FromMI->memoperands())\n"; OS << " MIB.addMemOperand(MMO);\n"; OS << " " << RecycleVarName << ".eraseFromParent();\n"; - OS << " MachineInstr &NewI = *MIB;\n"; + OS << " MachineInstr &" << Name << " = *MIB;\n"; + } +}; + +/// Generates code to constrain the operands of an output instruction to the +/// register classes specified by the definition of that instruction. +class ConstrainOperandsToDefinitionAction : public MatchAction { + std::string Name; + +public: + ConstrainOperandsToDefinitionAction(const StringRef Name) : Name(Name) {} + + void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, + StringRef RecycleVarName) const override { + OS << " constrainSelectedInstRegOperands(" << Name << ", TII, TRI, RBI);\n"; + } +}; + +/// Generates code to constrain the specified operand of an output instruction +/// to the specified register class. +class ConstrainOperandToRegClassAction : public MatchAction { + std::string Name; + unsigned OpIdx; + const CodeGenRegisterClass &RC; + +public: + ConstrainOperandToRegClassAction(const StringRef Name, unsigned OpIdx, + const CodeGenRegisterClass &RC) + : Name(Name), OpIdx(OpIdx), RC(RC) {} + + void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, + StringRef RecycleVarName) const override { + OS << " constrainOperandRegToRegClass(" << Name << ", " << OpIdx + << ", " << RC.getQualifiedName() << "RegClass, TII, TRI, RBI);\n"; } }; @@ -1205,7 +1250,6 @@ void RuleMatcher::emit(raw_ostream &OS, MA->emitCxxActionStmts(OS, *this, "I"); } - OS << " constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);\n"; OS << " return true;\n"; OS << " }\n"; OS << " return false;\n"; @@ -1439,15 +1483,10 @@ Error GlobalISelEmitter::importChildMatcher(InstructionMatcher &InsnMatcher, auto *ChildRec = ChildDefInit->getDef(); // Check for register classes. - if (ChildRec->isSubClassOf("RegisterClass")) { + if (ChildRec->isSubClassOf("RegisterClass") || + ChildRec->isSubClassOf("RegisterOperand")) { OM.addPredicate( - Target.getRegisterClass(ChildRec)); - return Error::success(); - } - - if (ChildRec->isSubClassOf("RegisterOperand")) { - OM.addPredicate( - Target.getRegisterClass(ChildRec->getValueAsDef("RegClass"))); + Target.getRegisterClass(getInitValueAsRegClass(ChildDefInit))); return Error::success(); } @@ -1554,22 +1593,33 @@ Expected GlobalISelEmitter::createAndImportInstructionRenderer( "Pattern operator isn't an instruction (it's a ValueType)"); return failedImport("Pattern operator isn't an instruction"); } - auto &DstI = Target.getInstruction(DstOp); + CodeGenInstruction *DstI = &Target.getInstruction(DstOp); - auto &DstMIBuilder = M.addAction(&DstI, InsnMatcher); + unsigned DstINumUses = DstI->Operands.size() - DstI->Operands.NumDefs; + unsigned ExpectedDstINumUses = Dst->getNumChildren(); + + // COPY_TO_REGCLASS is just a copy with a ConstrainOperandToRegClassAction + // attached. + if (DstI->TheDef->getName() == "COPY_TO_REGCLASS") { + DstI = &Target.getInstruction(RK.getDef("COPY")); + DstINumUses--; // Ignore the class constraint. + ExpectedDstINumUses--; + } + + auto &DstMIBuilder = M.addAction("NewI", DstI, InsnMatcher); // Render the explicit defs. - for (unsigned I = 0; I < DstI.Operands.NumDefs; ++I) { - const auto &DstIOperand = DstI.Operands[I]; + for (unsigned I = 0; I < DstI->Operands.NumDefs; ++I) { + const CGIOperandList::OperandInfo &DstIOperand = DstI->Operands[I]; DstMIBuilder.addRenderer(InsnMatcher, DstIOperand.Name); } // Render the explicit uses. unsigned Child = 0; - unsigned DstINumUses = DstI.Operands.size() - DstI.Operands.NumDefs; unsigned NumDefaultOps = 0; for (unsigned I = 0; I != DstINumUses; ++I) { - const auto &DstIOperand = DstI.Operands[DstI.Operands.NumDefs + I]; + const CGIOperandList::OperandInfo &DstIOperand = + DstI->Operands[DstI->Operands.NumDefs + I]; // If the operand has default values, introduce them now. // FIXME: Until we have a decent test case that dictates we should do @@ -1590,10 +1640,10 @@ Expected GlobalISelEmitter::createAndImportInstructionRenderer( ++Child; } - if (NumDefaultOps + Dst->getNumChildren() != DstINumUses) + if (NumDefaultOps + ExpectedDstINumUses != DstINumUses) return failedImport("Expected " + llvm::to_string(DstINumUses) + " used operands but found " + - llvm::to_string(Dst->getNumChildren()) + + llvm::to_string(ExpectedDstINumUses) + " explicit ones and " + llvm::to_string(NumDefaultOps) + " default ones"); @@ -1684,10 +1734,16 @@ Expected GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { const auto &DstIOperand = DstI.Operands[OpIdx]; Record *DstIOpRec = DstIOperand.Rec; - if (DstIOpRec->isSubClassOf("RegisterOperand")) + if (DstI.TheDef->getName() == "COPY_TO_REGCLASS") { + DstIOpRec = getInitValueAsRegClass(Dst->getChild(1)->getLeafValue()); + + if (DstIOpRec == nullptr) + return failedImport( + "COPY_TO_REGCLASS operand #1 isn't a register class"); + } else if (DstIOpRec->isSubClassOf("RegisterOperand")) DstIOpRec = DstIOpRec->getValueAsDef("RegClass"); - if (!DstIOpRec->isSubClassOf("RegisterClass")) - return failedImport("Dst MI def isn't a register class"); + else if (!DstIOpRec->isSubClassOf("RegisterClass")) + return failedImport("Dst MI def isn't a register class" + to_string(*Dst)); OperandMatcher &OM = InsnMatcher.getOperand(OpIdx); OM.setSymbolicName(DstIOperand.Name); @@ -1707,6 +1763,22 @@ Expected GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { if (auto Error = importImplicitDefRenderers(DstMIBuilder, P.getDstRegs())) return std::move(Error); + // Constrain the registers to classes. This is normally derived from the + // emitted instruction but a few instructions require special handling. + if (DstI.TheDef->getName() == "COPY_TO_REGCLASS") { + // COPY_TO_REGCLASS does not provide operand constraints itself but the + // result is constrained to the class given by the second child. + Record *DstIOpRec = + getInitValueAsRegClass(Dst->getChild(1)->getLeafValue()); + + if (DstIOpRec == nullptr) + return failedImport("COPY_TO_REGCLASS operand #1 isn't a register class"); + + M.addAction( + "NewI", 0, Target.getRegisterClass(DstIOpRec)); + } else + M.addAction("NewI"); + // We're done with this pattern! It's eligible for GISel emission; return it. ++NumPatternImported; return std::move(M); diff --git a/contrib/llvm/utils/TableGen/OptParserEmitter.cpp b/contrib/llvm/utils/TableGen/OptParserEmitter.cpp index 04e6537f3d15..e3777d036a23 100644 --- a/contrib/llvm/utils/TableGen/OptParserEmitter.cpp +++ b/contrib/llvm/utils/TableGen/OptParserEmitter.cpp @@ -196,6 +196,9 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { OS << ", nullptr"; // The option meta-variable name (unused). + OS << ", nullptr"; + + // The option Values (unused for groups). OS << ", nullptr)\n"; } OS << "\n"; @@ -285,6 +288,13 @@ void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { else OS << "nullptr"; + // The option Values. Used for shell autocompletion. + OS << ", "; + if (!isa(R.getValueInit("Values"))) + write_cstring(OS, R.getValueAsString("Values")); + else + OS << "nullptr"; + OS << ")\n"; } OS << "#endif // OPTION\n"; diff --git a/lib/clang/include/clang/Basic/Version.inc b/lib/clang/include/clang/Basic/Version.inc index 2b32eb8a3fb9..abce66d516ac 100644 --- a/lib/clang/include/clang/Basic/Version.inc +++ b/lib/clang/include/clang/Basic/Version.inc @@ -8,4 +8,4 @@ #define CLANG_VENDOR "FreeBSD " -#define SVN_REVISION "305575" +#define SVN_REVISION "306325" diff --git a/lib/clang/include/lld/Config/Version.inc b/lib/clang/include/lld/Config/Version.inc index 8885da9f65c2..01af1fc642a3 100644 --- a/lib/clang/include/lld/Config/Version.inc +++ b/lib/clang/include/lld/Config/Version.inc @@ -4,5 +4,5 @@ #define LLD_VERSION_STRING "5.0.0" #define LLD_VERSION_MAJOR 5 #define LLD_VERSION_MINOR 0 -#define LLD_REVISION_STRING "305575" +#define LLD_REVISION_STRING "306325" #define LLD_REPOSITORY_STRING "FreeBSD" diff --git a/lib/clang/include/llvm/Config/abi-breaking.h b/lib/clang/include/llvm/Config/abi-breaking.h index 7069166cda12..a6976a1ac939 100644 --- a/lib/clang/include/llvm/Config/abi-breaking.h +++ b/lib/clang/include/llvm/Config/abi-breaking.h @@ -16,6 +16,9 @@ /* Define to enable checks that alter the LLVM C++ ABI */ #define LLVM_ENABLE_ABI_BREAKING_CHECKS 1 +/* Define to enable reverse iteration of unordered llvm containers */ +#define LLVM_ENABLE_REVERSE_ITERATION 0 + /* Allow selectively disabling link-time mismatch checking so that header-only ADT content from LLVM can be used without linking libSupport. */ #if !LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING diff --git a/lib/clang/include/llvm/Config/config.h b/lib/clang/include/llvm/Config/config.h index 4a58f3817718..1a0d316a1f00 100644 --- a/lib/clang/include/llvm/Config/config.h +++ b/lib/clang/include/llvm/Config/config.h @@ -358,33 +358,15 @@ /* Host triple LLVM will be executed on */ /* #undef LLVM_HOST_TRIPLE */ -/* LLVM architecture name for the native architecture, if available */ -#define LLVM_NATIVE_ARCH X86 - -/* LLVM name for the native AsmParser init function, if available */ -#define LLVM_NATIVE_ASMPARSER LLVMInitializeX86AsmParser - -/* LLVM name for the native AsmPrinter init function, if available */ -#define LLVM_NATIVE_ASMPRINTER LLVMInitializeX86AsmPrinter - -/* LLVM name for the native Disassembler init function, if available */ -#define LLVM_NATIVE_DISASSEMBLER LLVMInitializeX86Disassembler - -/* LLVM name for the native Target init function, if available */ -#define LLVM_NATIVE_TARGET LLVMInitializeX86Target - -/* LLVM name for the native TargetInfo init function, if available */ -#define LLVM_NATIVE_TARGETINFO LLVMInitializeX86TargetInfo - -/* LLVM name for the native target MC init function, if available */ -#define LLVM_NATIVE_TARGETMC LLVMInitializeX86TargetMC - /* Define if this is Unixish platform */ #define LLVM_ON_UNIX 1 /* Define if this is Win32ish platform */ /* #undef LLVM_ON_WIN32 */ +/* Define if overriding target triple is enabled */ +/* #undef LLVM_TARGET_TRIPLE_ENV */ + /* Define if we have the Intel JIT API runtime support library */ #define LLVM_USE_INTEL_JITEVENTS 0 diff --git a/lib/clang/include/llvm/Support/DataTypes.h b/lib/clang/include/llvm/Support/DataTypes.h index 49b0b7c69910..d48e83df38ef 100644 --- a/lib/clang/include/llvm/Support/DataTypes.h +++ b/lib/clang/include/llvm/Support/DataTypes.h @@ -86,11 +86,11 @@ typedef u_int64_t uint64_t; #else /* _MSC_VER */ #ifdef __cplusplus -#include #include +#include #else -#include #include +#include #endif #include diff --git a/lib/clang/include/llvm/Support/VCSRevision.h b/lib/clang/include/llvm/Support/VCSRevision.h index db36df90bd6b..bb6f7724d130 100644 --- a/lib/clang/include/llvm/Support/VCSRevision.h +++ b/lib/clang/include/llvm/Support/VCSRevision.h @@ -1,2 +1,2 @@ /* $FreeBSD$ */ -#define LLVM_REVISION "svn-r305575" +#define LLVM_REVISION "svn-r306325" diff --git a/lib/clang/libclang/Makefile b/lib/clang/libclang/Makefile index 82d932f5037c..544f7d4596ce 100644 --- a/lib/clang/libclang/Makefile +++ b/lib/clang/libclang/Makefile @@ -228,6 +228,7 @@ SRCS_MIN+= Driver/Tool.cpp SRCS_MIN+= Driver/ToolChain.cpp SRCS_MIN+= Driver/ToolChains/AMDGPU.cpp SRCS_MIN+= Driver/ToolChains/AVR.cpp +SRCS_MIN+= Driver/ToolChains/Ananas.cpp SRCS_MIN+= Driver/ToolChains/Arch/AArch64.cpp SRCS_MIN+= Driver/ToolChains/Arch/ARM.cpp SRCS_MIN+= Driver/ToolChains/Arch/Mips.cpp @@ -281,6 +282,7 @@ SRCS_EXT+= Format/TokenAnalyzer.cpp SRCS_EXT+= Format/TokenAnnotator.cpp SRCS_EXT+= Format/UnwrappedLineFormatter.cpp SRCS_EXT+= Format/UnwrappedLineParser.cpp +SRCS_EXT+= Format/UsingDeclarationsSorter.cpp SRCS_EXT+= Format/WhitespaceManager.cpp SRCS_MIN+= Frontend/ASTConsumers.cpp SRCS_MIN+= Frontend/ASTMerge.cpp @@ -307,6 +309,7 @@ SRCS_MIN+= Frontend/LogDiagnosticPrinter.cpp SRCS_MIN+= Frontend/ModuleDependencyCollector.cpp SRCS_MIN+= Frontend/MultiplexConsumer.cpp SRCS_MIN+= Frontend/PCHContainerOperations.cpp +SRCS_MIN+= Frontend/PrecompiledPreamble.cpp SRCS_MIN+= Frontend/PrintPreprocessedOutput.cpp SRCS_MIN+= Frontend/Rewrite/FixItRewriter.cpp SRCS_MIN+= Frontend/Rewrite/FrontendActions.cpp diff --git a/lib/clang/liblldb/Makefile b/lib/clang/liblldb/Makefile index 331411d307c7..c7981407c830 100644 --- a/lib/clang/liblldb/Makefile +++ b/lib/clang/liblldb/Makefile @@ -245,7 +245,7 @@ SRCS+= Host/posix/HostProcessPosix.cpp SRCS+= Host/posix/HostThreadPosix.cpp SRCS+= Host/posix/LockFilePosix.cpp SRCS+= Host/posix/PipePosix.cpp -SRCS+= Host/posix/ProcessLauncherPosix.cpp +SRCS+= Host/posix/ProcessLauncherPosixFork.cpp SRCS+= Initialization/SystemInitializer.cpp SRCS+= Initialization/SystemInitializerCommon.cpp SRCS+= Initialization/SystemLifetimeManager.cpp @@ -326,7 +326,9 @@ SRCS+= Plugins/Instruction/ARM/EmulationStateARM.cpp SRCS+= Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp SRCS+= Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp SRCS+= Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp -SRCS+= Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.cpp +SRCS+= Plugins/InstrumentationRuntime/ASan/ASanRuntime.cpp +SRCS+= Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp +SRCS+= Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.cpp SRCS+= Plugins/JITLoader/GDB/JITLoaderGDB.cpp SRCS+= Plugins/Language/CPlusPlus/BlockPointer.cpp SRCS+= Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp diff --git a/lib/clang/libllvm/Makefile b/lib/clang/libllvm/Makefile index daebe6ab43c0..585d1f46cca7 100644 --- a/lib/clang/libllvm/Makefile +++ b/lib/clang/libllvm/Makefile @@ -242,6 +242,7 @@ SRCS_MIN+= CodeGen/MachineScheduler.cpp SRCS_MIN+= CodeGen/MachineSink.cpp SRCS_MIN+= CodeGen/MachineTraceMetrics.cpp SRCS_MIN+= CodeGen/MachineVerifier.cpp +SRCS_MIN+= CodeGen/MacroFusion.cpp SRCS_MIN+= CodeGen/OptimizePHIs.cpp SRCS_MIN+= CodeGen/PHIElimination.cpp SRCS_MIN+= CodeGen/PHIEliminationUtils.cpp @@ -288,6 +289,7 @@ SRCS_MIN+= CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp SRCS_MIN+= CodeGen/SelectionDAG/LegalizeVectorOps.cpp SRCS_MIN+= CodeGen/SelectionDAG/LegalizeVectorTypes.cpp SRCS_MIN+= CodeGen/SelectionDAG/ResourcePriorityQueue.cpp +SRCS_MIN+= CodeGen/SelectionDAG/SelectionDAGAddressAnalysis.cpp SRCS_MIN+= CodeGen/SelectionDAG/ScheduleDAGFast.cpp SRCS_MIN+= CodeGen/SelectionDAG/ScheduleDAGRRList.cpp SRCS_MIN+= CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -352,11 +354,10 @@ SRCS_EXT+= DebugInfo/CodeView/StringsAndChecksums.cpp SRCS_MIN+= DebugInfo/CodeView/SymbolDumper.cpp SRCS_MIN+= DebugInfo/CodeView/SymbolRecordMapping.cpp SRCS_EXT+= DebugInfo/CodeView/SymbolSerializer.cpp -SRCS_MIN+= DebugInfo/CodeView/TypeDatabase.cpp -SRCS_MIN+= DebugInfo/CodeView/TypeDatabaseVisitor.cpp SRCS_MIN+= DebugInfo/CodeView/TypeDumpVisitor.cpp SRCS_MIN+= DebugInfo/CodeView/TypeIndex.cpp SRCS_MIN+= DebugInfo/CodeView/TypeIndexDiscovery.cpp +SRCS_MIN+= DebugInfo/CodeView/TypeName.cpp SRCS_MIN+= DebugInfo/CodeView/TypeRecordMapping.cpp SRCS_MIN+= DebugInfo/CodeView/TypeSerializer.cpp SRCS_MIN+= DebugInfo/CodeView/TypeStreamMerger.cpp @@ -603,12 +604,12 @@ SRCS_MIN+= MC/MCTargetOptions.cpp SRCS_MIN+= MC/MCValue.cpp SRCS_MIN+= MC/MCWasmStreamer.cpp SRCS_MIN+= MC/MCWin64EH.cpp +SRCS_MIN+= MC/MCWinCOFFStreamer.cpp SRCS_MIN+= MC/MCWinEH.cpp SRCS_MIN+= MC/MachObjectWriter.cpp SRCS_MIN+= MC/StringTableBuilder.cpp SRCS_MIN+= MC/SubtargetFeature.cpp SRCS_MIN+= MC/WinCOFFObjectWriter.cpp -SRCS_MIN+= MC/WinCOFFStreamer.cpp SRCS_MIN+= Object/Archive.cpp SRCS_MIN+= Object/ArchiveWriter.cpp SRCS_MIN+= Object/Binary.cpp @@ -769,6 +770,7 @@ SRCS_MIN+= Target/AArch64/AArch64AsmPrinter.cpp SRCS_MIN+= Target/AArch64/AArch64CallLowering.cpp SRCS_MIN+= Target/AArch64/AArch64CleanupLocalDynamicTLSPass.cpp SRCS_MIN+= Target/AArch64/AArch64CollectLOH.cpp +SRCS_MIN+= Target/AArch64/AArch64CondBrTuning.cpp SRCS_MIN+= Target/AArch64/AArch64ConditionOptimizer.cpp SRCS_MIN+= Target/AArch64/AArch64ConditionalCompares.cpp SRCS_MIN+= Target/AArch64/AArch64DeadRegisterDefinitionsPass.cpp @@ -830,6 +832,7 @@ SRCS_MIN+= Target/ARM/ARMLegalizerInfo.cpp SRCS_MIN+= Target/ARM/ARMLoadStoreOptimizer.cpp SRCS_MIN+= Target/ARM/ARMMCInstLower.cpp SRCS_MIN+= Target/ARM/ARMMachineFunctionInfo.cpp +SRCS_MIN+= Target/ARM/ARMMacroFusion.cpp SRCS_MIN+= Target/ARM/ARMOptimizeBarriersPass.cpp SRCS_MIN+= Target/ARM/ARMRegisterBankInfo.cpp SRCS_MIN+= Target/ARM/ARMRegisterInfo.cpp @@ -1127,7 +1130,6 @@ SRCS_MIN+= Transforms/Scalar/InductiveRangeCheckElimination.cpp SRCS_EXT+= Transforms/Scalar/InferAddressSpaces.cpp SRCS_MIN+= Transforms/Scalar/JumpThreading.cpp SRCS_MIN+= Transforms/Scalar/LICM.cpp -SRCS_MIN+= Transforms/Scalar/LoadCombine.cpp SRCS_MIN+= Transforms/Scalar/LoopAccessAnalysisPrinter.cpp SRCS_MIN+= Transforms/Scalar/LoopDataPrefetch.cpp SRCS_MIN+= Transforms/Scalar/LoopDeletion.cpp diff --git a/usr.bin/clang/lld/Makefile b/usr.bin/clang/lld/Makefile index b57ed426f3f9..1252913b136d 100644 --- a/usr.bin/clang/lld/Makefile +++ b/usr.bin/clang/lld/Makefile @@ -23,6 +23,7 @@ SRCS+= ELF/Arch/AMDGPU.cpp SRCS+= ELF/Arch/ARM.cpp SRCS+= ELF/Arch/AVR.cpp SRCS+= ELF/Arch/Mips.cpp +SRCS+= ELF/Arch/MipsArchTree.cpp SRCS+= ELF/Arch/PPC.cpp SRCS+= ELF/Arch/PPC64.cpp SRCS+= ELF/Arch/X86.cpp @@ -40,7 +41,6 @@ SRCS+= ELF/LTO.cpp SRCS+= ELF/LinkerScript.cpp SRCS+= ELF/MapFile.cpp SRCS+= ELF/MarkLive.cpp -SRCS+= ELF/Mips.cpp SRCS+= ELF/OutputSections.cpp SRCS+= ELF/Relocations.cpp SRCS+= ELF/ScriptLexer.cpp diff --git a/usr.bin/clang/llvm-pdbutil/Makefile b/usr.bin/clang/llvm-pdbutil/Makefile index 25908b17015f..46b6de22c7b1 100644 --- a/usr.bin/clang/llvm-pdbutil/Makefile +++ b/usr.bin/clang/llvm-pdbutil/Makefile @@ -5,8 +5,9 @@ MAN= SRCDIR= tools/llvm-pdbutil SRCS+= Analyze.cpp -SRCS+= CompactTypeDumpVisitor.cpp +SRCS+= BytesOutputStyle.cpp SRCS+= Diff.cpp +SRCS+= DumpOutputStyle.cpp SRCS+= FormatUtil.cpp SRCS+= LinePrinter.cpp SRCS+= MinimalSymbolDumper.cpp @@ -22,7 +23,6 @@ SRCS+= PrettyFunctionDumper.cpp SRCS+= PrettyTypeDumper.cpp SRCS+= PrettyTypedefDumper.cpp SRCS+= PrettyVariableDumper.cpp -SRCS+= RawOutputStyle.cpp SRCS+= StreamUtil.cpp SRCS+= YAMLOutputStyle.cpp SRCS+= llvm-pdbutil.cpp