Merge llvm, clang, lld, lldb, compiler-rt and libc++ r304659, and update

build glue.
This commit is contained in:
Dimitry Andric 2017-06-03 18:18:34 +00:00
commit 6d97bb297c
278 changed files with 6101 additions and 3329 deletions
contrib
compiler-rt
libc++/include
llvm
include/llvm
lib

@ -19,8 +19,6 @@
extern "C" {
#endif
// Initialize coverage.
void __sanitizer_cov_init();
// Record and dump coverage info.
void __sanitizer_cov_dump();
@ -28,10 +26,6 @@ extern "C" {
// .sancov files.
void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len);
// Open <name>.sancov.packed in the coverage directory and return the file
// descriptor. Returns -1 on failure, or if coverage dumping is disabled.
// This is intended for use by sandboxing code.
intptr_t __sanitizer_maybe_open_cov_file(const char *name);
#ifdef __cplusplus
} // extern "C"
#endif

@ -106,7 +106,6 @@ void AsanDeactivate() {
// Deactivate the runtime.
SetCanPoisonMemory(false);
SetMallocContextSize(1);
ReInitializeCoverage(false, nullptr);
AllocatorOptions disabled = asan_deactivated_flags.allocator_options;
disabled.quarantine_size_mb = 0;
@ -130,8 +129,6 @@ void AsanActivate() {
SetCanPoisonMemory(asan_deactivated_flags.poison_heap);
SetMallocContextSize(asan_deactivated_flags.malloc_context_size);
ReInitializeCoverage(asan_deactivated_flags.coverage,
asan_deactivated_flags.coverage_dir);
ReInitializeAllocator(asan_deactivated_flags.allocator_options);
asan_is_deactivated = false;

@ -242,9 +242,8 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
CheckNoDeepBind(filename, flag); \
} while (false)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
CoverageUpdateMapping()
#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping()
#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
if (AsanThread *t = GetCurrentThread()) { \
@ -723,9 +722,7 @@ static void AfterFork() {
INTERCEPTOR(int, fork, void) {
ENSURE_ASAN_INITED();
BeforeFork();
if (common_flags()->coverage) CovBeforeFork();
int pid = REAL(fork)();
if (common_flags()->coverage) CovAfterFork(pid);
AfterFork();
return pid;
}

@ -166,16 +166,19 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save,
}
inline AsanThread::StackBounds AsanThread::GetStackBounds() const {
if (!atomic_load(&stack_switching_, memory_order_acquire))
return StackBounds{stack_bottom_, stack_top_}; // NOLINT
if (!atomic_load(&stack_switching_, memory_order_acquire)) {
// Make sure the stack bounds are fully initialized.
if (stack_bottom_ >= stack_top_) return {0, 0};
return {stack_bottom_, stack_top_};
}
char local;
const uptr cur_stack = (uptr)&local;
// Note: need to check next stack first, because FinishSwitchFiber
// may be in process of overwriting stack_top_/bottom_. But in such case
// we are already on the next stack.
if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT
return StackBounds{stack_bottom_, stack_top_}; // NOLINT
return {next_stack_bottom_, next_stack_top_};
return {stack_bottom_, stack_top_};
}
uptr AsanThread::stack_top() {
@ -197,6 +200,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
uptr stack_size = this->stack_size();
if (stack_size == 0) // stack_size is not yet available, don't use FakeStack.
return nullptr;
CHECK_LE(stack_size, 0x10000000);
uptr old_val = 0;
// fake_stack_ has 3 states:
// 0 -- not initialized

@ -408,6 +408,9 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) {
// On Linux, handles dynamically allocated TLS blocks by treating all chunks
// allocated from ld-linux.so as reachable.
// On Linux, treats all chunks allocated from ld-linux.so as reachable, which
// covers dynamically allocated TLS blocks, internal dynamic loader's loaded
// modules accounting etc.
// Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
// They are allocated with a __libc_memalign() call in allocate_and_init()
// (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those

@ -23,6 +23,10 @@
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#if SANITIZER_USE_GETAUXVAL
#include <sys/auxv.h>
#endif // SANITIZER_USE_GETAUXVAL
namespace __lsan {
static const char kLinkerName[] = "ld";
@ -30,8 +34,12 @@ static const char kLinkerName[] = "ld";
static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
static LoadedModule *linker = nullptr;
static bool IsLinker(const char* full_name) {
return LibraryNameIs(full_name, kLinkerName);
static bool IsLinker(const LoadedModule& module) {
#if SANITIZER_USE_GETAUXVAL
return module.base_address() == getauxval(AT_BASE);
#else
return LibraryNameIs(module.full_name(), kLinkerName);
#endif // SANITIZER_USE_GETAUXVAL
}
__attribute__((tls_model("initial-exec")))
@ -49,22 +57,25 @@ void InitializePlatformSpecificModules() {
ListOfModules modules;
modules.init();
for (LoadedModule &module : modules) {
if (!IsLinker(module.full_name())) continue;
if (!IsLinker(module))
continue;
if (linker == nullptr) {
linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
*linker = module;
module = LoadedModule();
} else {
VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
"TLS will not be handled correctly.\n", kLinkerName);
"TLS and other allocations originating from linker might be "
"falsely reported as leaks.\n", kLinkerName);
linker->clear();
linker = nullptr;
return;
}
}
if (linker == nullptr) {
VReport(1, "LeakSanitizer: Dynamic linker not found. "
"TLS will not be handled correctly.\n");
VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other "
"allocations originating from linker might be falsely reported "
"as leaks.\n");
}
}

@ -317,15 +317,9 @@ bool AddressSpaceIsUnlimited();
void SetAddressSpaceUnlimited();
void AdjustStackSize(void *attr);
void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
void SetSandboxingCallback(void (*f)());
void CoverageUpdateMapping();
void CovBeforeFork();
void CovAfterFork(int child_pid);
void InitializeCoverage(bool enabled, const char *coverage_dir);
void ReInitializeCoverage(bool enabled, const char *coverage_dir);
void InitTlsSize();
uptr GetTlsSize();

@ -11,7 +11,6 @@
INTERFACE_FUNCTION(__sanitizer_cov_dump)
INTERFACE_FUNCTION(__sanitizer_dump_coverage)
INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage)
INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
INTERFACE_WEAK_FUNCTION(__sancov_default_options)
INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp)
INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1)

@ -1,627 +0,0 @@
//===-- sanitizer_coverage.cc ---------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Sanitizer Coverage.
// This file implements run-time support for a poor man's coverage tool.
//
// Compiler instrumentation:
// For every interesting basic block the compiler injects the following code:
// if (Guard < 0) {
// __sanitizer_cov(&Guard);
// }
// At the module start up time __sanitizer_cov_module_init sets the guards
// to consecutive negative numbers (-1, -2, -3, ...).
// It's fine to call __sanitizer_cov more than once for a given block.
//
// Run-time:
// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC).
// and atomically set Guard to -Guard.
// - __sanitizer_cov_dump: dump the coverage data to disk.
// For every module of the current process that has coverage data
// this will create a file module_name.PID.sancov.
//
// The file format is simple: the first 8 bytes is the magic,
// one of 0xC0BFFFFFFFFFFF64 and 0xC0BFFFFFFFFFFF32. The last byte of the
// magic defines the size of the following offsets.
// The rest of the data is the offsets in the module.
//
// Eventually, this coverage implementation should be obsoleted by a more
// powerful general purpose Clang/LLVM coverage instrumentation.
// Consider this implementation as prototype.
//
// FIXME: support (or at least test with) dlclose.
//===----------------------------------------------------------------------===//
#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
#include "sanitizer_libc.h"
#include "sanitizer_mutex.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
#include "sanitizer_flags.h"
using namespace __sanitizer;
static const u64 kMagic64 = 0xC0BFFFFFFFFFFF64ULL;
static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL;
static const uptr kNumWordsForMagic = SANITIZER_WORDSIZE == 64 ? 1 : 2;
static const u64 kMagic = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32;
static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
static atomic_uintptr_t coverage_counter;
// pc_array is the array containing the covered PCs.
// To make the pc_array thread- and async-signal-safe it has to be large enough.
// 128M counters "ought to be enough for anybody" (4M on 32-bit).
// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file.
// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping()
// dump current memory layout to another file.
static bool cov_sandboxed = false;
static fd_t cov_fd = kInvalidFd;
static unsigned int cov_max_block_size = 0;
static bool coverage_enabled = false;
static const char *coverage_dir;
namespace __sanitizer {
class CoverageData {
public:
void Init();
void Enable();
void Disable();
void ReInit();
void BeforeFork();
void AfterFork(int child_pid);
void Extend(uptr npcs);
void Add(uptr pc, u32 *guard);
void DumpOffsets();
void DumpAll();
void InitializeGuardArray(s32 *guards);
void InitializeGuards(s32 *guards, uptr n, const char *module_name,
uptr caller_pc);
void ReinitializeGuards();
uptr *data();
uptr size() const;
private:
struct NamedPcRange {
const char *copied_module_name;
uptr beg, end; // elements [beg,end) in pc_array.
};
void DirectOpen();
void UpdateModuleNameVec(uptr caller_pc, uptr range_beg, uptr range_end);
void GetRangeOffsets(const NamedPcRange& r, Symbolizer* s,
InternalMmapVector<uptr>* offsets) const;
// Maximal size pc array may ever grow.
// We MmapNoReserve this space to ensure that the array is contiguous.
static const uptr kPcArrayMaxSize =
FIRST_32_SECOND_64(1 << (SANITIZER_ANDROID ? 24 : 26), 1 << 27);
// The amount file mapping for the pc array is grown by.
static const uptr kPcArrayMmapSize = 64 * 1024;
// pc_array is allocated with MmapNoReserveOrDie and so it uses only as
// much RAM as it really needs.
uptr *pc_array;
// Index of the first available pc_array slot.
atomic_uintptr_t pc_array_index;
// Array size.
atomic_uintptr_t pc_array_size;
// Current file mapped size of the pc array.
uptr pc_array_mapped_size;
// Descriptor of the file mapped pc array.
fd_t pc_fd;
// Vector of coverage guard arrays, protected by mu.
InternalMmapVectorNoCtor<s32*> guard_array_vec;
// Vector of module and compilation unit pc ranges.
InternalMmapVectorNoCtor<NamedPcRange> comp_unit_name_vec;
InternalMmapVectorNoCtor<NamedPcRange> module_name_vec;
StaticSpinMutex mu;
};
static CoverageData coverage_data;
void CovUpdateMapping(const char *path, uptr caller_pc = 0);
void CoverageData::DirectOpen() {
InternalScopedString path(kMaxPathLength);
internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw",
coverage_dir, internal_getpid());
pc_fd = OpenFile(path.data(), RdWr);
if (pc_fd == kInvalidFd) {
Report("Coverage: failed to open %s for reading/writing\n", path.data());
Die();
}
pc_array_mapped_size = 0;
CovUpdateMapping(coverage_dir);
}
void CoverageData::Init() {
pc_fd = kInvalidFd;
}
void CoverageData::Enable() {
if (pc_array)
return;
pc_array = reinterpret_cast<uptr *>(
MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit"));
atomic_store(&pc_array_index, 0, memory_order_relaxed);
if (common_flags()->coverage_direct) {
Report("coverage_direct=1 is deprecated, don't use it.\n");
Die();
atomic_store(&pc_array_size, 0, memory_order_relaxed);
} else {
atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
}
}
void CoverageData::InitializeGuardArray(s32 *guards) {
Enable(); // Make sure coverage is enabled at this point.
s32 n = guards[0];
for (s32 j = 1; j <= n; j++) {
uptr idx = atomic_load_relaxed(&pc_array_index);
atomic_store_relaxed(&pc_array_index, idx + 1);
guards[j] = -static_cast<s32>(idx + 1);
}
}
void CoverageData::Disable() {
if (pc_array) {
UnmapOrDie(pc_array, sizeof(uptr) * kPcArrayMaxSize);
pc_array = nullptr;
}
if (pc_fd != kInvalidFd) {
CloseFile(pc_fd);
pc_fd = kInvalidFd;
}
}
void CoverageData::ReinitializeGuards() {
// Assuming single thread.
atomic_store(&pc_array_index, 0, memory_order_relaxed);
for (uptr i = 0; i < guard_array_vec.size(); i++)
InitializeGuardArray(guard_array_vec[i]);
}
void CoverageData::ReInit() {
Disable();
if (coverage_enabled) {
if (common_flags()->coverage_direct) {
// In memory-mapped mode we must extend the new file to the known array
// size.
uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
uptr npcs = size / sizeof(uptr);
Enable();
if (size) Extend(npcs);
if (coverage_enabled) CovUpdateMapping(coverage_dir);
} else {
Enable();
}
}
// Re-initialize the guards.
// We are single-threaded now, no need to grab any lock.
CHECK_EQ(atomic_load(&pc_array_index, memory_order_relaxed), 0);
ReinitializeGuards();
}
void CoverageData::BeforeFork() {
mu.Lock();
}
void CoverageData::AfterFork(int child_pid) {
// We are single-threaded so it's OK to release the lock early.
mu.Unlock();
if (child_pid == 0) ReInit();
}
// Extend coverage PC array to fit additional npcs elements.
void CoverageData::Extend(uptr npcs) {
if (!common_flags()->coverage_direct) return;
SpinMutexLock l(&mu);
uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
size += npcs * sizeof(uptr);
if (coverage_enabled && size > pc_array_mapped_size) {
if (pc_fd == kInvalidFd) DirectOpen();
CHECK_NE(pc_fd, kInvalidFd);
uptr new_mapped_size = pc_array_mapped_size;
while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize;
CHECK_LE(new_mapped_size, sizeof(uptr) * kPcArrayMaxSize);
// Extend the file and map the new space at the end of pc_array.
uptr res = internal_ftruncate(pc_fd, new_mapped_size);
int err;
if (internal_iserror(res, &err)) {
Printf("failed to extend raw coverage file: %d\n", err);
Die();
}
uptr next_map_base = ((uptr)pc_array) + pc_array_mapped_size;
void *p = MapWritableFileToMemory((void *)next_map_base,
new_mapped_size - pc_array_mapped_size,
pc_fd, pc_array_mapped_size);
CHECK_EQ((uptr)p, next_map_base);
pc_array_mapped_size = new_mapped_size;
}
atomic_store(&pc_array_size, size, memory_order_release);
}
void CoverageData::UpdateModuleNameVec(uptr caller_pc, uptr range_beg,
uptr range_end) {
auto sym = Symbolizer::GetOrInit();
if (!sym)
return;
const char *module_name = sym->GetModuleNameForPc(caller_pc);
if (!module_name) return;
if (module_name_vec.empty() ||
module_name_vec.back().copied_module_name != module_name)
module_name_vec.push_back({module_name, range_beg, range_end});
else
module_name_vec.back().end = range_end;
}
void CoverageData::InitializeGuards(s32 *guards, uptr n,
const char *comp_unit_name,
uptr caller_pc) {
// The array 'guards' has n+1 elements, we use the element zero
// to store 'n'.
CHECK_LT(n, 1 << 30);
guards[0] = static_cast<s32>(n);
InitializeGuardArray(guards);
SpinMutexLock l(&mu);
uptr range_end = atomic_load(&pc_array_index, memory_order_relaxed);
uptr range_beg = range_end - n;
comp_unit_name_vec.push_back({comp_unit_name, range_beg, range_end});
guard_array_vec.push_back(guards);
UpdateModuleNameVec(caller_pc, range_beg, range_end);
}
static const uptr kBundleCounterBits = 16;
// When coverage_order_pcs==true and SANITIZER_WORDSIZE==64
// we insert the global counter into the first 16 bits of the PC.
uptr BundlePcAndCounter(uptr pc, uptr counter) {
if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
return pc;
static const uptr kMaxCounter = (1 << kBundleCounterBits) - 1;
if (counter > kMaxCounter)
counter = kMaxCounter;
CHECK_EQ(0, pc >> (SANITIZER_WORDSIZE - kBundleCounterBits));
return pc | (counter << (SANITIZER_WORDSIZE - kBundleCounterBits));
}
uptr UnbundlePc(uptr bundle) {
if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
return bundle;
return (bundle << kBundleCounterBits) >> kBundleCounterBits;
}
uptr UnbundleCounter(uptr bundle) {
if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
return 0;
return bundle >> (SANITIZER_WORDSIZE - kBundleCounterBits);
}
// If guard is negative, atomically set it to -guard and store the PC in
// pc_array.
void CoverageData::Add(uptr pc, u32 *guard) {
atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard);
s32 guard_value = atomic_load(atomic_guard, memory_order_relaxed);
if (guard_value >= 0) return;
atomic_store(atomic_guard, -guard_value, memory_order_relaxed);
if (!pc_array) return;
uptr idx = -guard_value - 1;
if (idx >= atomic_load(&pc_array_index, memory_order_acquire))
return; // May happen after fork when pc_array_index becomes 0.
CHECK_LT(idx, atomic_load(&pc_array_size, memory_order_acquire));
uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
pc_array[idx] = BundlePcAndCounter(pc, counter);
}
uptr *CoverageData::data() {
return pc_array;
}
uptr CoverageData::size() const {
return atomic_load(&pc_array_index, memory_order_relaxed);
}
// Block layout for packed file format: header, followed by module name (no
// trailing zero), followed by data blob.
struct CovHeader {
int pid;
unsigned int module_name_length;
unsigned int data_length;
};
static void CovWritePacked(int pid, const char *module, const void *blob,
unsigned int blob_size) {
if (cov_fd == kInvalidFd) return;
unsigned module_name_length = internal_strlen(module);
CovHeader header = {pid, module_name_length, blob_size};
if (cov_max_block_size == 0) {
// Writing to a file. Just go ahead.
WriteToFile(cov_fd, &header, sizeof(header));
WriteToFile(cov_fd, module, module_name_length);
WriteToFile(cov_fd, blob, blob_size);
} else {
// Writing to a socket. We want to split the data into appropriately sized
// blocks.
InternalScopedBuffer<char> block(cov_max_block_size);
CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data());
uptr header_size_with_module = sizeof(header) + module_name_length;
CHECK_LT(header_size_with_module, cov_max_block_size);
unsigned int max_payload_size =
cov_max_block_size - header_size_with_module;
char *block_pos = block.data();
internal_memcpy(block_pos, &header, sizeof(header));
block_pos += sizeof(header);
internal_memcpy(block_pos, module, module_name_length);
block_pos += module_name_length;
char *block_data_begin = block_pos;
const char *blob_pos = (const char *)blob;
while (blob_size > 0) {
unsigned int payload_size = Min(blob_size, max_payload_size);
blob_size -= payload_size;
internal_memcpy(block_data_begin, blob_pos, payload_size);
blob_pos += payload_size;
((CovHeader *)block.data())->data_length = payload_size;
WriteToFile(cov_fd, block.data(), header_size_with_module + payload_size);
}
}
}
// If packed = false: <name>.<pid>.<sancov> (name = module name).
// If packed = true and name == 0: <pid>.<sancov>.<packed>.
// If packed = true and name != 0: <name>.<sancov>.<packed> (name is
// user-supplied).
static fd_t CovOpenFile(InternalScopedString *path, bool packed,
const char *name, const char *extension = "sancov") {
path->clear();
if (!packed) {
CHECK(name);
path->append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(),
extension);
} else {
if (!name)
path->append("%s/%zd.%s.packed", coverage_dir, internal_getpid(),
extension);
else
path->append("%s/%s.%s.packed", coverage_dir, name, extension);
}
error_t err;
fd_t fd = OpenFile(path->data(), WrOnly, &err);
if (fd == kInvalidFd)
Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n",
path->data(), err);
return fd;
}
void CoverageData::GetRangeOffsets(const NamedPcRange& r, Symbolizer* sym,
InternalMmapVector<uptr>* offsets) const {
offsets->clear();
for (uptr i = 0; i < kNumWordsForMagic; i++)
offsets->push_back(0);
CHECK(r.copied_module_name);
CHECK_LE(r.beg, r.end);
CHECK_LE(r.end, size());
for (uptr i = r.beg; i < r.end; i++) {
uptr pc = UnbundlePc(pc_array[i]);
uptr counter = UnbundleCounter(pc_array[i]);
if (!pc) continue; // Not visited.
uptr offset = 0;
sym->GetModuleNameAndOffsetForPC(pc, nullptr, &offset);
offsets->push_back(BundlePcAndCounter(offset, counter));
}
CHECK_GE(offsets->size(), kNumWordsForMagic);
SortArray(offsets->data(), offsets->size());
for (uptr i = 0; i < offsets->size(); i++)
(*offsets)[i] = UnbundlePc((*offsets)[i]);
}
static void GenerateHtmlReport(const InternalMmapVector<char *> &cov_files) {
if (!common_flags()->html_cov_report) {
return;
}
char *sancov_path = FindPathToBinary(common_flags()->sancov_path);
if (sancov_path == nullptr) {
return;
}
InternalMmapVector<char *> sancov_argv(cov_files.size() * 2 + 3);
sancov_argv.push_back(sancov_path);
sancov_argv.push_back(internal_strdup("-html-report"));
auto argv_deleter = at_scope_exit([&] {
for (uptr i = 0; i < sancov_argv.size(); ++i) {
InternalFree(sancov_argv[i]);
}
});
for (const auto &cov_file : cov_files) {
sancov_argv.push_back(internal_strdup(cov_file));
}
{
ListOfModules modules;
modules.init();
for (const LoadedModule &module : modules) {
sancov_argv.push_back(internal_strdup(module.full_name()));
}
}
InternalScopedString report_path(kMaxPathLength);
fd_t report_fd =
CovOpenFile(&report_path, false /* packed */, GetProcessName(), "html");
int pid = StartSubprocess(sancov_argv[0], sancov_argv.data(),
kInvalidFd /* stdin */, report_fd /* std_out */);
if (pid > 0) {
int result = WaitForProcess(pid);
if (result == 0)
Printf("coverage report generated to %s\n", report_path.data());
}
}
void CoverageData::DumpOffsets() {
auto sym = Symbolizer::GetOrInit();
if (!common_flags()->coverage_pcs) return;
Printf("**\n***\n***\n");
Printf("**WARNING: this implementation of SanitizerCoverage is deprecated\n");
Printf("**WARNING: and will be removed in future versions\n");
Printf("**WARNING: See https://clang.llvm.org/docs/SanitizerCoverage.html\n");
Printf("**\n***\n***\n");
CHECK_NE(sym, nullptr);
InternalMmapVector<uptr> offsets(0);
InternalScopedString path(kMaxPathLength);
InternalMmapVector<char *> cov_files(module_name_vec.size());
auto cov_files_deleter = at_scope_exit([&] {
for (uptr i = 0; i < cov_files.size(); ++i) {
InternalFree(cov_files[i]);
}
});
for (uptr m = 0; m < module_name_vec.size(); m++) {
auto r = module_name_vec[m];
GetRangeOffsets(r, sym, &offsets);
uptr num_offsets = offsets.size() - kNumWordsForMagic;
u64 *magic_p = reinterpret_cast<u64*>(offsets.data());
CHECK_EQ(*magic_p, 0ULL);
// FIXME: we may want to write 32-bit offsets even in 64-mode
// if all the offsets are small enough.
*magic_p = kMagic;
const char *module_name = StripModuleName(r.copied_module_name);
if (cov_sandboxed) {
if (cov_fd != kInvalidFd) {
CovWritePacked(internal_getpid(), module_name, offsets.data(),
offsets.size() * sizeof(offsets[0]));
VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets);
}
} else {
// One file per module per process.
fd_t fd = CovOpenFile(&path, false /* packed */, module_name);
if (fd == kInvalidFd) continue;
WriteToFile(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
CloseFile(fd);
cov_files.push_back(internal_strdup(path.data()));
VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets);
}
}
if (cov_fd != kInvalidFd)
CloseFile(cov_fd);
GenerateHtmlReport(cov_files);
}
void CoverageData::DumpAll() {
if (!coverage_enabled || common_flags()->coverage_direct) return;
if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
return;
DumpOffsets();
}
void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
if (!args) return;
if (!coverage_enabled) return;
cov_sandboxed = args->coverage_sandboxed;
if (!cov_sandboxed) return;
cov_max_block_size = args->coverage_max_block_size;
if (args->coverage_fd >= 0) {
cov_fd = (fd_t)args->coverage_fd;
} else {
InternalScopedString path(kMaxPathLength);
// Pre-open the file now. The sandbox won't allow us to do it later.
cov_fd = CovOpenFile(&path, true /* packed */, nullptr);
}
}
fd_t MaybeOpenCovFile(const char *name) {
CHECK(name);
if (!coverage_enabled) return kInvalidFd;
InternalScopedString path(kMaxPathLength);
return CovOpenFile(&path, true /* packed */, name);
}
void CovBeforeFork() {
coverage_data.BeforeFork();
}
void CovAfterFork(int child_pid) {
coverage_data.AfterFork(child_pid);
}
static void MaybeDumpCoverage() {
if (common_flags()->coverage)
__sanitizer_cov_dump();
}
void InitializeCoverage(bool enabled, const char *dir) {
if (coverage_enabled)
return; // May happen if two sanitizer enable coverage in the same process.
coverage_enabled = enabled;
coverage_dir = dir;
coverage_data.Init();
if (enabled) coverage_data.Enable();
if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump);
AddDieCallback(MaybeDumpCoverage);
}
void ReInitializeCoverage(bool enabled, const char *dir) {
coverage_enabled = enabled;
coverage_dir = dir;
coverage_data.ReInit();
}
void CoverageUpdateMapping() {
if (coverage_enabled)
CovUpdateMapping(coverage_dir);
}
} // namespace __sanitizer
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() {
__sanitizer_dump_trace_pc_guard_coverage();
}
SANITIZER_INTERFACE_ATTRIBUTE
sptr __sanitizer_maybe_open_cov_file(const char *name) {
return (sptr)MaybeOpenCovFile(name);
}
// Default empty implementations (weak). Users should redefine them.
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
} // extern "C"

@ -146,6 +146,17 @@ static TracePcGuardController pc_guard_controller;
} // namespace
} // namespace __sancov
namespace __sanitizer {
void InitializeCoverage(bool enabled, const char *dir) {
static bool coverage_enabled = false;
if (coverage_enabled)
return; // May happen if two sanitizer enable coverage in the same process.
coverage_enabled = enabled;
Atexit(__sanitizer_cov_dump);
AddDieCallback(__sanitizer_cov_dump);
}
} // namespace __sanitizer
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT
const uptr* pcs, uptr len) {
@ -166,4 +177,18 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init,
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() {
__sancov::pc_guard_controller.Dump();
}
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() {
__sanitizer_dump_trace_pc_guard_coverage();
}
// Default empty implementations (weak). Users should redefine them.
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
} // extern "C"

@ -1,122 +0,0 @@
//===-- sanitizer_coverage_mapping.cc -------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Mmap-based implementation of sanitizer coverage.
//
// This is part of the implementation of code coverage that does not require
// __sanitizer_cov_dump() call. Data is stored in 2 files per process.
//
// $pid.sancov.map describes process memory layout in the following text-based
// format:
// <pointer size in bits> // 1 line, 32 or 64
// <mapping start> <mapping end> <base address> <dso name> // repeated
// ...
// Mapping lines are NOT sorted. This file is updated every time memory layout
// is changed (i.e. in dlopen() and dlclose() interceptors).
//
// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not
// sorted. This file is extended by 64Kb at a time and mapped into memory. It
// contains one or more 0 words at the end, up to the next 64Kb aligned offset.
//
// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack
// $pid.sancov.raw.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_allocator_internal.h"
#include "sanitizer_libc.h"
#include "sanitizer_procmaps.h"
namespace __sanitizer {
static const uptr kMaxTextSize = 64 * 1024;
struct CachedMapping {
public:
bool NeedsUpdate(uptr pc) {
int new_pid = internal_getpid();
if (last_pid == new_pid && pc && pc >= last_range_start &&
pc < last_range_end)
return false;
last_pid = new_pid;
return true;
}
void SetModuleRange(uptr start, uptr end) {
last_range_start = start;
last_range_end = end;
}
private:
uptr last_range_start, last_range_end;
int last_pid;
};
static CachedMapping cached_mapping;
static StaticSpinMutex mapping_mu;
void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) {
if (!common_flags()->coverage_direct) return;
SpinMutexLock l(&mapping_mu);
if (!cached_mapping.NeedsUpdate(caller_pc))
return;
InternalScopedString text(kMaxTextSize);
{
text.append("%d\n", sizeof(uptr) * 8);
ListOfModules modules;
modules.init();
for (const LoadedModule &module : modules) {
const char *module_name = StripModuleName(module.full_name());
uptr base = module.base_address();
for (const auto &range : module.ranges()) {
if (range.executable) {
uptr start = range.beg;
uptr end = range.end;
text.append("%zx %zx %zx %s\n", start, end, base, module_name);
if (caller_pc && caller_pc >= start && caller_pc < end)
cached_mapping.SetModuleRange(start, end);
}
}
}
}
error_t err;
InternalScopedString tmp_path(64 + internal_strlen(coverage_dir));
uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(),
"%s/%zd.sancov.map.tmp", coverage_dir,
internal_getpid());
CHECK_LE(res, tmp_path.size());
fd_t map_fd = OpenFile(tmp_path.data(), WrOnly, &err);
if (map_fd == kInvalidFd) {
Report("Coverage: failed to open %s for writing: %d\n", tmp_path.data(),
err);
Die();
}
if (!WriteToFile(map_fd, text.data(), text.length(), nullptr, &err)) {
Printf("sancov.map write failed: %d\n", err);
Die();
}
CloseFile(map_fd);
InternalScopedString path(64 + internal_strlen(coverage_dir));
res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map",
coverage_dir, internal_getpid());
CHECK_LE(res, path.size());
if (!RenameFile(tmp_path.data(), path.data(), &err)) {
Printf("sancov.map rename failed: %d\n", err);
Die();
}
}
} // namespace __sanitizer

@ -138,16 +138,6 @@ COMMON_FLAG(
bool, coverage, false,
"If set, coverage information will be dumped at program shutdown (if the "
"coverage instrumentation was enabled at compile time).")
COMMON_FLAG(bool, coverage_pcs, true,
"If set (and if 'coverage' is set too), the coverage information "
"will be dumped as a set of PC offsets for every module.")
COMMON_FLAG(bool, coverage_order_pcs, false,
"If true, the PCs will be dumped in the order they've"
" appeared during the execution.")
COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID,
"If set, coverage information will be dumped directly to a memory "
"mapped file. This way data is not lost even if the process is "
"suddenly killed.")
COMMON_FLAG(const char *, coverage_dir, ".",
"Target directory for coverage dumps. Defaults to the current "
"directory.")

@ -75,16 +75,6 @@ extern char **environ; // provided by crt1
#include <sys/signal.h>
#endif
#ifndef __GLIBC_PREREQ
#define __GLIBC_PREREQ(x, y) 0
#endif
#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16)
# define SANITIZER_USE_GETAUXVAL 1
#else
# define SANITIZER_USE_GETAUXVAL 0
#endif
#if SANITIZER_USE_GETAUXVAL
#include <sys/auxv.h>
#endif

@ -269,5 +269,14 @@
# define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0
#endif
#ifndef __GLIBC_PREREQ
#define __GLIBC_PREREQ(x, y) 0
#endif
#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16)
# define SANITIZER_USE_GETAUXVAL 1
#else
# define SANITIZER_USE_GETAUXVAL 0
#endif
#endif // SANITIZER_PLATFORM_H

@ -23,6 +23,9 @@
// incorporates the map structure.
# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544)))
// Get sys/_types.h, because that tells us whether 64-bit inodes are
// used in struct dirent below.
#include <sys/_types.h>
#else
# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle))
#endif // !SANITIZER_FREEBSD
@ -489,8 +492,12 @@ namespace __sanitizer {
};
#elif SANITIZER_FREEBSD
struct __sanitizer_dirent {
#if defined(__INO64)
unsigned long long d_fileno;
unsigned long long d_off;
#else
unsigned int d_fileno;
#endif
unsigned short d_reclen;
// more fields that we don't care about
};

@ -264,7 +264,6 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
// Same for /proc/self/exe in the symbolizer.
#if !SANITIZER_GO
Symbolizer::GetOrInit()->PrepareForSandboxing();
CovPrepareForSandboxing(args);
#endif
}

@ -400,9 +400,6 @@ void ReExec() {
}
void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
#if !SANITIZER_GO
CovPrepareForSandboxing(args);
#endif
}
bool StackSizeIsUnlimited() {

@ -19,6 +19,7 @@
UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined")
UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null")
UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow")
UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment")
UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size")
UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow",

@ -554,6 +554,37 @@ void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) {
Die();
}
static void handlePointerOverflowImpl(PointerOverflowData *Data,
ValueHandle Base,
ValueHandle Result,
ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
ErrorType ET = ErrorType::PointerOverflow;
if (ignoreReport(Loc, Opts, ET))
return;
ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error, "pointer index expression with base %0 overflowed to %1")
<< (void *)Base << (void*)Result;
}
void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data,
ValueHandle Base,
ValueHandle Result) {
GET_REPORT_OPTIONS(false);
handlePointerOverflowImpl(Data, Base, Result, Opts);
}
void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data,
ValueHandle Base,
ValueHandle Result) {
GET_REPORT_OPTIONS(true);
handlePointerOverflowImpl(Data, Base, Result, Opts);
Die();
}
static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,
ReportOptions Opts) {
if (Data->CheckKind != CFITCK_ICall)

@ -152,6 +152,13 @@ struct NonNullArgData {
RECOVERABLE(nonnull_arg, NonNullArgData *Data)
RECOVERABLE(nullability_arg, NonNullArgData *Data)
struct PointerOverflowData {
SourceLocation Loc;
};
RECOVERABLE(pointer_overflow, PointerOverflowData *Data, ValueHandle Base,
ValueHandle Result)
/// \brief Known CFI check kinds.
/// Keep in sync with the enum of the same name in CodeGenFunction.h
enum CFITypeCheckKind : unsigned char {

@ -36,6 +36,8 @@ INTERFACE_FUNCTION(__ubsan_handle_nullability_return)
INTERFACE_FUNCTION(__ubsan_handle_nullability_return_abort)
INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds)
INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort)
INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow)
INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow_abort)
INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds)
INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds_abort)
INTERFACE_FUNCTION(__ubsan_handle_sub_overflow)

@ -137,7 +137,7 @@ inline _LIBCPP_INLINE_VISIBILITY
size_t
__next_hash_pow2(size_t __n)
{
return size_t(1) << (std::numeric_limits<size_t>::digits - __clz(__n-1));
return __n < 2 ? __n : (size_t(1) << (std::numeric_limits<size_t>::digits - __clz(__n-1)));
}

@ -415,6 +415,9 @@ public:
append(IL.begin(), IL.end());
}
// FIXME: Consider assigning over existing elements, rather than clearing &
// re-initializing them - for all assign(...) variants.
void assign(size_type NumElts, const T &Elt) {
clear();
if (this->capacity() < NumElts)
@ -423,6 +426,11 @@ public:
std::uninitialized_fill(this->begin(), this->end(), Elt);
}
template <typename in_iter> void assign(in_iter in_start, in_iter in_end) {
clear();
append(in_start, in_end);
}
void assign(std::initializer_list<T> IL) {
clear();
append(IL);

@ -58,6 +58,7 @@ public:
/// comes before \p B in \p BB. This is a simplification that considers
/// cached instruction positions and ignores other basic blocks, being
/// only relevant to compare relative instructions positions inside \p BB.
/// Returns false for A == B.
bool dominates(const Instruction *A, const Instruction *B);
};

@ -78,6 +78,11 @@ public:
return PMT_RegionPassManager;
}
//@}
protected:
/// Optional passes call this function to check whether the pass should be
/// skipped. This is the case when optimization bisect is over the limit.
bool skipRegion(Region &R) const;
};
/// @brief The pass manager to schedule RegionPasses.

@ -636,7 +636,7 @@ private:
/// @}
public:
BackedgeTakenInfo() : MaxAndComplete(nullptr, 0) {}
BackedgeTakenInfo() : MaxAndComplete(nullptr, 0), MaxOrZero(false) {}
BackedgeTakenInfo(BackedgeTakenInfo &&) = default;
BackedgeTakenInfo &operator=(BackedgeTakenInfo &&) = default;

@ -10,83 +10,77 @@
#ifndef LLVM_CODEGEN_MACHINEREGIONINFO_H
#define LLVM_CODEGEN_MACHINEREGIONINFO_H
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominanceFrontier.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include <cassert>
namespace llvm {
class MachineDominatorTree;
struct MachinePostDominatorTree;
class MachineRegion;
class MachineRegionNode;
class MachineRegionInfo;
template<>
struct RegionTraits<MachineFunction> {
typedef MachineFunction FuncT;
typedef MachineBasicBlock BlockT;
typedef MachineRegion RegionT;
typedef MachineRegionNode RegionNodeT;
typedef MachineRegionInfo RegionInfoT;
typedef MachineDominatorTree DomTreeT;
typedef MachineDomTreeNode DomTreeNodeT;
typedef MachinePostDominatorTree PostDomTreeT;
typedef MachineDominanceFrontier DomFrontierT;
typedef MachineInstr InstT;
typedef MachineLoop LoopT;
typedef MachineLoopInfo LoopInfoT;
template <> struct RegionTraits<MachineFunction> {
using FuncT = MachineFunction;
using BlockT = MachineBasicBlock;
using RegionT = MachineRegion;
using RegionNodeT = MachineRegionNode;
using RegionInfoT = MachineRegionInfo;
using DomTreeT = MachineDominatorTree;
using DomTreeNodeT = MachineDomTreeNode;
using PostDomTreeT = MachinePostDominatorTree;
using DomFrontierT = MachineDominanceFrontier;
using InstT = MachineInstr;
using LoopT = MachineLoop;
using LoopInfoT = MachineLoopInfo;
static unsigned getNumSuccessors(MachineBasicBlock *BB) {
return BB->succ_size();
}
};
class MachineRegionNode : public RegionNodeBase<RegionTraits<MachineFunction>> {
public:
inline MachineRegionNode(MachineRegion *Parent,
MachineBasicBlock *Entry,
inline MachineRegionNode(MachineRegion *Parent, MachineBasicBlock *Entry,
bool isSubRegion = false)
: RegionNodeBase<RegionTraits<MachineFunction>>(Parent, Entry, isSubRegion) {
}
: RegionNodeBase<RegionTraits<MachineFunction>>(Parent, Entry,
isSubRegion) {}
bool operator==(const MachineRegion &RN) const {
return this == reinterpret_cast<const MachineRegionNode*>(&RN);
return this == reinterpret_cast<const MachineRegionNode *>(&RN);
}
};
class MachineRegion : public RegionBase<RegionTraits<MachineFunction>> {
public:
MachineRegion(MachineBasicBlock *Entry, MachineBasicBlock *Exit,
MachineRegionInfo* RI,
MachineDominatorTree *DT, MachineRegion *Parent = nullptr);
MachineRegionInfo *RI, MachineDominatorTree *DT,
MachineRegion *Parent = nullptr);
~MachineRegion();
bool operator==(const MachineRegionNode &RN) const {
return &RN == reinterpret_cast<const MachineRegionNode*>(this);
return &RN == reinterpret_cast<const MachineRegionNode *>(this);
}
};
class MachineRegionInfo : public RegionInfoBase<RegionTraits<MachineFunction>> {
public:
explicit MachineRegionInfo();
~MachineRegionInfo() override;
// updateStatistics - Update statistic about created regions.
void updateStatistics(MachineRegion *R) final;
void recalculate(MachineFunction &F,
MachineDominatorTree *DT,
MachinePostDominatorTree *PDT,
MachineDominanceFrontier *DF);
void recalculate(MachineFunction &F, MachineDominatorTree *DT,
MachinePostDominatorTree *PDT, MachineDominanceFrontier *DF);
};
class MachineRegionInfoPass : public MachineFunctionPass {
@ -94,17 +88,13 @@ class MachineRegionInfoPass : public MachineFunctionPass {
public:
static char ID;
explicit MachineRegionInfoPass();
explicit MachineRegionInfoPass();
~MachineRegionInfoPass() override;
MachineRegionInfo &getRegionInfo() {
return RI;
}
MachineRegionInfo &getRegionInfo() { return RI; }
const MachineRegionInfo &getRegionInfo() const {
return RI;
}
const MachineRegionInfo &getRegionInfo() const { return RI; }
/// @name MachineFunctionPass interface
//@{
@ -117,66 +107,76 @@ public:
//@}
};
template <>
template <>
inline MachineBasicBlock* RegionNodeBase<RegionTraits<MachineFunction>>::getNodeAs<MachineBasicBlock>() const {
inline MachineBasicBlock *
RegionNodeBase<RegionTraits<MachineFunction>>::getNodeAs<MachineBasicBlock>()
const {
assert(!isSubRegion() && "This is not a MachineBasicBlock RegionNode!");
return getEntry();
}
template<>
template<>
inline MachineRegion* RegionNodeBase<RegionTraits<MachineFunction>>::getNodeAs<MachineRegion>() const {
template <>
template <>
inline MachineRegion *
RegionNodeBase<RegionTraits<MachineFunction>>::getNodeAs<MachineRegion>()
const {
assert(isSubRegion() && "This is not a subregion RegionNode!");
auto Unconst = const_cast<RegionNodeBase<RegionTraits<MachineFunction>>*>(this);
return reinterpret_cast<MachineRegion*>(Unconst);
auto Unconst =
const_cast<RegionNodeBase<RegionTraits<MachineFunction>> *>(this);
return reinterpret_cast<MachineRegion *>(Unconst);
}
RegionNodeGraphTraits(MachineRegionNode, MachineBasicBlock, MachineRegion);
RegionNodeGraphTraits(const MachineRegionNode, MachineBasicBlock, MachineRegion);
RegionNodeGraphTraits(const MachineRegionNode, MachineBasicBlock,
MachineRegion);
RegionGraphTraits(MachineRegion, MachineRegionNode);
RegionGraphTraits(const MachineRegion, const MachineRegionNode);
template <> struct GraphTraits<MachineRegionInfo*>
: public GraphTraits<FlatIt<MachineRegionNode*> > {
typedef df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
GraphTraits<FlatIt<NodeRef>>>
nodes_iterator;
template <>
struct GraphTraits<MachineRegionInfo *>
: public GraphTraits<FlatIt<MachineRegionNode *>> {
using nodes_iterator = df_iterator<NodeRef, df_iterator_default_set<NodeRef>,
false, GraphTraits<FlatIt<NodeRef>>>;
static NodeRef getEntryNode(MachineRegionInfo *RI) {
return GraphTraits<FlatIt<MachineRegion*> >::getEntryNode(RI->getTopLevelRegion());
return GraphTraits<FlatIt<MachineRegion *>>::getEntryNode(
RI->getTopLevelRegion());
}
static nodes_iterator nodes_begin(MachineRegionInfo* RI) {
static nodes_iterator nodes_begin(MachineRegionInfo *RI) {
return nodes_iterator::begin(getEntryNode(RI));
}
static nodes_iterator nodes_end(MachineRegionInfo *RI) {
return nodes_iterator::end(getEntryNode(RI));
}
};
template <> struct GraphTraits<MachineRegionInfoPass*>
: public GraphTraits<MachineRegionInfo *> {
typedef df_iterator<NodeRef, df_iterator_default_set<NodeRef>, false,
GraphTraits<FlatIt<NodeRef>>>
nodes_iterator;
template <>
struct GraphTraits<MachineRegionInfoPass *>
: public GraphTraits<MachineRegionInfo *> {
using nodes_iterator = df_iterator<NodeRef, df_iterator_default_set<NodeRef>,
false, GraphTraits<FlatIt<NodeRef>>>;
static NodeRef getEntryNode(MachineRegionInfoPass *RI) {
return GraphTraits<MachineRegionInfo*>::getEntryNode(&RI->getRegionInfo());
return GraphTraits<MachineRegionInfo *>::getEntryNode(&RI->getRegionInfo());
}
static nodes_iterator nodes_begin(MachineRegionInfoPass* RI) {
return GraphTraits<MachineRegionInfo*>::nodes_begin(&RI->getRegionInfo());
static nodes_iterator nodes_begin(MachineRegionInfoPass *RI) {
return GraphTraits<MachineRegionInfo *>::nodes_begin(&RI->getRegionInfo());
}
static nodes_iterator nodes_end(MachineRegionInfoPass *RI) {
return GraphTraits<MachineRegionInfo*>::nodes_end(&RI->getRegionInfo());
return GraphTraits<MachineRegionInfo *>::nodes_end(&RI->getRegionInfo());
}
};
extern template class RegionBase<RegionTraits<MachineFunction>>;
extern template class RegionNodeBase<RegionTraits<MachineFunction>>;
extern template class RegionInfoBase<RegionTraits<MachineFunction>>;
}
#endif
} // end namespace llvm
#endif // LLVM_CODEGEN_MACHINEREGIONINFO_H

@ -14,11 +14,13 @@
#ifndef LLVM_CODEGEN_MACHINEREGISTERINFO_H
#define LLVM_CODEGEN_MACHINEREGISTERINFO_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/GlobalISel/RegisterBank.h"
#include "llvm/CodeGen/LowLevelType.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
@ -41,8 +43,8 @@ namespace llvm {
class PSetIterator;
/// Convenient type to represent either a register class or a register bank.
typedef PointerUnion<const TargetRegisterClass *, const RegisterBank *>
RegClassOrRegBank;
using RegClassOrRegBank =
PointerUnion<const TargetRegisterClass *, const RegisterBank *>;
/// MachineRegisterInfo - Keep track of information for virtual and physical
/// registers, including vreg register classes, use/def chains for registers,
@ -125,7 +127,7 @@ private:
/// started.
BitVector ReservedRegs;
typedef DenseMap<unsigned, LLT> VRegToTypeMap;
using VRegToTypeMap = DenseMap<unsigned, LLT>;
/// Map generic virtual registers to their actual size.
mutable std::unique_ptr<VRegToTypeMap> VRegToType;
@ -266,8 +268,8 @@ public:
/// reg_iterator/reg_begin/reg_end - Walk all defs and uses of the specified
/// register.
typedef defusechain_iterator<true,true,false,true,false,false>
reg_iterator;
using reg_iterator =
defusechain_iterator<true, true, false, true, false, false>;
reg_iterator reg_begin(unsigned RegNo) const {
return reg_iterator(getRegUseDefListHead(RegNo));
}
@ -279,8 +281,8 @@ public:
/// reg_instr_iterator/reg_instr_begin/reg_instr_end - Walk all defs and uses
/// of the specified register, stepping by MachineInstr.
typedef defusechain_instr_iterator<true,true,false,false,true,false>
reg_instr_iterator;
using reg_instr_iterator =
defusechain_instr_iterator<true, true, false, false, true, false>;
reg_instr_iterator reg_instr_begin(unsigned RegNo) const {
return reg_instr_iterator(getRegUseDefListHead(RegNo));
}
@ -295,8 +297,8 @@ public:
/// reg_bundle_iterator/reg_bundle_begin/reg_bundle_end - Walk all defs and uses
/// of the specified register, stepping by bundle.
typedef defusechain_instr_iterator<true,true,false,false,false,true>
reg_bundle_iterator;
using reg_bundle_iterator =
defusechain_instr_iterator<true, true, false, false, false, true>;
reg_bundle_iterator reg_bundle_begin(unsigned RegNo) const {
return reg_bundle_iterator(getRegUseDefListHead(RegNo));
}
@ -314,8 +316,8 @@ public:
/// reg_nodbg_iterator/reg_nodbg_begin/reg_nodbg_end - Walk all defs and uses
/// of the specified register, skipping those marked as Debug.
typedef defusechain_iterator<true,true,true,true,false,false>
reg_nodbg_iterator;
using reg_nodbg_iterator =
defusechain_iterator<true, true, true, true, false, false>;
reg_nodbg_iterator reg_nodbg_begin(unsigned RegNo) const {
return reg_nodbg_iterator(getRegUseDefListHead(RegNo));
}
@ -331,8 +333,8 @@ public:
/// reg_instr_nodbg_iterator/reg_instr_nodbg_begin/reg_instr_nodbg_end - Walk
/// all defs and uses of the specified register, stepping by MachineInstr,
/// skipping those marked as Debug.
typedef defusechain_instr_iterator<true,true,true,false,true,false>
reg_instr_nodbg_iterator;
using reg_instr_nodbg_iterator =
defusechain_instr_iterator<true, true, true, false, true, false>;
reg_instr_nodbg_iterator reg_instr_nodbg_begin(unsigned RegNo) const {
return reg_instr_nodbg_iterator(getRegUseDefListHead(RegNo));
}
@ -348,8 +350,8 @@ public:
/// reg_bundle_nodbg_iterator/reg_bundle_nodbg_begin/reg_bundle_nodbg_end - Walk
/// all defs and uses of the specified register, stepping by bundle,
/// skipping those marked as Debug.
typedef defusechain_instr_iterator<true,true,true,false,false,true>
reg_bundle_nodbg_iterator;
using reg_bundle_nodbg_iterator =
defusechain_instr_iterator<true, true, true, false, false, true>;
reg_bundle_nodbg_iterator reg_bundle_nodbg_begin(unsigned RegNo) const {
return reg_bundle_nodbg_iterator(getRegUseDefListHead(RegNo));
}
@ -369,8 +371,8 @@ public:
}
/// def_iterator/def_begin/def_end - Walk all defs of the specified register.
typedef defusechain_iterator<false,true,false,true,false,false>
def_iterator;
using def_iterator =
defusechain_iterator<false, true, false, true, false, false>;
def_iterator def_begin(unsigned RegNo) const {
return def_iterator(getRegUseDefListHead(RegNo));
}
@ -382,8 +384,8 @@ public:
/// def_instr_iterator/def_instr_begin/def_instr_end - Walk all defs of the
/// specified register, stepping by MachineInst.
typedef defusechain_instr_iterator<false,true,false,false,true,false>
def_instr_iterator;
using def_instr_iterator =
defusechain_instr_iterator<false, true, false, false, true, false>;
def_instr_iterator def_instr_begin(unsigned RegNo) const {
return def_instr_iterator(getRegUseDefListHead(RegNo));
}
@ -398,8 +400,8 @@ public:
/// def_bundle_iterator/def_bundle_begin/def_bundle_end - Walk all defs of the
/// specified register, stepping by bundle.
typedef defusechain_instr_iterator<false,true,false,false,false,true>
def_bundle_iterator;
using def_bundle_iterator =
defusechain_instr_iterator<false, true, false, false, false, true>;
def_bundle_iterator def_bundle_begin(unsigned RegNo) const {
return def_bundle_iterator(getRegUseDefListHead(RegNo));
}
@ -425,8 +427,8 @@ public:
}
/// use_iterator/use_begin/use_end - Walk all uses of the specified register.
typedef defusechain_iterator<true,false,false,true,false,false>
use_iterator;
using use_iterator =
defusechain_iterator<true, false, false, true, false, false>;
use_iterator use_begin(unsigned RegNo) const {
return use_iterator(getRegUseDefListHead(RegNo));
}
@ -438,8 +440,8 @@ public:
/// use_instr_iterator/use_instr_begin/use_instr_end - Walk all uses of the
/// specified register, stepping by MachineInstr.
typedef defusechain_instr_iterator<true,false,false,false,true,false>
use_instr_iterator;
using use_instr_iterator =
defusechain_instr_iterator<true, false, false, false, true, false>;
use_instr_iterator use_instr_begin(unsigned RegNo) const {
return use_instr_iterator(getRegUseDefListHead(RegNo));
}
@ -454,8 +456,8 @@ public:
/// use_bundle_iterator/use_bundle_begin/use_bundle_end - Walk all uses of the
/// specified register, stepping by bundle.
typedef defusechain_instr_iterator<true,false,false,false,false,true>
use_bundle_iterator;
using use_bundle_iterator =
defusechain_instr_iterator<true, false, false, false, false, true>;
use_bundle_iterator use_bundle_begin(unsigned RegNo) const {
return use_bundle_iterator(getRegUseDefListHead(RegNo));
}
@ -482,8 +484,8 @@ public:
/// use_nodbg_iterator/use_nodbg_begin/use_nodbg_end - Walk all uses of the
/// specified register, skipping those marked as Debug.
typedef defusechain_iterator<true,false,true,true,false,false>
use_nodbg_iterator;
using use_nodbg_iterator =
defusechain_iterator<true, false, true, true, false, false>;
use_nodbg_iterator use_nodbg_begin(unsigned RegNo) const {
return use_nodbg_iterator(getRegUseDefListHead(RegNo));
}
@ -499,8 +501,8 @@ public:
/// use_instr_nodbg_iterator/use_instr_nodbg_begin/use_instr_nodbg_end - Walk
/// all uses of the specified register, stepping by MachineInstr, skipping
/// those marked as Debug.
typedef defusechain_instr_iterator<true,false,true,false,true,false>
use_instr_nodbg_iterator;
using use_instr_nodbg_iterator =
defusechain_instr_iterator<true, false, true, false, true, false>;
use_instr_nodbg_iterator use_instr_nodbg_begin(unsigned RegNo) const {
return use_instr_nodbg_iterator(getRegUseDefListHead(RegNo));
}
@ -516,8 +518,8 @@ public:
/// use_bundle_nodbg_iterator/use_bundle_nodbg_begin/use_bundle_nodbg_end - Walk
/// all uses of the specified register, stepping by bundle, skipping
/// those marked as Debug.
typedef defusechain_instr_iterator<true,false,true,false,false,true>
use_bundle_nodbg_iterator;
using use_bundle_nodbg_iterator =
defusechain_instr_iterator<true, false, true, false, false, true>;
use_bundle_nodbg_iterator use_bundle_nodbg_begin(unsigned RegNo) const {
return use_bundle_nodbg_iterator(getRegUseDefListHead(RegNo));
}
@ -593,7 +595,6 @@ public:
/// Return the register class of the specified virtual register.
/// This shouldn't be used directly unless \p Reg has a register class.
/// \see getRegClassOrNull when this might happen.
///
const TargetRegisterClass *getRegClass(unsigned Reg) const {
assert(VRegInfo[Reg].first.is<const TargetRegisterClass *>() &&
"Register class not set, wrong accessor");
@ -620,7 +621,6 @@ public:
/// a register bank or has been assigned a register class.
/// \note It is possible to get the register bank from the register class via
/// RegisterBankInfo::getRegBankFromRegClass.
///
const RegisterBank *getRegBankOrNull(unsigned Reg) const {
const RegClassOrRegBank &Val = VRegInfo[Reg].first;
return Val.dyn_cast<const RegisterBank *>();
@ -629,17 +629,14 @@ public:
/// Return the register bank or register class of \p Reg.
/// \note Before the register bank gets assigned (i.e., before the
/// RegBankSelect pass) \p Reg may not have either.
///
const RegClassOrRegBank &getRegClassOrRegBank(unsigned Reg) const {
return VRegInfo[Reg].first;
}
/// setRegClass - Set the register class of the specified virtual register.
///
void setRegClass(unsigned Reg, const TargetRegisterClass *RC);
/// Set the register bank to \p RegBank for \p Reg.
///
void setRegBank(unsigned Reg, const RegisterBank &RegBank);
void setRegClassOrRegBank(unsigned Reg,
@ -653,7 +650,6 @@ public:
/// new register class, or NULL if no such class exists.
/// This should only be used when the constraint is known to be trivial, like
/// GR32 -> GR32_NOSP. Beware of increasing register pressure.
///
const TargetRegisterClass *constrainRegClass(unsigned Reg,
const TargetRegisterClass *RC,
unsigned MinNumRegs = 0);
@ -665,12 +661,10 @@ public:
/// This method can be used after constraints have been removed from a
/// virtual register, for example after removing instructions or splitting
/// the live range.
///
bool recomputeRegClass(unsigned Reg);
/// createVirtualRegister - Create and return a new virtual register in the
/// function with the specified register class.
///
unsigned createVirtualRegister(const TargetRegisterClass *RegClass);
/// Accessor for VRegToType. This accessor should only be used
@ -704,7 +698,6 @@ public:
unsigned createIncompleteVirtualRegister();
/// getNumVirtRegs - Return the number of virtual registers created.
///
unsigned getNumVirtRegs() const { return VRegInfo.size(); }
/// clearVirtRegs - Remove all virtual registers (after physreg assignment).
@ -810,7 +803,6 @@ public:
///
/// Reserved registers may belong to an allocatable register class, but the
/// target has explicitly requested that they are not used.
///
bool isReserved(unsigned PhysReg) const {
return getReservedRegs().test(PhysReg);
}
@ -838,8 +830,8 @@ public:
// Iteration support for the live-ins set. It's kept in sorted order
// by register number.
typedef std::vector<std::pair<unsigned,unsigned>>::const_iterator
livein_iterator;
using livein_iterator =
std::vector<std::pair<unsigned,unsigned>>::const_iterator;
livein_iterator livein_begin() const { return LiveIns.begin(); }
livein_iterator livein_end() const { return LiveIns.end(); }
bool livein_empty() const { return LiveIns.empty(); }
@ -910,10 +902,10 @@ public:
}
public:
typedef std::iterator<std::forward_iterator_tag,
MachineInstr, ptrdiff_t>::reference reference;
typedef std::iterator<std::forward_iterator_tag,
MachineInstr, ptrdiff_t>::pointer pointer;
using reference = std::iterator<std::forward_iterator_tag,
MachineInstr, ptrdiff_t>::reference;
using pointer = std::iterator<std::forward_iterator_tag,
MachineInstr, ptrdiff_t>::pointer;
defusechain_iterator() = default;
@ -1016,10 +1008,10 @@ public:
}
public:
typedef std::iterator<std::forward_iterator_tag,
MachineInstr, ptrdiff_t>::reference reference;
typedef std::iterator<std::forward_iterator_tag,
MachineInstr, ptrdiff_t>::pointer pointer;
using reference = std::iterator<std::forward_iterator_tag,
MachineInstr, ptrdiff_t>::reference;
using pointer = std::iterator<std::forward_iterator_tag,
MachineInstr, ptrdiff_t>::pointer;
defusechain_instr_iterator() = default;

@ -104,10 +104,15 @@ extern cl::opt<bool> ForceBottomUp;
class LiveIntervals;
class MachineDominatorTree;
class MachineFunction;
class MachineInstr;
class MachineLoopInfo;
class RegisterClassInfo;
class SchedDFSResult;
class ScheduleHazardRecognizer;
class TargetInstrInfo;
class TargetPassConfig;
class TargetRegisterInfo;
/// MachineSchedContext provides enough context from the MachineScheduler pass
/// for the target to instantiate a scheduler.
@ -129,10 +134,10 @@ struct MachineSchedContext {
/// schedulers.
class MachineSchedRegistry : public MachinePassRegistryNode {
public:
typedef ScheduleDAGInstrs *(*ScheduleDAGCtor)(MachineSchedContext *);
using ScheduleDAGCtor = ScheduleDAGInstrs *(*)(MachineSchedContext *);
// RegisterPassParser requires a (misnamed) FunctionPassCtor type.
typedef ScheduleDAGCtor FunctionPassCtor;
using FunctionPassCtor = ScheduleDAGCtor;
static MachinePassRegistry Registry;
@ -527,7 +532,7 @@ public:
unsigned size() const { return Queue.size(); }
typedef std::vector<SUnit*>::iterator iterator;
using iterator = std::vector<SUnit*>::iterator;
iterator begin() { return Queue.begin(); }

@ -1,4 +1,4 @@
//===---------- CostAllocator.h - PBQP Cost Allocator -----------*- C++ -*-===//
//===- CostAllocator.h - PBQP Cost Allocator --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -19,26 +19,28 @@
#define LLVM_CODEGEN_PBQP_COSTALLOCATOR_H
#include "llvm/ADT/DenseSet.h"
#include <algorithm>
#include <cstdint>
#include <memory>
#include <type_traits>
namespace llvm {
namespace PBQP {
template <typename ValueT>
class ValuePool {
template <typename ValueT> class ValuePool {
public:
typedef std::shared_ptr<const ValueT> PoolRef;
using PoolRef = std::shared_ptr<const ValueT>;
private:
class PoolEntry : public std::enable_shared_from_this<PoolEntry> {
public:
template <typename ValueKeyT>
PoolEntry(ValuePool &Pool, ValueKeyT Value)
: Pool(Pool), Value(std::move(Value)) {}
~PoolEntry() { Pool.removeEntry(this); }
const ValueT& getValue() const { return Value; }
const ValueT &getValue() const { return Value; }
private:
ValuePool &Pool;
ValueT Value;
@ -46,10 +48,10 @@ private:
class PoolEntryDSInfo {
public:
static inline PoolEntry* getEmptyKey() { return nullptr; }
static inline PoolEntry *getEmptyKey() { return nullptr; }
static inline PoolEntry* getTombstoneKey() {
return reinterpret_cast<PoolEntry*>(static_cast<uintptr_t>(1));
static inline PoolEntry *getTombstoneKey() {
return reinterpret_cast<PoolEntry *>(static_cast<uintptr_t>(1));
}
template <typename ValueKeyT>
@ -66,8 +68,7 @@ private:
}
template <typename ValueKeyT1, typename ValueKeyT2>
static
bool isEqual(const ValueKeyT1 &C1, const ValueKeyT2 &C2) {
static bool isEqual(const ValueKeyT1 &C1, const ValueKeyT2 &C2) {
return C1 == C2;
}
@ -83,10 +84,9 @@ private:
return P1 == P2;
return isEqual(P1->getValue(), P2);
}
};
typedef DenseSet<PoolEntry*, PoolEntryDSInfo> EntrySetT;
using EntrySetT = DenseSet<PoolEntry *, PoolEntryDSInfo>;
EntrySetT EntrySet;
@ -105,28 +105,31 @@ public:
}
};
template <typename VectorT, typename MatrixT>
class PoolCostAllocator {
template <typename VectorT, typename MatrixT> class PoolCostAllocator {
private:
typedef ValuePool<VectorT> VectorCostPool;
typedef ValuePool<MatrixT> MatrixCostPool;
using VectorCostPool = ValuePool<VectorT>;
using MatrixCostPool = ValuePool<MatrixT>;
public:
typedef VectorT Vector;
typedef MatrixT Matrix;
typedef typename VectorCostPool::PoolRef VectorPtr;
typedef typename MatrixCostPool::PoolRef MatrixPtr;
using Vector = VectorT;
using Matrix = MatrixT;
using VectorPtr = typename VectorCostPool::PoolRef;
using MatrixPtr = typename MatrixCostPool::PoolRef;
template <typename VectorKeyT>
VectorPtr getVector(VectorKeyT v) { return VectorPool.getValue(std::move(v)); }
template <typename VectorKeyT> VectorPtr getVector(VectorKeyT v) {
return VectorPool.getValue(std::move(v));
}
template <typename MatrixKeyT> MatrixPtr getMatrix(MatrixKeyT m) {
return MatrixPool.getValue(std::move(m));
}
template <typename MatrixKeyT>
MatrixPtr getMatrix(MatrixKeyT m) { return MatrixPool.getValue(std::move(m)); }
private:
VectorCostPool VectorPool;
MatrixCostPool MatrixPool;
};
} // namespace PBQP
} // namespace llvm
} // end namespace PBQP
} // end namespace llvm
#endif
#endif // LLVM_CODEGEN_PBQP_COSTALLOCATOR_H

@ -1,4 +1,4 @@
//===-------------------- Graph.h - PBQP Graph ------------------*- C++ -*-===//
//===- Graph.h - PBQP Graph -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -11,16 +11,14 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_PBQP_GRAPH_H
#define LLVM_CODEGEN_PBQP_GRAPH_H
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <limits>
#include <utility>
#include <vector>
namespace llvm {
@ -28,8 +26,8 @@ namespace PBQP {
class GraphBase {
public:
typedef unsigned NodeId;
typedef unsigned EdgeId;
using NodeId = unsigned;
using EdgeId = unsigned;
/// @brief Returns a value representing an invalid (non-existent) node.
static NodeId invalidNodeId() {
@ -48,32 +46,32 @@ namespace PBQP {
template <typename SolverT>
class Graph : public GraphBase {
private:
typedef typename SolverT::CostAllocator CostAllocator;
using CostAllocator = typename SolverT::CostAllocator;
public:
typedef typename SolverT::RawVector RawVector;
typedef typename SolverT::RawMatrix RawMatrix;
typedef typename SolverT::Vector Vector;
typedef typename SolverT::Matrix Matrix;
typedef typename CostAllocator::VectorPtr VectorPtr;
typedef typename CostAllocator::MatrixPtr MatrixPtr;
typedef typename SolverT::NodeMetadata NodeMetadata;
typedef typename SolverT::EdgeMetadata EdgeMetadata;
typedef typename SolverT::GraphMetadata GraphMetadata;
using RawVector = typename SolverT::RawVector;
using RawMatrix = typename SolverT::RawMatrix;
using Vector = typename SolverT::Vector;
using Matrix = typename SolverT::Matrix;
using VectorPtr = typename CostAllocator::VectorPtr;
using MatrixPtr = typename CostAllocator::MatrixPtr;
using NodeMetadata = typename SolverT::NodeMetadata;
using EdgeMetadata = typename SolverT::EdgeMetadata;
using GraphMetadata = typename SolverT::GraphMetadata;
private:
class NodeEntry {
public:
typedef std::vector<EdgeId> AdjEdgeList;
typedef AdjEdgeList::size_type AdjEdgeIdx;
typedef AdjEdgeList::const_iterator AdjEdgeItr;
using AdjEdgeList = std::vector<EdgeId>;
using AdjEdgeIdx = AdjEdgeList::size_type;
using AdjEdgeItr = AdjEdgeList::const_iterator;
NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {}
static AdjEdgeIdx getInvalidAdjEdgeIdx() {
return std::numeric_limits<AdjEdgeIdx>::max();
}
NodeEntry(VectorPtr Costs) : Costs(std::move(Costs)) {}
AdjEdgeIdx addAdjEdgeId(EdgeId EId) {
AdjEdgeIdx Idx = AdjEdgeIds.size();
AdjEdgeIds.push_back(EId);
@ -96,6 +94,7 @@ namespace PBQP {
VectorPtr Costs;
NodeMetadata Metadata;
private:
AdjEdgeList AdjEdgeIds;
};
@ -150,8 +149,10 @@ namespace PBQP {
NodeId getN1Id() const { return NIds[0]; }
NodeId getN2Id() const { return NIds[1]; }
MatrixPtr Costs;
EdgeMetadata Metadata;
private:
NodeId NIds[2];
typename NodeEntry::AdjEdgeIdx ThisEdgeAdjIdxs[2];
@ -161,18 +162,20 @@ namespace PBQP {
GraphMetadata Metadata;
CostAllocator CostAlloc;
SolverT *Solver;
SolverT *Solver = nullptr;
typedef std::vector<NodeEntry> NodeVector;
typedef std::vector<NodeId> FreeNodeVector;
using NodeVector = std::vector<NodeEntry>;
using FreeNodeVector = std::vector<NodeId>;
NodeVector Nodes;
FreeNodeVector FreeNodeIds;
typedef std::vector<EdgeEntry> EdgeVector;
typedef std::vector<EdgeId> FreeEdgeVector;
using EdgeVector = std::vector<EdgeEntry>;
using FreeEdgeVector = std::vector<EdgeId>;
EdgeVector Edges;
FreeEdgeVector FreeEdgeIds;
Graph(const Graph &Other) {}
// ----- INTERNAL METHODS -----
NodeEntry &getNode(NodeId NId) {
@ -220,20 +223,18 @@ namespace PBQP {
return EId;
}
Graph(const Graph &Other) {}
void operator=(const Graph &Other) {}
public:
typedef typename NodeEntry::AdjEdgeItr AdjEdgeItr;
using AdjEdgeItr = typename NodeEntry::AdjEdgeItr;
class NodeItr {
public:
typedef std::forward_iterator_tag iterator_category;
typedef NodeId value_type;
typedef int difference_type;
typedef NodeId* pointer;
typedef NodeId& reference;
using iterator_category = std::forward_iterator_tag;
using value_type = NodeId;
using difference_type = int;
using pointer = NodeId *;
using reference = NodeId &;
NodeItr(NodeId CurNId, const Graph &G)
: CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) {
@ -283,53 +284,65 @@ namespace PBQP {
class NodeIdSet {
public:
NodeIdSet(const Graph &G) : G(G) { }
NodeIdSet(const Graph &G) : G(G) {}
NodeItr begin() const { return NodeItr(0, G); }
NodeItr end() const { return NodeItr(G.Nodes.size(), G); }
bool empty() const { return G.Nodes.empty(); }
typename NodeVector::size_type size() const {
return G.Nodes.size() - G.FreeNodeIds.size();
}
private:
const Graph& G;
};
class EdgeIdSet {
public:
EdgeIdSet(const Graph &G) : G(G) { }
EdgeIdSet(const Graph &G) : G(G) {}
EdgeItr begin() const { return EdgeItr(0, G); }
EdgeItr end() const { return EdgeItr(G.Edges.size(), G); }
bool empty() const { return G.Edges.empty(); }
typename NodeVector::size_type size() const {
return G.Edges.size() - G.FreeEdgeIds.size();
}
private:
const Graph& G;
};
class AdjEdgeIdSet {
public:
AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) { }
AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) {}
typename NodeEntry::AdjEdgeItr begin() const {
return NE.getAdjEdgeIds().begin();
}
typename NodeEntry::AdjEdgeItr end() const {
return NE.getAdjEdgeIds().end();
}
bool empty() const { return NE.getAdjEdgeIds().empty(); }
typename NodeEntry::AdjEdgeList::size_type size() const {
return NE.getAdjEdgeIds().size();
}
private:
const NodeEntry &NE;
};
/// @brief Construct an empty PBQP graph.
Graph() : Solver(nullptr) {}
Graph() = default;
/// @brief Construct an empty PBQP graph with the given graph metadata.
Graph(GraphMetadata Metadata)
: Metadata(std::move(Metadata)), Solver(nullptr) {}
Graph(GraphMetadata Metadata) : Metadata(std::move(Metadata)) {}
/// @brief Get a reference to the graph metadata.
GraphMetadata& getMetadata() { return Metadata; }
@ -656,7 +669,7 @@ namespace PBQP {
}
};
} // namespace PBQP
} // namespace llvm
} // end namespace PBQP
} // end namespace llvm
#endif // LLVM_CODEGEN_PBQP_GRAPH_HPP

@ -1,4 +1,4 @@
//===------ Math.h - PBQP Vector and Matrix classes -------------*- C++ -*-===//
//===- Math.h - PBQP Vector and Matrix classes ------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -11,20 +11,22 @@
#define LLVM_CODEGEN_PBQP_MATH_H
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
#include <cassert>
#include <functional>
#include <memory>
namespace llvm {
namespace PBQP {
typedef float PBQPNum;
using PBQPNum = float;
/// \brief PBQP Vector class.
class Vector {
friend hash_code hash_value(const Vector &);
public:
public:
/// \brief Construct a PBQP vector of the given size.
explicit Vector(unsigned Length)
: Length(Length), Data(llvm::make_unique<PBQPNum []>(Length)) {}
@ -120,8 +122,8 @@ OStream& operator<<(OStream &OS, const Vector &V) {
class Matrix {
private:
friend hash_code hash_value(const Matrix &);
public:
public:
/// \brief Construct a PBQP Matrix with the given dimensions.
Matrix(unsigned Rows, unsigned Cols) :
Rows(Rows), Cols(Cols), Data(llvm::make_unique<PBQPNum []>(Rows * Cols)) {
@ -253,9 +255,11 @@ OStream& operator<<(OStream &OS, const Matrix &M) {
template <typename Metadata>
class MDVector : public Vector {
public:
MDVector(const Vector &v) : Vector(v), md(*this) { }
MDVector(const Vector &v) : Vector(v), md(*this) {}
MDVector(Vector &&v) : Vector(std::move(v)), md(*this) { }
const Metadata& getMetadata() const { return md; }
private:
Metadata md;
};
@ -268,9 +272,11 @@ inline hash_code hash_value(const MDVector<Metadata> &V) {
template <typename Metadata>
class MDMatrix : public Matrix {
public:
MDMatrix(const Matrix &m) : Matrix(m), md(*this) { }
MDMatrix(const Matrix &m) : Matrix(m), md(*this) {}
MDMatrix(Matrix &&m) : Matrix(std::move(m)), md(*this) { }
const Metadata& getMetadata() const { return md; }
private:
Metadata md;
};
@ -280,7 +286,7 @@ inline hash_code hash_value(const MDMatrix<Metadata> &M) {
return hash_value(static_cast<const Matrix&>(M));
}
} // namespace PBQP
} // namespace llvm
} // end namespace PBQP
} // end namespace llvm
#endif // LLVM_CODEGEN_PBQP_MATH_H

@ -1,4 +1,4 @@
//===----------- ReductionRules.h - Reduction Rules -------------*- C++ -*-===//
//===- ReductionRules.h - Reduction Rules -----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -17,6 +17,8 @@
#include "Graph.h"
#include "Math.h"
#include "Solution.h"
#include <cassert>
#include <limits>
namespace llvm {
namespace PBQP {
@ -27,11 +29,11 @@ namespace PBQP {
/// neighbor. Notify the problem domain.
template <typename GraphT>
void applyR1(GraphT &G, typename GraphT::NodeId NId) {
typedef typename GraphT::NodeId NodeId;
typedef typename GraphT::EdgeId EdgeId;
typedef typename GraphT::Vector Vector;
typedef typename GraphT::Matrix Matrix;
typedef typename GraphT::RawVector RawVector;
using NodeId = typename GraphT::NodeId;
using EdgeId = typename GraphT::EdgeId;
using Vector = typename GraphT::Vector;
using Matrix = typename GraphT::Matrix;
using RawVector = typename GraphT::RawVector;
assert(G.getNodeDegree(NId) == 1 &&
"R1 applied to node with degree != 1.");
@ -71,11 +73,11 @@ namespace PBQP {
template <typename GraphT>
void applyR2(GraphT &G, typename GraphT::NodeId NId) {
typedef typename GraphT::NodeId NodeId;
typedef typename GraphT::EdgeId EdgeId;
typedef typename GraphT::Vector Vector;
typedef typename GraphT::Matrix Matrix;
typedef typename GraphT::RawMatrix RawMatrix;
using NodeId = typename GraphT::NodeId;
using EdgeId = typename GraphT::EdgeId;
using Vector = typename GraphT::Vector;
using Matrix = typename GraphT::Matrix;
using RawMatrix = typename GraphT::RawMatrix;
assert(G.getNodeDegree(NId) == 2 &&
"R2 applied to node with degree != 2.");
@ -177,9 +179,9 @@ namespace PBQP {
// state.
template <typename GraphT, typename StackT>
Solution backpropagate(GraphT& G, StackT stack) {
typedef GraphBase::NodeId NodeId;
typedef typename GraphT::Matrix Matrix;
typedef typename GraphT::RawVector RawVector;
using NodeId = GraphBase::NodeId;
using Matrix = typename GraphT::Matrix;
using RawVector = typename GraphT::RawVector;
Solution s;
@ -215,7 +217,7 @@ namespace PBQP {
return s;
}
} // namespace PBQP
} // namespace llvm
} // end namespace PBQP
} // end namespace llvm
#endif
#endif // LLVM_CODEGEN_PBQP_REDUCTIONRULES_H

@ -26,7 +26,7 @@ namespace PBQP {
/// To get the selection for each node in the problem use the getSelection method.
class Solution {
private:
typedef std::map<GraphBase::NodeId, unsigned> SelectionsMap;
using SelectionsMap = std::map<GraphBase::NodeId, unsigned>;
SelectionsMap selections;
unsigned r0Reductions = 0;

@ -1,4 +1,4 @@
//===-- RegAllocPBQP.h ------------------------------------------*- C++ -*-===//
//===- RegAllocPBQP.h -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -16,23 +16,22 @@
#ifndef LLVM_CODEGEN_PBQPRACONSTRAINT_H
#define LLVM_CODEGEN_PBQPRACONSTRAINT_H
#include <algorithm>
#include <memory>
#include <vector>
namespace llvm {
namespace PBQP {
namespace RegAlloc {
// Forward declare PBQP graph class.
class PBQPRAGraph;
}
}
class LiveIntervals;
class MachineBlockFrequencyInfo;
class MachineFunction;
class TargetRegisterInfo;
} // end namespace RegAlloc
} // end namespace PBQP
typedef PBQP::RegAlloc::PBQPRAGraph PBQPRAGraph;
using PBQPRAGraph = PBQP::RegAlloc::PBQPRAGraph;
/// @brief Abstract base for classes implementing PBQP register allocation
/// constraints (e.g. Spill-costs, interference, coalescing).
@ -40,6 +39,7 @@ class PBQPRAConstraint {
public:
virtual ~PBQPRAConstraint() = 0;
virtual void apply(PBQPRAGraph &G) = 0;
private:
virtual void anchor();
};
@ -59,11 +59,13 @@ public:
if (C)
Constraints.push_back(std::move(C));
}
private:
std::vector<std::unique_ptr<PBQPRAConstraint>> Constraints;
void anchor() override;
};
}
} // end namespace llvm
#endif /* LLVM_CODEGEN_PBQPRACONSTRAINT_H */
#endif // LLVM_CODEGEN_PBQPRACONSTRAINT_H

@ -140,6 +140,9 @@ namespace llvm {
/// Greedy register allocator.
extern char &RAGreedyID;
/// Basic register allocator.
extern char &RABasicID;
/// VirtRegRewriter pass. Rewrite virtual registers to physical registers as
/// assigned in VirtRegMap.
extern char &VirtRegRewriterID;

@ -130,10 +130,10 @@ inline hash_code hash_value(const AllowedRegVector &OptRegs) {
/// \brief Holds graph-level metadata relevant to PBQP RA problems.
class GraphMetadata {
private:
typedef ValuePool<AllowedRegVector> AllowedRegVecPool;
using AllowedRegVecPool = ValuePool<AllowedRegVector>;
public:
typedef AllowedRegVecPool::PoolRef AllowedRegVecRef;
using AllowedRegVecRef = AllowedRegVecPool::PoolRef;
GraphMetadata(MachineFunction &MF,
LiveIntervals &LIS,
@ -167,17 +167,17 @@ private:
/// \brief Holds solver state and other metadata relevant to each PBQP RA node.
class NodeMetadata {
public:
typedef RegAlloc::AllowedRegVector AllowedRegVector;
using AllowedRegVector = RegAlloc::AllowedRegVector;
// The node's reduction state. The order in this enum is important,
// as it is assumed nodes can only progress up (i.e. towards being
// optimally reducible) when reducing the graph.
typedef enum {
using ReductionState = enum {
Unprocessed,
NotProvablyAllocatable,
ConservativelyAllocatable,
OptimallyReducible
} ReductionState;
};
NodeMetadata() = default;
@ -267,23 +267,23 @@ private:
class RegAllocSolverImpl {
private:
typedef MDMatrix<MatrixMetadata> RAMatrix;
using RAMatrix = MDMatrix<MatrixMetadata>;
public:
typedef PBQP::Vector RawVector;
typedef PBQP::Matrix RawMatrix;
typedef PBQP::Vector Vector;
typedef RAMatrix Matrix;
typedef PBQP::PoolCostAllocator<Vector, Matrix> CostAllocator;
using RawVector = PBQP::Vector;
using RawMatrix = PBQP::Matrix;
using Vector = PBQP::Vector;
using Matrix = RAMatrix;
using CostAllocator = PBQP::PoolCostAllocator<Vector, Matrix>;
typedef GraphBase::NodeId NodeId;
typedef GraphBase::EdgeId EdgeId;
using NodeId = GraphBase::NodeId;
using EdgeId = GraphBase::EdgeId;
typedef RegAlloc::NodeMetadata NodeMetadata;
struct EdgeMetadata { };
typedef RegAlloc::GraphMetadata GraphMetadata;
using NodeMetadata = RegAlloc::NodeMetadata;
struct EdgeMetadata {};
using GraphMetadata = RegAlloc::GraphMetadata;
typedef PBQP::Graph<RegAllocSolverImpl> Graph;
using Graph = PBQP::Graph<RegAllocSolverImpl>;
RegAllocSolverImpl(Graph &G) : G(G) {}
@ -426,7 +426,7 @@ private:
std::vector<GraphBase::NodeId> reduce() {
assert(!G.empty() && "Cannot reduce empty graph.");
typedef GraphBase::NodeId NodeId;
using NodeId = GraphBase::NodeId;
std::vector<NodeId> NodeStack;
// Consume worklists.
@ -459,7 +459,6 @@ private:
ConservativelyAllocatableNodes.erase(NItr);
NodeStack.push_back(NId);
G.disconnectAllNeighborsFromNode(NId);
} else if (!NotProvablyAllocatableNodes.empty()) {
NodeSet::iterator NItr =
std::min_element(NotProvablyAllocatableNodes.begin(),
@ -493,7 +492,7 @@ private:
};
Graph& G;
typedef std::set<NodeId> NodeSet;
using NodeSet = std::set<NodeId>;
NodeSet OptimallyReducibleNodes;
NodeSet ConservativelyAllocatableNodes;
NodeSet NotProvablyAllocatableNodes;
@ -501,7 +500,7 @@ private:
class PBQPRAGraph : public PBQP::Graph<RegAllocSolverImpl> {
private:
typedef PBQP::Graph<RegAllocSolverImpl> BaseT;
using BaseT = PBQP::Graph<RegAllocSolverImpl>;
public:
PBQPRAGraph(GraphMetadata Metadata) : BaseT(std::move(Metadata)) {}

@ -204,6 +204,10 @@ private:
void setLiveInsUsed(const MachineBasicBlock &MBB);
};
/// Replaces all frame index virtual registers with physical registers. Uses the
/// register scavenger to find an appropriate register to use.
void scavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger &RS);
} // end namespace llvm
#endif // LLVM_CODEGEN_REGISTERSCAVENGING_H

@ -1,4 +1,4 @@
//==- ScheduleDAGInstrs.h - MachineInstr Scheduling --------------*- C++ -*-==//
//===- ScheduleDAGInstrs.h - MachineInstr Scheduling ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -15,22 +15,38 @@
#ifndef LLVM_CODEGEN_SCHEDULEDAGINSTRS_H
#define LLVM_CODEGEN_SCHEDULEDAGINSTRS_H
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SparseMultiSet.h"
#include "llvm/ADT/SparseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/ScheduleDAG.h"
#include "llvm/CodeGen/TargetSchedule.h"
#include "llvm/Support/Compiler.h"
#include "llvm/MC/LaneBitmask.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include <cassert>
#include <cstdint>
#include <list>
#include <utility>
#include <vector>
namespace llvm {
class LiveIntervals;
class MachineFrameInfo;
class MachineFunction;
class MachineInstr;
class MachineLoopInfo;
class MachineDominatorTree;
class RegPressureTracker;
class MachineOperand;
struct MCSchedClassDesc;
class PressureDiffs;
class PseudoSourceValue;
class RegPressureTracker;
class UndefValue;
class Value;
/// An individual mapping from virtual register number to SUnit.
struct VReg2SUnit {
@ -70,31 +86,34 @@ namespace llvm {
/// Use a SparseMultiSet to track physical registers. Storage is only
/// allocated once for the pass. It can be cleared in constant time and reused
/// without any frees.
typedef SparseMultiSet<PhysRegSUOper, llvm::identity<unsigned>, uint16_t>
Reg2SUnitsMap;
using Reg2SUnitsMap =
SparseMultiSet<PhysRegSUOper, identity<unsigned>, uint16_t>;
/// Use SparseSet as a SparseMap by relying on the fact that it never
/// compares ValueT's, only unsigned keys. This allows the set to be cleared
/// between scheduling regions in constant time as long as ValueT does not
/// require a destructor.
typedef SparseSet<VReg2SUnit, VirtReg2IndexFunctor> VReg2SUnitMap;
using VReg2SUnitMap = SparseSet<VReg2SUnit, VirtReg2IndexFunctor>;
/// Track local uses of virtual registers. These uses are gathered by the DAG
/// builder and may be consulted by the scheduler to avoid iterating an entire
/// vreg use list.
typedef SparseMultiSet<VReg2SUnit, VirtReg2IndexFunctor> VReg2SUnitMultiMap;
using VReg2SUnitMultiMap = SparseMultiSet<VReg2SUnit, VirtReg2IndexFunctor>;
typedef SparseMultiSet<VReg2SUnitOperIdx, VirtReg2IndexFunctor>
VReg2SUnitOperIdxMultiMap;
using VReg2SUnitOperIdxMultiMap =
SparseMultiSet<VReg2SUnitOperIdx, VirtReg2IndexFunctor>;
using ValueType = PointerUnion<const Value *, const PseudoSourceValue *>;
typedef PointerUnion<const Value *, const PseudoSourceValue *> ValueType;
struct UnderlyingObject : PointerIntPair<ValueType, 1, bool> {
UnderlyingObject(ValueType V, bool MayAlias)
: PointerIntPair<ValueType, 1, bool>(V, MayAlias) {}
ValueType getValue() const { return getPointer(); }
bool mayAlias() const { return getInt(); }
};
typedef SmallVector<UnderlyingObject, 4> UnderlyingObjectsVector;
using UnderlyingObjectsVector = SmallVector<UnderlyingObject, 4>;
/// A ScheduleDAG for scheduling lists of MachineInstr.
class ScheduleDAGInstrs : public ScheduleDAG {
@ -114,10 +133,10 @@ namespace llvm {
/// reordering. A specialized scheduler can override
/// TargetInstrInfo::isSchedulingBoundary then enable this flag to indicate
/// it has taken responsibility for scheduling the terminator correctly.
bool CanHandleTerminators;
bool CanHandleTerminators = false;
/// Whether lane masks should get tracked.
bool TrackLaneMasks;
bool TrackLaneMasks = false;
// State specific to the current scheduling region.
// ------------------------------------------------
@ -155,12 +174,12 @@ namespace llvm {
/// Tracks the last instructions in this region using each virtual register.
VReg2SUnitOperIdxMultiMap CurrentVRegUses;
AliasAnalysis *AAForDep;
AliasAnalysis *AAForDep = nullptr;
/// Remember a generic side-effecting instruction as we proceed.
/// No other SU ever gets scheduled around it (except in the special
/// case of a huge region that gets reduced).
SUnit *BarrierChain;
SUnit *BarrierChain = nullptr;
public:
/// A list of SUnits, used in Value2SUsMap, during DAG construction.
@ -168,7 +187,7 @@ namespace llvm {
/// implementation of this data structure, such as a singly linked list
/// with a memory pool (SmallVector was tried but slow and SparseSet is not
/// applicable).
typedef std::list<SUnit *> SUList;
using SUList = std::list<SUnit *>;
protected:
/// \brief A map from ValueType to SUList, used during DAG construction, as
@ -216,13 +235,13 @@ namespace llvm {
/// For an unanalyzable memory access, this Value is used in maps.
UndefValue *UnknownValue;
typedef std::vector<std::pair<MachineInstr *, MachineInstr *>>
DbgValueVector;
using DbgValueVector =
std::vector<std::pair<MachineInstr *, MachineInstr *>>;
/// Remember instruction that precedes DBG_VALUE.
/// These are generated by buildSchedGraph but persist so they can be
/// referenced when emitting the final schedule.
DbgValueVector DbgValues;
MachineInstr *FirstDbgValue;
MachineInstr *FirstDbgValue = nullptr;
/// Set of live physical registers for updating kill flags.
LivePhysRegs LiveRegs;
@ -232,7 +251,7 @@ namespace llvm {
const MachineLoopInfo *mli,
bool RemoveKillFlags = false);
~ScheduleDAGInstrs() override {}
~ScheduleDAGInstrs() override = default;
/// Gets the machine model for instruction scheduling.
const TargetSchedModel *getSchedModel() const { return &SchedModel; }
@ -354,6 +373,7 @@ namespace llvm {
return nullptr;
return I->second;
}
} // end namespace llvm
#endif
#endif // LLVM_CODEGEN_SCHEDULEDAGINSTRS_H

@ -1,4 +1,4 @@
//===-- llvm/CodeGen/SelectionDAG.h - InstSelection DAG ---------*- C++ -*-===//
//===- llvm/CodeGen/SelectionDAG.h - InstSelection DAG ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -15,35 +15,72 @@
#ifndef LLVM_CODEGEN_SELECTIONDAG_H
#define LLVM_CODEGEN_SELECTIONDAG_H
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/CodeGen/DAGCombine.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/ArrayRecycler.h"
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/RecyclingAllocator.h"
#include "llvm/Target/TargetMachine.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
namespace llvm {
class BlockAddress;
class Constant;
class ConstantFP;
class ConstantInt;
class DataLayout;
struct fltSemantics;
class GlobalValue;
struct KnownBits;
class LLVMContext;
class MachineBasicBlock;
class MachineConstantPoolValue;
class MachineFunction;
class MDNode;
class MCSymbol;
class OptimizationRemarkEmitter;
class SDDbgValue;
class TargetLowering;
class SelectionDAG;
class SelectionDAGTargetInfo;
class TargetLowering;
class TargetMachine;
class TargetSubtargetInfo;
class Value;
class SDVTListNode : public FoldingSetNode {
friend struct FoldingSetTrait<SDVTListNode>;
/// A reference to an Interned FoldingSetNodeID for this node.
/// The Allocator in SelectionDAG holds the data.
/// SDVTList contains all types which are frequently accessed in SelectionDAG.
@ -55,11 +92,13 @@ class SDVTListNode : public FoldingSetNode {
/// The hash value for SDVTList is fixed, so cache it to avoid
/// hash calculation.
unsigned HashValue;
public:
SDVTListNode(const FoldingSetNodeIDRef ID, const EVT *VT, unsigned int Num) :
FastID(ID), VTs(VT), NumVTs(Num) {
HashValue = ID.ComputeHash();
}
SDVTList getSDVTList() {
SDVTList result = {VTs, NumVTs};
return result;
@ -72,12 +111,14 @@ template<> struct FoldingSetTrait<SDVTListNode> : DefaultFoldingSetTrait<SDVTLis
static void Profile(const SDVTListNode &X, FoldingSetNodeID& ID) {
ID = X.FastID;
}
static bool Equals(const SDVTListNode &X, const FoldingSetNodeID &ID,
unsigned IDHash, FoldingSetNodeID &TempID) {
if (X.HashValue != IDHash)
return false;
return ID == X.FastID;
}
static unsigned ComputeHash(const SDVTListNode &X, FoldingSetNodeID &TempID) {
return X.HashValue;
}
@ -104,13 +145,13 @@ class SDDbgInfo {
BumpPtrAllocator Alloc;
SmallVector<SDDbgValue*, 32> DbgValues;
SmallVector<SDDbgValue*, 32> ByvalParmDbgValues;
typedef DenseMap<const SDNode*, SmallVector<SDDbgValue*, 2> > DbgValMapType;
using DbgValMapType = DenseMap<const SDNode *, SmallVector<SDDbgValue *, 2>>;
DbgValMapType DbgValMap;
void operator=(const SDDbgInfo&) = delete;
SDDbgInfo(const SDDbgInfo&) = delete;
public:
SDDbgInfo() {}
SDDbgInfo() = default;
SDDbgInfo(const SDDbgInfo &) = delete;
SDDbgInfo &operator=(const SDDbgInfo &) = delete;
void add(SDDbgValue *V, const SDNode *Node, bool isParameter) {
if (isParameter) {
@ -144,14 +185,14 @@ public:
return ArrayRef<SDDbgValue*>();
}
typedef SmallVectorImpl<SDDbgValue*>::iterator DbgIterator;
using DbgIterator = SmallVectorImpl<SDDbgValue*>::iterator;
DbgIterator DbgBegin() { return DbgValues.begin(); }
DbgIterator DbgEnd() { return DbgValues.end(); }
DbgIterator ByvalParmDbgBegin() { return ByvalParmDbgValues.begin(); }
DbgIterator ByvalParmDbgEnd() { return ByvalParmDbgValues.end(); }
};
class SelectionDAG;
void checkForCycles(const SelectionDAG *DAG, bool force = false);
/// This is used to represent a portion of an LLVM function in a low-level
@ -167,8 +208,8 @@ void checkForCycles(const SelectionDAG *DAG, bool force = false);
///
class SelectionDAG {
const TargetMachine &TM;
const SelectionDAGTargetInfo *TSI;
const TargetLowering *TLI;
const SelectionDAGTargetInfo *TSI = nullptr;
const TargetLowering *TLI = nullptr;
MachineFunction *MF;
LLVMContext *Context;
CodeGenOpt::Level OptLevel;
@ -188,9 +229,9 @@ class SelectionDAG {
/// The AllocatorType for allocating SDNodes. We use
/// pool allocation with recycling.
typedef RecyclingAllocator<BumpPtrAllocator, SDNode, sizeof(LargestSDNode),
alignof(MostAlignedSDNode)>
NodeAllocatorType;
using NodeAllocatorType = RecyclingAllocator<BumpPtrAllocator, SDNode,
sizeof(LargestSDNode),
alignof(MostAlignedSDNode)>;
/// Pool allocation for nodes.
NodeAllocatorType NodeAllocator;
@ -243,9 +284,11 @@ public:
struct DAGNodeDeletedListener : public DAGUpdateListener {
std::function<void(SDNode *, SDNode *)> Callback;
DAGNodeDeletedListener(SelectionDAG &DAG,
std::function<void(SDNode *, SDNode *)> Callback)
: DAGUpdateListener(DAG), Callback(std::move(Callback)) {}
void NodeDeleted(SDNode *N, SDNode *E) override { Callback(N, E); }
};
@ -254,7 +297,7 @@ public:
/// have legal types. This is important after type legalization since
/// any illegally typed nodes generated after this point will not experience
/// type legalization.
bool NewNodesMustHaveLegalTypes;
bool NewNodesMustHaveLegalTypes = false;
private:
/// DAGUpdateListener is a friend so it can manipulate the listener stack.
@ -262,7 +305,7 @@ private:
/// Linked list of registered DAGUpdateListener instances.
/// This stack is maintained by DAGUpdateListener RAII.
DAGUpdateListener *UpdateListeners;
DAGUpdateListener *UpdateListeners = nullptr;
/// Implementation of setSubgraphColor.
/// Return whether we had to truncate the search.
@ -316,11 +359,10 @@ private:
Node->OperandList = nullptr;
}
void operator=(const SelectionDAG&) = delete;
SelectionDAG(const SelectionDAG&) = delete;
public:
explicit SelectionDAG(const TargetMachine &TM, llvm::CodeGenOpt::Level);
explicit SelectionDAG(const TargetMachine &TM, CodeGenOpt::Level);
SelectionDAG(const SelectionDAG &) = delete;
SelectionDAG &operator=(const SelectionDAG &) = delete;
~SelectionDAG();
/// Prepare this SelectionDAG to process code in the given MachineFunction.
@ -364,12 +406,16 @@ public:
/// Convenience for setting subgraph color attribute.
void setSubgraphColor(SDNode *N, const char *Color);
typedef ilist<SDNode>::const_iterator allnodes_const_iterator;
using allnodes_const_iterator = ilist<SDNode>::const_iterator;
allnodes_const_iterator allnodes_begin() const { return AllNodes.begin(); }
allnodes_const_iterator allnodes_end() const { return AllNodes.end(); }
typedef ilist<SDNode>::iterator allnodes_iterator;
using allnodes_iterator = ilist<SDNode>::iterator;
allnodes_iterator allnodes_begin() { return AllNodes.begin(); }
allnodes_iterator allnodes_end() { return AllNodes.end(); }
ilist<SDNode>::size_type allnodes_size() const {
return AllNodes.size();
}
@ -475,7 +521,6 @@ public:
//===--------------------------------------------------------------------===//
// Node creation methods.
//
/// \brief Create a ConstantSDNode wrapping a constant value.
/// If VT is a vector type, the constant is splatted into a BUILD_VECTOR.
@ -1251,9 +1296,11 @@ public:
SDDbgInfo::DbgIterator DbgBegin() { return DbgInfo->DbgBegin(); }
SDDbgInfo::DbgIterator DbgEnd() { return DbgInfo->DbgEnd(); }
SDDbgInfo::DbgIterator ByvalParmDbgBegin() {
return DbgInfo->ByvalParmDbgBegin();
}
SDDbgInfo::DbgIterator ByvalParmDbgEnd() {
return DbgInfo->ByvalParmDbgEnd();
}
@ -1479,10 +1526,12 @@ private:
};
template <> struct GraphTraits<SelectionDAG*> : public GraphTraits<SDNode*> {
typedef pointer_iterator<SelectionDAG::allnodes_iterator> nodes_iterator;
using nodes_iterator = pointer_iterator<SelectionDAG::allnodes_iterator>;
static nodes_iterator nodes_begin(SelectionDAG *G) {
return nodes_iterator(G->allnodes_begin());
}
static nodes_iterator nodes_end(SelectionDAG *G) {
return nodes_iterator(G->allnodes_end());
}
@ -1493,7 +1542,6 @@ SDValue SelectionDAG::getTargetMemSDNode(SDVTList VTs,
ArrayRef<SDValue> Ops,
const SDLoc &dl, EVT MemVT,
MachineMemOperand *MMO) {
/// Compose node ID and try to find an existing node.
FoldingSetNodeID ID;
unsigned Opcode =
@ -1524,6 +1572,6 @@ SDValue SelectionDAG::getTargetMemSDNode(SDVTList VTs,
return SDValue(N, 0);
}
} // end namespace llvm
} // end namespace llvm
#endif
#endif // LLVM_CODEGEN_SELECTIONDAG_H

@ -37,6 +37,7 @@
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/AlignOf.h"
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/Casting.h"
@ -53,14 +54,18 @@
namespace llvm {
class SelectionDAG;
class APInt;
class Constant;
template <typename T> struct DenseMapInfo;
class GlobalValue;
class MachineBasicBlock;
class MachineConstantPoolValue;
class SDNode;
class Value;
class MCSymbol;
template <typename T> struct DenseMapInfo;
class raw_ostream;
class SDNode;
class SelectionDAG;
class Type;
class Value;
void checkForCycles(const SDNode *N, const SelectionDAG *DAG = nullptr,
bool force = false);
@ -229,13 +234,15 @@ template <> struct isPodLike<SDValue> { static const bool value = true; };
/// Allow casting operators to work directly on
/// SDValues as if they were SDNode*'s.
template<> struct simplify_type<SDValue> {
typedef SDNode* SimpleType;
using SimpleType = SDNode *;
static SimpleType getSimplifiedValue(SDValue &Val) {
return Val.getNode();
}
};
template<> struct simplify_type<const SDValue> {
typedef /*const*/ SDNode* SimpleType;
using SimpleType = /*const*/ SDNode *;
static SimpleType getSimplifiedValue(const SDValue &Val) {
return Val.getNode();
}
@ -330,7 +337,8 @@ private:
/// simplify_type specializations - Allow casting operators to work directly on
/// SDValues as if they were SDNode*'s.
template<> struct simplify_type<SDUse> {
typedef SDNode* SimpleType;
using SimpleType = SDNode *;
static SimpleType getSimplifiedValue(SDUse &Val) {
return Val.getNode();
}
@ -695,10 +703,10 @@ public:
explicit use_iterator(SDUse *op) : Op(op) {}
public:
typedef std::iterator<std::forward_iterator_tag,
SDUse, ptrdiff_t>::reference reference;
typedef std::iterator<std::forward_iterator_tag,
SDUse, ptrdiff_t>::pointer pointer;
using reference = std::iterator<std::forward_iterator_tag,
SDUse, ptrdiff_t>::reference;
using pointer = std::iterator<std::forward_iterator_tag,
SDUse, ptrdiff_t>::pointer;
use_iterator() = default;
use_iterator(const use_iterator &I) : Op(I.Op) {}
@ -824,7 +832,7 @@ public:
return OperandList[Num];
}
typedef SDUse* op_iterator;
using op_iterator = SDUse *;
op_iterator op_begin() const { return OperandList; }
op_iterator op_end() const { return OperandList+NumOperands; }
@ -896,7 +904,8 @@ public:
return getValueType(ResNo).getSizeInBits();
}
typedef const EVT* value_iterator;
using value_iterator = const EVT *;
value_iterator value_begin() const { return ValueList; }
value_iterator value_end() const { return ValueList+NumValues; }
@ -1822,8 +1831,7 @@ class BlockAddressSDNode : public SDNode {
BlockAddressSDNode(unsigned NodeTy, EVT VT, const BlockAddress *ba,
int64_t o, unsigned char Flags)
: SDNode(NodeTy, 0, DebugLoc(), getSDVTList(VT)),
BA(ba), Offset(o), TargetFlags(Flags) {
}
BA(ba), Offset(o), TargetFlags(Flags) {}
public:
const BlockAddress *getBlockAddress() const { return BA; }
@ -2154,7 +2162,7 @@ public:
/// instruction selection proper phase.
class MachineSDNode : public SDNode {
public:
typedef MachineMemOperand **mmo_iterator;
using mmo_iterator = MachineMemOperand **;
private:
friend class SelectionDAG;
@ -2226,8 +2234,8 @@ public:
};
template <> struct GraphTraits<SDNode*> {
typedef SDNode *NodeRef;
typedef SDNodeIterator ChildIteratorType;
using NodeRef = SDNode *;
using ChildIteratorType = SDNodeIterator;
static NodeRef getEntryNode(SDNode *N) { return N; }
@ -2244,12 +2252,12 @@ template <> struct GraphTraits<SDNode*> {
///
/// This needs to be a union because the largest node differs on 32 bit systems
/// with 4 and 8 byte pointer alignment, respectively.
typedef AlignedCharArrayUnion<AtomicSDNode, TargetIndexSDNode,
BlockAddressSDNode, GlobalAddressSDNode>
LargestSDNode;
using LargestSDNode = AlignedCharArrayUnion<AtomicSDNode, TargetIndexSDNode,
BlockAddressSDNode,
GlobalAddressSDNode>;
/// The SDNode class with the greatest alignment requirement.
typedef GlobalAddressSDNode MostAlignedSDNode;
using MostAlignedSDNode = GlobalAddressSDNode;
namespace ISD {

@ -20,17 +20,26 @@
#define LLVM_CODEGEN_SLOTINDEXES_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/IntervalMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/ilist.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBundle.h"
#include "llvm/Pass.h"
#include "llvm/Support/Allocator.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <utility>
namespace llvm {
class raw_ostream;
/// This class represents an entry in the slot index list held in the
/// SlotIndexes pass. It should not be used directly. See the
/// SlotIndex & SlotIndexes classes for the public interface to this
@ -40,7 +49,6 @@ namespace llvm {
unsigned index;
public:
IndexListEntry(MachineInstr *mi, unsigned index) : mi(mi), index(index) {}
MachineInstr* getInstr() const { return mi; }
@ -301,7 +309,7 @@ namespace llvm {
return os;
}
typedef std::pair<SlotIndex, MachineBasicBlock*> IdxMBBPair;
using IdxMBBPair = std::pair<SlotIndex, MachineBasicBlock *>;
inline bool operator<(SlotIndex V, const IdxMBBPair &IM) {
return V < IM.first;
@ -325,7 +333,7 @@ namespace llvm {
// IndexListEntry allocator.
BumpPtrAllocator ileAllocator;
typedef ilist<IndexListEntry> IndexList;
using IndexList = ilist<IndexListEntry>;
IndexList indexList;
#ifdef EXPENSIVE_CHECKS
@ -334,7 +342,7 @@ namespace llvm {
MachineFunction *mf;
typedef DenseMap<const MachineInstr*, SlotIndex> Mi2IndexMap;
using Mi2IndexMap = DenseMap<const MachineInstr *, SlotIndex>;
Mi2IndexMap mi2iMap;
/// MBBRanges - Map MBB number to (start, stop) indexes.
@ -436,7 +444,7 @@ namespace llvm {
const MachineBasicBlock *MBB = MI.getParent();
assert(MBB && "MI must be inserted inna basic block");
MachineBasicBlock::const_iterator I = MI, B = MBB->begin();
for (;;) {
while (true) {
if (I == B)
return getMBBStartIdx(MBB);
--I;
@ -453,7 +461,7 @@ namespace llvm {
const MachineBasicBlock *MBB = MI.getParent();
assert(MBB && "MI must be inserted inna basic block");
MachineBasicBlock::const_iterator I = MI, E = MBB->end();
for (;;) {
while (true) {
++I;
if (I == E)
return getMBBEndIdx(MBB);
@ -497,21 +505,25 @@ namespace llvm {
/// Iterator over the idx2MBBMap (sorted pairs of slot index of basic block
/// begin and basic block)
typedef SmallVectorImpl<IdxMBBPair>::const_iterator MBBIndexIterator;
using MBBIndexIterator = SmallVectorImpl<IdxMBBPair>::const_iterator;
/// Move iterator to the next IdxMBBPair where the SlotIndex is greater or
/// equal to \p To.
MBBIndexIterator advanceMBBIndex(MBBIndexIterator I, SlotIndex To) const {
return std::lower_bound(I, idx2MBBMap.end(), To);
}
/// Get an iterator pointing to the IdxMBBPair with the biggest SlotIndex
/// that is greater or equal to \p Idx.
MBBIndexIterator findMBBIndex(SlotIndex Idx) const {
return advanceMBBIndex(idx2MBBMap.begin(), Idx);
}
/// Returns an iterator for the begin of the idx2MBBMap.
MBBIndexIterator MBBIndexBegin() const {
return idx2MBBMap.begin();
}
/// Return an iterator for the end of the idx2MBBMap.
MBBIndexIterator MBBIndexEnd() const {
return idx2MBBMap.end();

@ -145,21 +145,27 @@ public:
///
/// Statepoint operands take the form:
/// <id>, <num patch bytes >, <num call arguments>, <call target>,
/// [call arguments], <StackMaps::ConstantOp>, <calling convention>,
/// [call arguments...],
/// <StackMaps::ConstantOp>, <calling convention>,
/// <StackMaps::ConstantOp>, <statepoint flags>,
/// <StackMaps::ConstantOp>, <num other args>, [other args],
/// [gc values]
/// <StackMaps::ConstantOp>, <num deopt args>, [deopt args...],
/// <gc base/derived pairs...> <gc allocas...>
/// Note that the last two sets of arguments are not currently length
/// prefixed.
class StatepointOpers {
private:
// TODO:: we should change the STATEPOINT representation so that CC and
// Flags should be part of meta operands, with args and deopt operands, and
// gc operands all prefixed by their length and a type code. This would be
// much more consistent.
public:
// These values are aboolute offsets into the operands of the statepoint
// instruction.
enum { IDPos, NBytesPos, NCallArgsPos, CallTargetPos, MetaEnd };
// These values are relative offests from the start of the statepoint meta
// arguments (i.e. the end of the call arguments).
enum { CCOffset = 1, FlagsOffset = 3, NumVMSArgsOffset = 5 };
enum { CCOffset = 1, FlagsOffset = 3, NumDeoptOperandsOffset = 5 };
public:
explicit StatepointOpers(const MachineInstr *MI) : MI(MI) {}
/// Get starting index of non call related arguments
@ -220,7 +226,7 @@ public:
// OpTypes are used to encode information about the following logical
// operand (which may consist of several MachineOperands) for the
// OpParser.
typedef enum { DirectMemRefOp, IndirectMemRefOp, ConstantOp } OpType;
using OpType = enum { DirectMemRefOp, IndirectMemRefOp, ConstantOp };
StackMaps(AsmPrinter &AP);
@ -248,9 +254,10 @@ public:
private:
static const char *WSMP;
typedef SmallVector<Location, 8> LocationVec;
typedef SmallVector<LiveOutReg, 8> LiveOutVec;
typedef MapVector<uint64_t, uint64_t> ConstantPool;
using LocationVec = SmallVector<Location, 8>;
using LiveOutVec = SmallVector<LiveOutReg, 8>;
using ConstantPool = MapVector<uint64_t, uint64_t>;
struct FunctionInfo {
uint64_t StackSize = 0;
@ -273,8 +280,8 @@ private:
LiveOuts(std::move(LiveOuts)) {}
};
typedef MapVector<const MCSymbol *, FunctionInfo> FnInfoMap;
typedef std::vector<CallsiteInfo> CallsiteInfoList;
using FnInfoMap = MapVector<const MCSymbol *, FunctionInfo>;
using CallsiteInfoList = std::vector<CallsiteInfo>;
AsmPrinter &AP;
CallsiteInfoList CSInfos;

@ -55,6 +55,9 @@ public:
/// Return the MCSchedClassDesc for this instruction.
const MCSchedClassDesc *resolveSchedClass(const MachineInstr *MI) const;
/// \brief TargetSubtargetInfo getter.
const TargetSubtargetInfo *getSubtargetInfo() const { return STI; }
/// \brief TargetInstrInfo getter.
const TargetInstrInfo *getInstrInfo() const { return TII; }

@ -1,4 +1,4 @@
//===-- llvm/CodeGen/WinEHFuncInfo.h ----------------------------*- C++ -*-===//
//===- llvm/CodeGen/WinEHFuncInfo.h -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -17,28 +17,26 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/IR/Instructions.h"
#include <cstdint>
#include <limits>
#include <utility>
namespace llvm {
class AllocaInst;
class BasicBlock;
class CatchReturnInst;
class Constant;
class FuncletPadInst;
class Function;
class GlobalVariable;
class Instruction;
class InvokeInst;
class IntrinsicInst;
class LandingPadInst;
class MCExpr;
class MCSymbol;
class MachineBasicBlock;
class Value;
class MCSymbol;
// The following structs respresent the .xdata tables for various
// Windows-related EH personalities.
typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
using MBBOrBasicBlock = PointerUnion<const BasicBlock *, MachineBasicBlock *>;
struct CxxUnwindMapEntry {
int ToState;
@ -99,18 +97,18 @@ struct WinEHFuncInfo {
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
SmallVector<ClrEHUnwindMapEntry, 4> ClrEHUnwindMap;
int UnwindHelpFrameIdx = INT_MAX;
int PSPSymFrameIdx = INT_MAX;
int UnwindHelpFrameIdx = std::numeric_limits<int>::max();
int PSPSymFrameIdx = std::numeric_limits<int>::max();
int getLastStateNumber() const { return CxxUnwindMap.size() - 1; }
void addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin,
MCSymbol *InvokeEnd);
int EHRegNodeFrameIndex = INT_MAX;
int EHRegNodeEndOffset = INT_MAX;
int EHGuardFrameIndex = INT_MAX;
int SEHSetFrameOffset = INT_MAX;
int EHRegNodeFrameIndex = std::numeric_limits<int>::max();
int EHRegNodeEndOffset = std::numeric_limits<int>::max();
int EHGuardFrameIndex = std::numeric_limits<int>::max();
int SEHSetFrameOffset = std::numeric_limits<int>::max();
WinEHFuncInfo();
};
@ -125,5 +123,7 @@ void calculateSEHStateNumbers(const Function *ParentFn,
WinEHFuncInfo &FuncInfo);
void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
}
} // end namespace llvm
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H

@ -574,6 +574,14 @@ struct FrameData {
IsFunctionStart = 1 << 2,
};
};
enum class CodeViewContainer { ObjectFile, Pdb };
inline uint32_t alignOf(CodeViewContainer Container) {
if (Container == CodeViewContainer::ObjectFile)
return 1;
return 4;
}
}
}

@ -136,6 +136,7 @@ public:
Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes);
Error mapByteVectorTail(std::vector<uint8_t> &Bytes);
Error padToAlignment(uint32_t Align);
Error skipPadding();
private:

@ -60,8 +60,8 @@ public:
Error initialize(BinaryStreamReader Reader);
Error initialize(BinaryStreamRef Stream);
Iterator begin() { return Checksums.begin(); }
Iterator end() { return Checksums.end(); }
Iterator begin() const { return Checksums.begin(); }
Iterator end() const { return Checksums.end(); }
const FileChecksumArray &getArray() const { return Checksums; }

@ -74,8 +74,13 @@ private:
class DebugInlineeLinesSubsection final : public DebugSubsection {
public:
struct Entry {
std::vector<support::ulittle32_t> ExtraFiles;
InlineeSourceLineHeader Header;
};
DebugInlineeLinesSubsection(DebugChecksumsSubsection &Checksums,
bool HasExtraFiles);
bool HasExtraFiles = false);
static bool classof(const DebugSubsection *S) {
return S->kind() == DebugSubsectionKind::InlineeLines;
@ -87,16 +92,18 @@ public:
void addInlineSite(TypeIndex FuncId, StringRef FileName, uint32_t SourceLine);
void addExtraFile(StringRef FileName);
bool hasExtraFiles() const { return HasExtraFiles; }
void setHasExtraFiles(bool Has) { HasExtraFiles = Has; }
std::vector<Entry>::const_iterator begin() const { return Entries.begin(); }
std::vector<Entry>::const_iterator end() const { return Entries.end(); }
private:
DebugChecksumsSubsection &Checksums;
bool HasExtraFiles = false;
uint32_t ExtraFileCount = 0;
struct Entry {
std::vector<support::ulittle32_t> ExtraFiles;
InlineeSourceLineHeader Header;
};
std::vector<Entry> Entries;
};
}

@ -31,28 +31,32 @@ struct DebugSubsectionHeader {
class DebugSubsectionRecord {
public:
DebugSubsectionRecord();
DebugSubsectionRecord(DebugSubsectionKind Kind, BinaryStreamRef Data);
DebugSubsectionRecord(DebugSubsectionKind Kind, BinaryStreamRef Data,
CodeViewContainer Container);
static Error initialize(BinaryStreamRef Stream, DebugSubsectionRecord &Info);
static Error initialize(BinaryStreamRef Stream, DebugSubsectionRecord &Info,
CodeViewContainer Container);
uint32_t getRecordLength() const;
DebugSubsectionKind kind() const;
BinaryStreamRef getRecordData() const;
private:
CodeViewContainer Container;
DebugSubsectionKind Kind;
BinaryStreamRef Data;
};
class DebugSubsectionRecordBuilder {
public:
DebugSubsectionRecordBuilder(DebugSubsectionKind Kind, DebugSubsection &Frag);
DebugSubsectionRecordBuilder(std::unique_ptr<DebugSubsection> Subsection,
CodeViewContainer Container);
uint32_t calculateSerializedLength();
Error commit(BinaryStreamWriter &Writer);
private:
DebugSubsectionKind Kind;
DebugSubsection &Frag;
std::unique_ptr<DebugSubsection> Subsection;
CodeViewContainer Container;
};
} // namespace codeview
@ -62,7 +66,12 @@ template <> struct VarStreamArrayExtractor<codeview::DebugSubsectionRecord> {
static Error extract(BinaryStreamRef Stream, uint32_t &Length,
codeview::DebugSubsectionRecord &Info) {
if (auto EC = codeview::DebugSubsectionRecord::initialize(Stream, Info))
// FIXME: We need to pass the container type through to this function, but
// VarStreamArray doesn't easily support stateful contexts. In practice
// this isn't super important since the subsection header describes its
// length and we can just skip it. It's more important when writing.
if (auto EC = codeview::DebugSubsectionRecord::initialize(
Stream, Info, codeview::CodeViewContainer::Pdb))
return EC;
Length = Info.getRecordLength();
return Error::success();

@ -24,9 +24,9 @@ namespace codeview {
class SymbolVisitorDelegate;
class SymbolDeserializer : public SymbolVisitorCallbacks {
struct MappingInfo {
explicit MappingInfo(ArrayRef<uint8_t> RecordData)
MappingInfo(ArrayRef<uint8_t> RecordData, CodeViewContainer Container)
: Stream(RecordData, llvm::support::little), Reader(Stream),
Mapping(Reader) {}
Mapping(Reader, Container) {}
BinaryByteStream Stream;
BinaryStreamReader Reader;
@ -35,7 +35,9 @@ class SymbolDeserializer : public SymbolVisitorCallbacks {
public:
template <typename T> static Error deserializeAs(CVSymbol Symbol, T &Record) {
SymbolDeserializer S(nullptr);
// If we're just deserializing one record, then don't worry about alignment
// as there's nothing that comes after.
SymbolDeserializer S(nullptr, CodeViewContainer::ObjectFile);
if (auto EC = S.visitSymbolBegin(Symbol))
return EC;
if (auto EC = S.visitKnownRecord(Symbol, Record))
@ -45,12 +47,13 @@ public:
return Error::success();
}
explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate)
: Delegate(Delegate) {}
explicit SymbolDeserializer(SymbolVisitorDelegate *Delegate,
CodeViewContainer Container)
: Delegate(Delegate), Container(Container) {}
Error visitSymbolBegin(CVSymbol &Record) override {
assert(!Mapping && "Already in a symbol mapping!");
Mapping = llvm::make_unique<MappingInfo>(Record.content());
Mapping = llvm::make_unique<MappingInfo>(Record.content(), Container);
return Mapping->Mapping.visitSymbolBegin(Record);
}
Error visitSymbolEnd(CVSymbol &Record) override {
@ -78,6 +81,7 @@ private:
}
SymbolVisitorDelegate *Delegate;
CodeViewContainer Container;
std::unique_ptr<MappingInfo> Mapping;
};
}

@ -26,9 +26,11 @@ class TypeCollection;
class CVSymbolDumper {
public:
CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types,
CodeViewContainer Container,
std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
bool PrintRecordBytes)
: W(W), Types(Types), ObjDelegate(std::move(ObjDelegate)),
: W(W), Types(Types), Container(Container),
ObjDelegate(std::move(ObjDelegate)),
PrintRecordBytes(PrintRecordBytes) {}
/// Dumps one type record. Returns false if there was a type parsing error,
@ -44,6 +46,7 @@ public:
private:
ScopedPrinter &W;
TypeCollection &Types;
CodeViewContainer Container;
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
bool PrintRecordBytes;

@ -20,8 +20,12 @@ class BinaryStreamWriter;
namespace codeview {
class SymbolRecordMapping : public SymbolVisitorCallbacks {
public:
explicit SymbolRecordMapping(BinaryStreamReader &Reader) : IO(Reader) {}
explicit SymbolRecordMapping(BinaryStreamWriter &Writer) : IO(Writer) {}
explicit SymbolRecordMapping(BinaryStreamReader &Reader,
CodeViewContainer Container)
: IO(Reader), Container(Container) {}
explicit SymbolRecordMapping(BinaryStreamWriter &Writer,
CodeViewContainer Container)
: IO(Writer), Container(Container) {}
Error visitSymbolBegin(CVSymbol &Record) override;
Error visitSymbolEnd(CVSymbol &Record) override;
@ -35,6 +39,7 @@ private:
Optional<SymbolKind> Kind;
CodeViewRecordIO IO;
CodeViewContainer Container;
};
}
}

@ -46,17 +46,18 @@ class SymbolSerializer : public SymbolVisitorCallbacks {
public:
template <typename SymType>
static CVSymbol writeOneSymbol(SymType &Sym, BumpPtrAllocator &Storage) {
static CVSymbol writeOneSymbol(SymType &Sym, BumpPtrAllocator &Storage,
CodeViewContainer Container) {
CVSymbol Result;
Result.Type = static_cast<SymbolKind>(Sym.Kind);
SymbolSerializer Serializer(Storage);
SymbolSerializer Serializer(Storage, Container);
consumeError(Serializer.visitSymbolBegin(Result));
consumeError(Serializer.visitKnownRecord(Result, Sym));
consumeError(Serializer.visitSymbolEnd(Result));
return Result;
}
explicit SymbolSerializer(BumpPtrAllocator &Storage);
SymbolSerializer(BumpPtrAllocator &Storage, CodeViewContainer Container);
virtual Error visitSymbolBegin(CVSymbol &Record) override;
virtual Error visitSymbolEnd(CVSymbol &Record) override;

@ -44,17 +44,19 @@ class MappedBlockStream : public BinaryStream {
public:
static std::unique_ptr<MappedBlockStream>
createStream(uint32_t BlockSize, const MSFStreamLayout &Layout,
BinaryStreamRef MsfData);
BinaryStreamRef MsfData, BumpPtrAllocator &Allocator);
static std::unique_ptr<MappedBlockStream>
createIndexedStream(const MSFLayout &Layout, BinaryStreamRef MsfData,
uint32_t StreamIndex);
uint32_t StreamIndex, BumpPtrAllocator &Allocator);
static std::unique_ptr<MappedBlockStream>
createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData);
createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData,
BumpPtrAllocator &Allocator);
static std::unique_ptr<MappedBlockStream>
createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData);
createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData,
BumpPtrAllocator &Allocator);
llvm::support::endianness getEndian() const override {
return llvm::support::little;
@ -67,9 +69,7 @@ public:
uint32_t getLength() override;
uint32_t getNumBytesCopied() const;
llvm::BumpPtrAllocator &getAllocator() { return Pool; }
llvm::BumpPtrAllocator &getAllocator() { return Allocator; }
void invalidateCache();
@ -79,7 +79,7 @@ public:
protected:
MappedBlockStream(uint32_t BlockSize, const MSFStreamLayout &StreamLayout,
BinaryStreamRef MsfData);
BinaryStreamRef MsfData, BumpPtrAllocator &Allocator);
private:
const MSFStreamLayout &getStreamLayout() const { return StreamLayout; }
@ -94,7 +94,15 @@ private:
BinaryStreamRef MsfData;
typedef MutableArrayRef<uint8_t> CacheEntry;
llvm::BumpPtrAllocator Pool;
// We just store the allocator by reference. We use this to allocate
// contiguous memory for things like arrays or strings that cross a block
// boundary, and this memory is expected to outlive the stream. For example,
// someone could create a stream, read some stuff, then close the stream, and
// we would like outstanding references to fields to remain valid since the
// entire file is mapped anyway. Because of that, the user must supply the
// allocator to allocate broken records from.
BumpPtrAllocator &Allocator;
DenseMap<uint32_t, std::vector<CacheEntry>> CacheMap;
};
@ -102,18 +110,20 @@ class WritableMappedBlockStream : public WritableBinaryStream {
public:
static std::unique_ptr<WritableMappedBlockStream>
createStream(uint32_t BlockSize, const MSFStreamLayout &Layout,
WritableBinaryStreamRef MsfData);
WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator);
static std::unique_ptr<WritableMappedBlockStream>
createIndexedStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData,
uint32_t StreamIndex);
uint32_t StreamIndex, BumpPtrAllocator &Allocator);
static std::unique_ptr<WritableMappedBlockStream>
createDirectoryStream(const MSFLayout &Layout,
WritableBinaryStreamRef MsfData);
WritableBinaryStreamRef MsfData,
BumpPtrAllocator &Allocator);
static std::unique_ptr<WritableMappedBlockStream>
createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData);
createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData,
BumpPtrAllocator &Allocator);
llvm::support::endianness getEndian() const override {
return llvm::support::little;
@ -139,7 +149,8 @@ public:
protected:
WritableMappedBlockStream(uint32_t BlockSize,
const MSFStreamLayout &StreamLayout,
WritableBinaryStreamRef MsfData);
WritableBinaryStreamRef MsfData,
BumpPtrAllocator &Allocator);
private:
MappedBlockStream ReadInterface;

@ -49,11 +49,8 @@ public:
void setObjFileName(StringRef Name);
void addSymbol(codeview::CVSymbol Symbol);
void addC13Fragment(std::unique_ptr<codeview::DebugLinesSubsection> Lines);
void addC13Fragment(
std::unique_ptr<codeview::DebugInlineeLinesSubsection> Inlinees);
void setC13FileChecksums(
std::unique_ptr<codeview::DebugChecksumsSubsection> Checksums);
void
addDebugSubsection(std::unique_ptr<codeview::DebugSubsection> Subsection);
uint16_t getStreamIndex() const;
StringRef getModuleName() const { return ModuleName; }
@ -83,10 +80,6 @@ private:
std::vector<std::string> SourceFiles;
std::vector<codeview::CVSymbol> Symbols;
std::unique_ptr<codeview::DebugChecksumsSubsection> ChecksumInfo;
std::vector<std::unique_ptr<codeview::DebugLinesSubsection>> LineInfo;
std::vector<std::unique_ptr<codeview::DebugInlineeLinesSubsection>> Inlinees;
std::vector<std::unique_ptr<codeview::DebugSubsectionRecordBuilder>>
C13Builders;

@ -12,6 +12,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
@ -25,7 +26,7 @@ class PDBFile;
class DbiModuleDescriptor;
class ModuleDebugStreamRef {
typedef codeview::DebugSubsectionArray::Iterator LinesAndChecksumsIterator;
typedef codeview::DebugSubsectionArray::Iterator DebugSubsectionIterator;
public:
ModuleDebugStreamRef(const DbiModuleDescriptor &Module,
@ -39,12 +40,15 @@ public:
iterator_range<codeview::CVSymbolArray::Iterator>
symbols(bool *HadError) const;
llvm::iterator_range<LinesAndChecksumsIterator> linesAndChecksums() const;
llvm::iterator_range<DebugSubsectionIterator> subsections() const;
bool hasLineInfo() const;
bool hasDebugSubsections() const;
Error commit();
Expected<codeview::DebugChecksumsSubsectionRef>
findChecksumsSubsection() const;
private:
const DbiModuleDescriptor &Mod;
@ -57,7 +61,7 @@ private:
BinaryStreamRef C13LinesSubstream;
BinaryStreamRef GlobalRefsSubstream;
codeview::DebugSubsectionArray LinesAndChecksums;
codeview::DebugSubsectionArray Subsections;
};
}
}

@ -45,6 +45,8 @@ public:
FixedStreamArray<support::ulittle32_t> name_ids() const;
codeview::DebugStringTableSubsectionRef getStringTable() const;
private:
Error readHeader(BinaryStreamReader &Reader);
Error readStrings(BinaryStreamReader &Reader);

@ -34,8 +34,7 @@ class TpiStream {
friend class TpiStreamBuilder;
public:
TpiStream(const PDBFile &File,
std::unique_ptr<msf::MappedBlockStream> Stream);
TpiStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream);
~TpiStream();
Error reload();
@ -61,7 +60,7 @@ public:
Error commit();
private:
const PDBFile &Pdb;
PDBFile &Pdb;
std::unique_ptr<msf::MappedBlockStream> Stream;
std::unique_ptr<codeview::LazyRandomTypeCollection> Types;

@ -86,6 +86,10 @@ namespace llvm {
/// Construct any deferred debug info descriptors.
void finalize();
/// Finalize a specific subprogram - no new variables may be added to this
/// subprogram afterwards.
void finalizeSubprogram(DISubprogram *SP);
/// A CompileUnit provides an anchor for all debugging
/// information generated during this instance of compilation.
/// \param Lang Source programming language, eg. dwarf::DW_LANG_C99

@ -90,12 +90,6 @@ namespace llvm {
DenseMap<const MDNode *, MDNode *> &Cache,
bool ReplaceLast = false);
/// Reparent all debug locations referenced by \c I that belong to \c OrigSP
/// to become (possibly indirect) children of \c NewSP.
static void reparentDebugInfo(Instruction &I, DISubprogram *OrigSP,
DISubprogram *NewSP,
DenseMap<const MDNode *, MDNode *> &Cache);
unsigned getLine() const;
unsigned getCol() const;
MDNode *getScope() const;

@ -134,16 +134,18 @@ public:
/// be renamed or references something that can't be renamed).
unsigned NotEligibleToImport : 1;
/// Indicate that the global value must be considered a live root for
/// index-based liveness analysis. Used for special LLVM values such as
/// llvm.global_ctors that the linker does not know about.
unsigned LiveRoot : 1;
/// In per-module summary, indicate that the global value must be considered
/// a live root for index-based liveness analysis. Used for special LLVM
/// values such as llvm.global_ctors that the linker does not know about.
///
/// In combined summary, indicate that the global value is live.
unsigned Live : 1;
/// Convenience Constructors
explicit GVFlags(GlobalValue::LinkageTypes Linkage,
bool NotEligibleToImport, bool LiveRoot)
bool NotEligibleToImport, bool Live)
: Linkage(Linkage), NotEligibleToImport(NotEligibleToImport),
LiveRoot(LiveRoot) {}
Live(Live) {}
};
private:
@ -172,6 +174,8 @@ private:
/// are listed in the derived FunctionSummary object.
std::vector<ValueInfo> RefEdgeList;
bool isLive() const { return Flags.Live; }
protected:
GlobalValueSummary(SummaryKind K, GVFlags Flags, std::vector<ValueInfo> Refs)
: Kind(K), Flags(Flags), RefEdgeList(std::move(Refs)) {}
@ -213,19 +217,17 @@ public:
/// Return true if this global value can't be imported.
bool notEligibleToImport() const { return Flags.NotEligibleToImport; }
/// Return true if this global value must be considered a root for live
/// value analysis on the index.
bool liveRoot() const { return Flags.LiveRoot; }
/// Flag that this global value must be considered a root for live
/// value analysis on the index.
void setLiveRoot() { Flags.LiveRoot = true; }
void setLive(bool Live) { Flags.Live = Live; }
/// Flag that this global value cannot be imported.
void setNotEligibleToImport() { Flags.NotEligibleToImport = true; }
/// Return the list of values referenced by this global value definition.
ArrayRef<ValueInfo> refs() const { return RefEdgeList; }
friend class ModuleSummaryIndex;
friend void computeDeadSymbols(class ModuleSummaryIndex &,
const DenseSet<GlobalValue::GUID> &);
};
/// \brief Alias summary information.
@ -535,6 +537,11 @@ private:
/// GUIDs, it will be mapped to 0.
std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap;
/// Indicates that summary-based GlobalValue GC has run, and values with
/// GVFlags::Live==false are really dead. Otherwise, all values must be
/// considered live.
bool WithGlobalValueDeadStripping = false;
// YAML I/O support.
friend yaml::MappingTraits<ModuleSummaryIndex>;
@ -550,6 +557,17 @@ public:
const_gvsummary_iterator end() const { return GlobalValueMap.end(); }
size_t size() const { return GlobalValueMap.size(); }
bool withGlobalValueDeadStripping() const {
return WithGlobalValueDeadStripping;
}
void setWithGlobalValueDeadStripping() {
WithGlobalValueDeadStripping = true;
}
bool isGlobalValueLive(const GlobalValueSummary *GVS) const {
return !WithGlobalValueDeadStripping || GVS->isLive();
}
/// Return a ValueInfo for GUID if it exists, otherwise return ValueInfo().
ValueInfo getValueInfo(GlobalValue::GUID GUID) const {
auto I = GlobalValueMap.find(GUID);

@ -128,6 +128,8 @@ template <> struct MappingTraits<TypeIdSummary> {
};
struct FunctionSummaryYaml {
unsigned Linkage;
bool NotEligibleToImport, Live;
std::vector<uint64_t> TypeTests;
std::vector<FunctionSummary::VFuncId> TypeTestAssumeVCalls,
TypeCheckedLoadVCalls;
@ -168,6 +170,9 @@ namespace yaml {
template <> struct MappingTraits<FunctionSummaryYaml> {
static void mapping(IO &io, FunctionSummaryYaml& summary) {
io.mapOptional("Linkage", summary.Linkage);
io.mapOptional("NotEligibleToImport", summary.NotEligibleToImport);
io.mapOptional("Live", summary.Live);
io.mapOptional("TypeTests", summary.TypeTests);
io.mapOptional("TypeTestAssumeVCalls", summary.TypeTestAssumeVCalls);
io.mapOptional("TypeCheckedLoadVCalls", summary.TypeCheckedLoadVCalls);
@ -199,12 +204,12 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
}
auto &Elem = V[KeyInt];
for (auto &FSum : FSums) {
GlobalValueSummary::GVFlags GVFlags(GlobalValue::ExternalLinkage, false,
false);
Elem.SummaryList.push_back(llvm::make_unique<FunctionSummary>(
GVFlags, 0, ArrayRef<ValueInfo>{},
ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests),
std::move(FSum.TypeTestAssumeVCalls),
GlobalValueSummary::GVFlags(
static_cast<GlobalValue::LinkageTypes>(FSum.Linkage),
FSum.NotEligibleToImport, FSum.Live),
0, ArrayRef<ValueInfo>{}, ArrayRef<FunctionSummary::EdgeTy>{},
std::move(FSum.TypeTests), std::move(FSum.TypeTestAssumeVCalls),
std::move(FSum.TypeCheckedLoadVCalls),
std::move(FSum.TypeTestAssumeConstVCalls),
std::move(FSum.TypeCheckedLoadConstVCalls)));
@ -216,8 +221,10 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
for (auto &Sum : P.second.SummaryList) {
if (auto *FSum = dyn_cast<FunctionSummary>(Sum.get()))
FSums.push_back(FunctionSummaryYaml{
FSum->type_tests(), FSum->type_test_assume_vcalls(),
FSum->type_checked_load_vcalls(),
FSum->flags().Linkage,
static_cast<bool>(FSum->flags().NotEligibleToImport),
static_cast<bool>(FSum->flags().Live), FSum->type_tests(),
FSum->type_test_assume_vcalls(), FSum->type_checked_load_vcalls(),
FSum->type_test_assume_const_vcalls(),
FSum->type_checked_load_const_vcalls()});
}
@ -231,6 +238,8 @@ template <> struct MappingTraits<ModuleSummaryIndex> {
static void mapping(IO &io, ModuleSummaryIndex& index) {
io.mapOptional("GlobalValueMap", index.GlobalValueMap);
io.mapOptional("TypeIdMap", index.TypeIdMap);
io.mapOptional("WithGlobalValueDeadStripping",
index.WithGlobalValueDeadStripping);
}
};

@ -228,24 +228,24 @@ public:
return cast<ConstantInt>(NumVMSArgs)->getZExtValue();
}
typename CallSiteTy::arg_iterator vm_state_begin() const {
typename CallSiteTy::arg_iterator deopt_begin() const {
auto I = gc_transition_args_end() + 1;
assert((getCallSite().arg_end() - I) >= 0);
return I;
}
typename CallSiteTy::arg_iterator vm_state_end() const {
auto I = vm_state_begin() + getNumTotalVMSArgs();
typename CallSiteTy::arg_iterator deopt_end() const {
auto I = deopt_begin() + getNumTotalVMSArgs();
assert((getCallSite().arg_end() - I) >= 0);
return I;
}
/// range adapter for vm state arguments
iterator_range<arg_iterator> vm_state_args() const {
return make_range(vm_state_begin(), vm_state_end());
iterator_range<arg_iterator> deopt_operands() const {
return make_range(deopt_begin(), deopt_end());
}
typename CallSiteTy::arg_iterator gc_args_begin() const {
return vm_state_end();
return deopt_end();
}
typename CallSiteTy::arg_iterator gc_args_end() const {
return getCallSite().arg_end();
@ -289,8 +289,8 @@ public:
(void)arg_end();
(void)gc_transition_args_begin();
(void)gc_transition_args_end();
(void)vm_state_begin();
(void)vm_state_end();
(void)deopt_begin();
(void)deopt_end();
(void)gc_args_begin();
(void)gc_args_end();
}

@ -86,7 +86,6 @@ void initializeCFGOnlyPrinterLegacyPassPass(PassRegistry&);
void initializeCFGOnlyViewerLegacyPassPass(PassRegistry&);
void initializeCFGPrinterLegacyPassPass(PassRegistry&);
void initializeCFGSimplifyPassPass(PassRegistry&);
void initializeLateCFGSimplifyPassPass(PassRegistry&);
void initializeCFGViewerLegacyPassPass(PassRegistry&);
void initializeCFLAndersAAWrapperPassPass(PassRegistry&);
void initializeCFLSteensAAWrapperPassPass(PassRegistry&);
@ -144,8 +143,8 @@ void initializeGCMachineCodeAnalysisPass(PassRegistry&);
void initializeGCModuleInfoPass(PassRegistry&);
void initializeGCOVProfilerLegacyPassPass(PassRegistry&);
void initializeGVNHoistLegacyPassPass(PassRegistry&);
void initializeGVNSinkLegacyPassPass(PassRegistry&);
void initializeGVNLegacyPassPass(PassRegistry&);
void initializeGVNSinkLegacyPassPass(PassRegistry&);
void initializeGlobalDCELegacyPassPass(PassRegistry&);
void initializeGlobalMergePass(PassRegistry&);
void initializeGlobalOptLegacyPassPass(PassRegistry&);
@ -175,13 +174,14 @@ void initializeIntervalPartitionPass(PassRegistry&);
void initializeJumpThreadingPass(PassRegistry&);
void initializeLCSSAVerificationPassPass(PassRegistry&);
void initializeLCSSAWrapperPassPass(PassRegistry&);
void initializeLateCFGSimplifyPassPass(PassRegistry&);
void initializeLazyBlockFrequencyInfoPassPass(PassRegistry&);
void initializeLazyBranchProbabilityInfoPassPass(PassRegistry&);
void initializeLazyMachineBlockFrequencyInfoPassPass(PassRegistry&);
void initializeLazyValueInfoPrinterPass(PassRegistry&);
void initializeLazyValueInfoWrapperPassPass(PassRegistry&);
void initializeLegacyLICMPassPass(PassRegistry&);
void initializeLegacyLoopSinkPassPass(PassRegistry&);
void initializeLazyValueInfoPrinterPass(PassRegistry&);
void initializeLegalizerPass(PassRegistry&);
void initializeLibCallsShrinkWrapLegacyPassPass(PassRegistry&);
void initializeLintPass(PassRegistry&);
@ -195,8 +195,8 @@ void initializeLiveVariablesPass(PassRegistry&);
void initializeLoadCombinePass(PassRegistry&);
void initializeLoadStoreVectorizerPass(PassRegistry&);
void initializeLoaderPassPass(PassRegistry&);
void initializeLocalizerPass(PassRegistry&);
void initializeLocalStackSlotPassPass(PassRegistry&);
void initializeLocalizerPass(PassRegistry&);
void initializeLoopAccessLegacyAnalysisPass(PassRegistry&);
void initializeLoopDataPrefetchLegacyPassPass(PassRegistry&);
void initializeLoopDeletionLegacyPassPass(PassRegistry&);
@ -304,6 +304,7 @@ void initializeProcessImplicitDefsPass(PassRegistry&);
void initializeProfileSummaryInfoWrapperPassPass(PassRegistry&);
void initializePromoteLegacyPassPass(PassRegistry&);
void initializePruneEHPass(PassRegistry&);
void initializeRABasicPass(PassRegistry&);
void initializeRAGreedyPass(PassRegistry&);
void initializeReassociateLegacyPassPass(PassRegistry&);
void initializeRegBankSelectPass(PassRegistry&);
@ -327,8 +328,9 @@ void initializeSafeStackLegacyPassPass(PassRegistry&);
void initializeSampleProfileLoaderLegacyPassPass(PassRegistry&);
void initializeSanitizerCoverageModulePass(PassRegistry&);
void initializeScalarEvolutionWrapperPassPass(PassRegistry&);
void initializeScalarizerPass(PassRegistry&);
void initializeScalarizeMaskedMemIntrinPass(PassRegistry&);
void initializeScalarizerPass(PassRegistry&);
void initializeScavengerTestPass(PassRegistry&);
void initializeScopedNoAliasAAWrapperPassPass(PassRegistry&);
void initializeSeparateConstOffsetFromGEPPass(PassRegistry&);
void initializeShadowStackGCLoweringPass(PassRegistry&);

@ -46,6 +46,9 @@ struct Config {
unsigned OptLevel = 2;
bool DisableVerify = false;
/// Use the new pass manager
bool UseNewPM = false;
/// Disable entirely the optimizer, including importing for ThinLTO
bool CodeGenOnly = false;

@ -17,12 +17,20 @@
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
#include "llvm/ObjectYAML/YAML.h"
namespace llvm {
namespace codeview {
class DebugStringTableSubsection;
class DebugStringTableSubsectionRef;
class DebugChecksumsSubsectionRef;
}
namespace CodeViewYAML {
namespace detail {
struct C13FragmentBase;
struct YAMLSubsectionBase;
}
struct SourceLineEntry {
@ -74,18 +82,24 @@ struct InlineeInfo {
std::vector<InlineeSite> Sites;
};
struct SourceFileInfo {
std::vector<SourceFileChecksumEntry> FileChecksums;
std::vector<SourceLineInfo> LineFragments;
std::vector<InlineeInfo> Inlinees;
struct YAMLDebugSubsection {
static Expected<YAMLDebugSubsection>
fromCodeViewSubection(const codeview::DebugStringTableSubsectionRef &Strings,
const codeview::DebugChecksumsSubsectionRef &Checksums,
const codeview::DebugSubsectionRecord &SS);
std::shared_ptr<detail::YAMLSubsectionBase> Subsection;
};
struct C13DebugSection {
std::vector<detail::C13FragmentBase> Fragments;
};
Expected<std::vector<std::unique_ptr<codeview::DebugSubsection>>>
convertSubsectionList(ArrayRef<YAMLDebugSubsection> Subsections,
codeview::DebugStringTableSubsection &Strings);
} // namespace CodeViewYAML
} // namespace llvm
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::SourceFileInfo)
LLVM_YAML_DECLARE_MAPPING_TRAITS(CodeViewYAML::YAMLDebugSubsection)
LLVM_YAML_IS_SEQUENCE_VECTOR(CodeViewYAML::YAMLDebugSubsection)
#endif

@ -28,7 +28,9 @@ struct SymbolRecordBase;
struct SymbolRecord {
std::shared_ptr<detail::SymbolRecordBase> Symbol;
codeview::CVSymbol toCodeViewSymbol(BumpPtrAllocator &Allocator) const;
codeview::CVSymbol
toCodeViewSymbol(BumpPtrAllocator &Allocator,
codeview::CodeViewContainer Container) const;
static Expected<SymbolRecord> fromCodeViewSymbol(codeview::CVSymbol Symbol);
};

@ -1361,10 +1361,6 @@ public:
return false;
}
bool isTemplateArg(StringRef Name) const {
return isTemplateArg(StringInit::get(Name));
}
const RecordVal *getValue(const Init *Name) const {
for (const RecordVal &Val : Values)
if (Val.Name == Name) return &Val;
@ -1388,10 +1384,6 @@ public:
TemplateArgs.push_back(Name);
}
void addTemplateArg(StringRef Name) {
addTemplateArg(StringInit::get(Name));
}
void addValue(const RecordVal &RV) {
assert(getValue(RV.getNameInit()) == nullptr && "Value already added!");
Values.push_back(RV);

@ -81,15 +81,11 @@ public:
/// \p ExportLists contains for each Module the set of globals (GUID) that will
/// be imported by another module, or referenced by such a function. I.e. this
/// is the set of globals that need to be promoted/renamed appropriately.
///
/// \p DeadSymbols (optional) contains a list of GUID that are deemed "dead" and
/// will be ignored for the purpose of importing.
void ComputeCrossModuleImport(
const ModuleSummaryIndex &Index,
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
StringMap<FunctionImporter::ImportMapTy> &ImportLists,
StringMap<FunctionImporter::ExportSetTy> &ExportLists,
const DenseSet<GlobalValue::GUID> *DeadSymbols = nullptr);
StringMap<FunctionImporter::ExportSetTy> &ExportLists);
/// Compute all the imports for the given module using the Index.
///
@ -102,9 +98,9 @@ void ComputeCrossModuleImportForModule(
/// Compute all the symbols that are "dead": i.e these that can't be reached
/// in the graph from any of the given symbols listed in
/// \p GUIDPreservedSymbols.
DenseSet<GlobalValue::GUID>
computeDeadSymbols(const ModuleSummaryIndex &Index,
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols);
void computeDeadSymbols(
ModuleSummaryIndex &Index,
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols);
/// Compute the set of summaries needed for a ThinLTO backend compilation of
/// \p ModulePath.

@ -177,6 +177,7 @@ struct SanitizerCoverageOptions {
bool Use8bitCounters = false;
bool TracePC = false;
bool TracePCGuard = false;
bool Inline8bitCounters = false;
bool NoPrune = false;
SanitizerCoverageOptions() = default;

@ -36,6 +36,7 @@ class BasicBlock;
class BlockFrequencyInfo;
class CallInst;
class CallGraph;
class DebugInfoFinder;
class DominatorTree;
class Function;
class Instruction;
@ -110,7 +111,8 @@ struct ClonedCodeInfo {
///
BasicBlock *CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap,
const Twine &NameSuffix = "", Function *F = nullptr,
ClonedCodeInfo *CodeInfo = nullptr);
ClonedCodeInfo *CodeInfo = nullptr,
DebugInfoFinder *DIFinder = nullptr);
/// CloneFunction - Return a copy of the specified function and add it to that
/// function's module. Also, any references specified in the VMap are changed

@ -1170,7 +1170,9 @@ Constant *llvm::ConstantFoldCompareInstOperands(unsigned Predicate,
const DataLayout &DL,
const TargetLibraryInfo *TLI) {
// fold: icmp (inttoptr x), null -> icmp x, 0
// fold: icmp null, (inttoptr x) -> icmp 0, x
// fold: icmp (ptrtoint x), 0 -> icmp x, null
// fold: icmp 0, (ptrtoint x) -> icmp null, x
// fold: icmp (inttoptr x), (inttoptr y) -> icmp trunc/zext x, trunc/zext y
// fold: icmp (ptrtoint x), (ptrtoint y) -> icmp x, y
//
@ -1240,6 +1242,11 @@ Constant *llvm::ConstantFoldCompareInstOperands(unsigned Predicate,
Predicate == ICmpInst::ICMP_EQ ? Instruction::And : Instruction::Or;
return ConstantFoldBinaryOpOperands(OpC, LHS, RHS, DL);
}
} else if (isa<ConstantExpr>(Ops1)) {
// If RHS is a constant expression, but the left side isn't, swap the
// operands and try again.
Predicate = ICmpInst::getSwappedPredicate((ICmpInst::Predicate)Predicate);
return ConstantFoldCompareInstOperands(Predicate, Ops1, Ops0, DL, TLI);
}
return ConstantExpr::getCompare(Predicate, Ops0, Ops1);

@ -43,7 +43,7 @@ static cl::opt<unsigned>
// The percent threshold for the direct-call target (this call site vs the
// total call count) for it to be considered as the promotion target.
static cl::opt<unsigned>
ICPPercentThreshold("icp-percent-threshold", cl::init(33), cl::Hidden,
ICPPercentThreshold("icp-percent-threshold", cl::init(30), cl::Hidden,
cl::ZeroOrMore,
cl::desc("The percentage threshold for the promotion"));

@ -54,11 +54,6 @@ static cl::opt<int>
cl::init(45),
cl::desc("Threshold for inlining cold callsites"));
static cl::opt<bool>
EnableGenericSwitchCost("inline-generic-switch-cost", cl::Hidden,
cl::init(false),
cl::desc("Enable generic switch cost model"));
// We introduce this threshold to help performance of instrumentation based
// PGO before we actually hook up inliner with analysis passes such as BPI and
// BFI.
@ -1015,83 +1010,68 @@ bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) {
if (isa<ConstantInt>(V))
return true;
if (EnableGenericSwitchCost) {
// Assume the most general case where the swith is lowered into
// either a jump table, bit test, or a balanced binary tree consisting of
// case clusters without merging adjacent clusters with the same
// destination. We do not consider the switches that are lowered with a mix
// of jump table/bit test/binary search tree. The cost of the switch is
// proportional to the size of the tree or the size of jump table range.
// 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,
(int64_t)SI.getNumCases() * InlineConstants::InstrCost + Cost);
if (CostLowerBound > Threshold) {
Cost = CostLowerBound;
return false;
}
unsigned JumpTableSize = 0;
unsigned NumCaseCluster =
TTI.getEstimatedNumberOfCaseClusters(SI, JumpTableSize);
// If suitable for a jump table, consider the cost for the table size and
// branch to destination.
if (JumpTableSize) {
int64_t JTCost = (int64_t)JumpTableSize * InlineConstants::InstrCost +
4 * InlineConstants::InstrCost;
Cost = std::min((int64_t)INT_MAX, JTCost + Cost);
return false;
}
// Considering forming a binary search, we should find the number of nodes
// which is same as the number of comparisons when lowered. For a given
// number of clusters, n, we can define a recursive function, f(n), to find
// the number of nodes in the tree. The recursion is :
// f(n) = 1 + f(n/2) + f (n - n/2), when n > 3,
// and f(n) = n, when n <= 3.
// This will lead a binary tree where the leaf should be either f(2) or f(3)
// when n > 3. So, the number of comparisons from leaves should be n, while
// the number of non-leaf should be :
// 2^(log2(n) - 1) - 1
// = 2^log2(n) * 2^-1 - 1
// = n / 2 - 1.
// Considering comparisons from leaf and non-leaf nodes, we can estimate the
// number of comparisons in a simple closed form :
// n + n / 2 - 1 = n * 3 / 2 - 1
if (NumCaseCluster <= 3) {
// Suppose a comparison includes one compare and one conditional branch.
Cost += NumCaseCluster * 2 * InlineConstants::InstrCost;
return false;
}
int64_t ExpectedNumberOfCompare = 3 * (uint64_t)NumCaseCluster / 2 - 1;
uint64_t SwitchCost =
ExpectedNumberOfCompare * 2 * InlineConstants::InstrCost;
Cost = std::min((uint64_t)INT_MAX, SwitchCost + Cost);
return false;
}
// Use a simple switch cost model where we accumulate a cost proportional to
// the number of distinct successor blocks. This fan-out in the CFG cannot
// be represented for free even if we can represent the core switch as a
// jumptable that takes a single instruction.
///
// Assume the most general case where the swith is lowered into
// either a jump table, bit test, or a balanced binary tree consisting of
// case clusters without merging adjacent clusters with the same
// destination. We do not consider the switches that are lowered with a mix
// of jump table/bit test/binary search tree. The cost of the switch is
// proportional to the size of the tree or the size of jump table range.
//
// NB: We convert large switches which are just used to initialize large phi
// nodes to lookup tables instead in simplify-cfg, so this shouldn't prevent
// inlining those. It will prevent inlining in cases where the optimization
// does not (yet) fire.
SmallPtrSet<BasicBlock *, 8> SuccessorBlocks;
SuccessorBlocks.insert(SI.getDefaultDest());
for (auto Case : SI.cases())
SuccessorBlocks.insert(Case.getCaseSuccessor());
// Add cost corresponding to the number of distinct destinations. The first
// we model as free because of fallthrough.
Cost += (SuccessorBlocks.size() - 1) * InlineConstants::InstrCost;
// 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,
(int64_t)SI.getNumCases() * InlineConstants::InstrCost + Cost);
if (CostLowerBound > Threshold) {
Cost = CostLowerBound;
return false;
}
unsigned JumpTableSize = 0;
unsigned NumCaseCluster =
TTI.getEstimatedNumberOfCaseClusters(SI, JumpTableSize);
// If suitable for a jump table, consider the cost for the table size and
// branch to destination.
if (JumpTableSize) {
int64_t JTCost = (int64_t)JumpTableSize * InlineConstants::InstrCost +
4 * InlineConstants::InstrCost;
Cost = std::min((int64_t)INT_MAX, JTCost + Cost);
return false;
}
// Considering forming a binary search, we should find the number of nodes
// which is same as the number of comparisons when lowered. For a given
// number of clusters, n, we can define a recursive function, f(n), to find
// the number of nodes in the tree. The recursion is :
// f(n) = 1 + f(n/2) + f (n - n/2), when n > 3,
// and f(n) = n, when n <= 3.
// This will lead a binary tree where the leaf should be either f(2) or f(3)
// when n > 3. So, the number of comparisons from leaves should be n, while
// the number of non-leaf should be :
// 2^(log2(n) - 1) - 1
// = 2^log2(n) * 2^-1 - 1
// = n / 2 - 1.
// Considering comparisons from leaf and non-leaf nodes, we can estimate the
// number of comparisons in a simple closed form :
// n + n / 2 - 1 = n * 3 / 2 - 1
if (NumCaseCluster <= 3) {
// Suppose a comparison includes one compare and one conditional branch.
Cost += NumCaseCluster * 2 * InlineConstants::InstrCost;
return false;
}
int64_t ExpectedNumberOfCompare = 3 * (uint64_t)NumCaseCluster / 2 - 1;
uint64_t SwitchCost =
ExpectedNumberOfCompare * 2 * InlineConstants::InstrCost;
Cost = std::min((uint64_t)INT_MAX, SwitchCost + Cost);
return false;
}

@ -662,13 +662,13 @@ namespace {
bool solveBlockValuePHINode(LVILatticeVal &BBLV, PHINode *PN, BasicBlock *BB);
bool solveBlockValueSelect(LVILatticeVal &BBLV, SelectInst *S,
BasicBlock *BB);
bool solveBlockValueBinaryOp(LVILatticeVal &BBLV, Instruction *BBI,
bool solveBlockValueBinaryOp(LVILatticeVal &BBLV, BinaryOperator *BBI,
BasicBlock *BB);
bool solveBlockValueCast(LVILatticeVal &BBLV, Instruction *BBI,
bool solveBlockValueCast(LVILatticeVal &BBLV, CastInst *CI,
BasicBlock *BB);
void intersectAssumeOrGuardBlockValueConstantRange(Value *Val,
LVILatticeVal &BBLV,
Instruction *BBI);
Instruction *BBI);
void solve();
@ -849,12 +849,12 @@ bool LazyValueInfoImpl::solveBlockValueImpl(LVILatticeVal &Res,
return true;
}
if (BBI->getType()->isIntegerTy()) {
if (isa<CastInst>(BBI))
return solveBlockValueCast(Res, BBI, BB);
if (auto *CI = dyn_cast<CastInst>(BBI))
return solveBlockValueCast(Res, CI, BB);
BinaryOperator *BO = dyn_cast<BinaryOperator>(BBI);
if (BO && isa<ConstantInt>(BO->getOperand(1)))
return solveBlockValueBinaryOp(Res, BBI, BB);
return solveBlockValueBinaryOp(Res, BO, BB);
}
DEBUG(dbgs() << " compute BB '" << BB->getName()
@ -1168,9 +1168,9 @@ bool LazyValueInfoImpl::solveBlockValueSelect(LVILatticeVal &BBLV,
}
bool LazyValueInfoImpl::solveBlockValueCast(LVILatticeVal &BBLV,
Instruction *BBI,
BasicBlock *BB) {
if (!BBI->getOperand(0)->getType()->isSized()) {
CastInst *CI,
BasicBlock *BB) {
if (!CI->getOperand(0)->getType()->isSized()) {
// Without knowing how wide the input is, we can't analyze it in any useful
// way.
BBLV = LVILatticeVal::getOverdefined();
@ -1180,7 +1180,7 @@ bool LazyValueInfoImpl::solveBlockValueCast(LVILatticeVal &BBLV,
// Filter out casts we don't know how to reason about before attempting to
// recurse on our operand. This can cut a long search short if we know we're
// not going to be able to get any useful information anways.
switch (BBI->getOpcode()) {
switch (CI->getOpcode()) {
case Instruction::Trunc:
case Instruction::SExt:
case Instruction::ZExt:
@ -1197,44 +1197,43 @@ bool LazyValueInfoImpl::solveBlockValueCast(LVILatticeVal &BBLV,
// Figure out the range of the LHS. If that fails, we still apply the
// transfer rule on the full set since we may be able to locally infer
// interesting facts.
if (!hasBlockValue(BBI->getOperand(0), BB))
if (pushBlockValue(std::make_pair(BB, BBI->getOperand(0))))
if (!hasBlockValue(CI->getOperand(0), BB))
if (pushBlockValue(std::make_pair(BB, CI->getOperand(0))))
// More work to do before applying this transfer rule.
return false;
const unsigned OperandBitWidth =
DL.getTypeSizeInBits(BBI->getOperand(0)->getType());
DL.getTypeSizeInBits(CI->getOperand(0)->getType());
ConstantRange LHSRange = ConstantRange(OperandBitWidth);
if (hasBlockValue(BBI->getOperand(0), BB)) {
LVILatticeVal LHSVal = getBlockValue(BBI->getOperand(0), BB);
intersectAssumeOrGuardBlockValueConstantRange(BBI->getOperand(0), LHSVal,
BBI);
if (hasBlockValue(CI->getOperand(0), BB)) {
LVILatticeVal LHSVal = getBlockValue(CI->getOperand(0), BB);
intersectAssumeOrGuardBlockValueConstantRange(CI->getOperand(0), LHSVal,
CI);
if (LHSVal.isConstantRange())
LHSRange = LHSVal.getConstantRange();
}
const unsigned ResultBitWidth =
cast<IntegerType>(BBI->getType())->getBitWidth();
const unsigned ResultBitWidth = CI->getType()->getIntegerBitWidth();
// NOTE: We're currently limited by the set of operations that ConstantRange
// can evaluate symbolically. Enhancing that set will allows us to analyze
// more definitions.
auto CastOp = (Instruction::CastOps) BBI->getOpcode();
BBLV = LVILatticeVal::getRange(LHSRange.castOp(CastOp, ResultBitWidth));
BBLV = LVILatticeVal::getRange(LHSRange.castOp(CI->getOpcode(),
ResultBitWidth));
return true;
}
bool LazyValueInfoImpl::solveBlockValueBinaryOp(LVILatticeVal &BBLV,
Instruction *BBI,
BinaryOperator *BO,
BasicBlock *BB) {
assert(BBI->getOperand(0)->getType()->isSized() &&
assert(BO->getOperand(0)->getType()->isSized() &&
"all operands to binary operators are sized");
// Filter out operators we don't know how to reason about before attempting to
// recurse on our operand(s). This can cut a long search short if we know
// we're not going to be able to get any useful information anways.
switch (BBI->getOpcode()) {
// we're not going to be able to get any useful information anyways.
switch (BO->getOpcode()) {
case Instruction::Add:
case Instruction::Sub:
case Instruction::Mul:
@ -1256,29 +1255,29 @@ bool LazyValueInfoImpl::solveBlockValueBinaryOp(LVILatticeVal &BBLV,
// Figure out the range of the LHS. If that fails, use a conservative range,
// but apply the transfer rule anyways. This lets us pick up facts from
// expressions like "and i32 (call i32 @foo()), 32"
if (!hasBlockValue(BBI->getOperand(0), BB))
if (pushBlockValue(std::make_pair(BB, BBI->getOperand(0))))
if (!hasBlockValue(BO->getOperand(0), BB))
if (pushBlockValue(std::make_pair(BB, BO->getOperand(0))))
// More work to do before applying this transfer rule.
return false;
const unsigned OperandBitWidth =
DL.getTypeSizeInBits(BBI->getOperand(0)->getType());
DL.getTypeSizeInBits(BO->getOperand(0)->getType());
ConstantRange LHSRange = ConstantRange(OperandBitWidth);
if (hasBlockValue(BBI->getOperand(0), BB)) {
LVILatticeVal LHSVal = getBlockValue(BBI->getOperand(0), BB);
intersectAssumeOrGuardBlockValueConstantRange(BBI->getOperand(0), LHSVal,
BBI);
if (hasBlockValue(BO->getOperand(0), BB)) {
LVILatticeVal LHSVal = getBlockValue(BO->getOperand(0), BB);
intersectAssumeOrGuardBlockValueConstantRange(BO->getOperand(0), LHSVal,
BO);
if (LHSVal.isConstantRange())
LHSRange = LHSVal.getConstantRange();
}
ConstantInt *RHS = cast<ConstantInt>(BBI->getOperand(1));
ConstantInt *RHS = cast<ConstantInt>(BO->getOperand(1));
ConstantRange RHSRange = ConstantRange(RHS->getValue());
// NOTE: We're currently limited by the set of operations that ConstantRange
// can evaluate symbolically. Enhancing that set will allows us to analyze
// more definitions.
auto BinOp = (Instruction::BinaryOps) BBI->getOpcode();
Instruction::BinaryOps BinOp = BO->getOpcode();
BBLV = LVILatticeVal::getRange(LHSRange.binaryOp(BinOp, RHSRange));
return true;
}

@ -275,7 +275,7 @@ computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
// FIXME: refactor this to use the same code that inliner is using.
F.isVarArg();
GlobalValueSummary::GVFlags Flags(F.getLinkage(), NotEligibleForImport,
/* LiveRoot = */ false);
/* Live = */ false);
auto FuncSummary = llvm::make_unique<FunctionSummary>(
Flags, NumInsts, RefEdges.takeVector(), CallGraphEdges.takeVector(),
TypeTests.takeVector(), TypeTestAssumeVCalls.takeVector(),
@ -295,7 +295,7 @@ computeVariableSummary(ModuleSummaryIndex &Index, const GlobalVariable &V,
findRefEdges(Index, &V, RefEdges, Visited);
bool NonRenamableLocal = isNonRenamableLocal(V);
GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
/* LiveRoot = */ false);
/* Live = */ false);
auto GVarSummary =
llvm::make_unique<GlobalVarSummary>(Flags, RefEdges.takeVector());
if (NonRenamableLocal)
@ -308,7 +308,7 @@ computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
DenseSet<GlobalValue::GUID> &CantBePromoted) {
bool NonRenamableLocal = isNonRenamableLocal(A);
GlobalValueSummary::GVFlags Flags(A.getLinkage(), NonRenamableLocal,
/* LiveRoot = */ false);
/* Live = */ false);
auto AS = llvm::make_unique<AliasSummary>(Flags, ArrayRef<ValueInfo>{});
auto *Aliasee = A.getBaseObject();
auto *AliaseeSummary = Index.getGlobalValueSummary(*Aliasee);
@ -323,7 +323,7 @@ computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A,
static void setLiveRoot(ModuleSummaryIndex &Index, StringRef Name) {
if (ValueInfo VI = Index.getValueInfo(GlobalValue::getGUID(Name)))
for (auto &Summary : VI.getSummaryList())
Summary->setLiveRoot();
Summary->setLive(true);
}
ModuleSummaryIndex llvm::buildModuleSummaryIndex(
@ -423,8 +423,8 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
return;
assert(GV->isDeclaration() && "Def in module asm already has definition");
GlobalValueSummary::GVFlags GVFlags(GlobalValue::InternalLinkage,
/* NotEligibleToImport */ true,
/* LiveRoot */ true);
/* NotEligibleToImport = */ true,
/* Live = */ true);
CantBePromoted.insert(GlobalValue::getGUID(Name));
// Create the appropriate summary type.
if (isa<Function>(GV)) {

@ -55,7 +55,7 @@ bool OrderedBasicBlock::comesBefore(const Instruction *A,
assert(II != IE && "Instruction not found?");
assert((Inst == A || Inst == B) && "Should find A or B");
LastInstFound = II;
return Inst == A;
return Inst != B;
}
/// \brief Find out whether \p A dominates \p B, meaning whether \p A

@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/RegionPass.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/IR/OptBisect.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
@ -280,3 +281,18 @@ Pass *RegionPass::createPrinterPass(raw_ostream &O,
const std::string &Banner) const {
return new PrintRegionPass(Banner, O);
}
bool RegionPass::skipRegion(Region &R) const {
Function &F = *R.getEntry()->getParent();
if (!F.getContext().getOptBisect().shouldRunPass(this, R))
return true;
if (F.hasFnAttribute(Attribute::OptimizeNone)) {
// Report this only once per function.
if (R.getEntry() == &F.getEntryBlock())
DEBUG(dbgs() << "Skipping pass '" << getPassName()
<< "' on function " << F.getName() << "\n");
return true;
}
return false;
}

@ -865,11 +865,11 @@ static GlobalValueSummary::GVFlags getDecodedGVSummaryFlags(uint64_t RawFlags,
auto Linkage = GlobalValue::LinkageTypes(RawFlags & 0xF); // 4 bits
RawFlags = RawFlags >> 4;
bool NotEligibleToImport = (RawFlags & 0x1) || Version < 3;
// The LiveRoot flag wasn't introduced until version 3. For dead stripping
// The Live flag wasn't introduced until version 3. For dead stripping
// to work correctly on earlier versions, we must conservatively treat all
// values as live.
bool LiveRoot = (RawFlags & 0x2) || Version < 3;
return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, LiveRoot);
bool Live = (RawFlags & 0x2) || Version < 3;
return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live);
}
static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) {

@ -351,7 +351,8 @@ public:
/// Calls the callback for each value GUID and summary to be written to
/// bitcode. This hides the details of whether they are being pulled from the
/// entire index or just those in a provided ModuleToSummariesForIndex map.
void forEachSummary(std::function<void(GVInfo)> Callback) {
template<typename Functor>
void forEachSummary(Functor Callback) {
if (ModuleToSummariesForIndex) {
for (auto &M : *ModuleToSummariesForIndex)
for (auto &Summary : M.second)
@ -363,6 +364,29 @@ public:
}
}
/// Calls the callback for each entry in the modulePaths StringMap that
/// should be written to the module path string table. This hides the details
/// of whether they are being pulled from the entire index or just those in a
/// provided ModuleToSummariesForIndex map.
template <typename Functor> void forEachModule(Functor Callback) {
if (ModuleToSummariesForIndex) {
for (const auto &M : *ModuleToSummariesForIndex) {
const auto &MPI = Index.modulePaths().find(M.first);
if (MPI == Index.modulePaths().end()) {
// This should only happen if the bitcode file was empty, in which
// case we shouldn't be importing (the ModuleToSummariesForIndex
// would only include the module we are writing and index for).
assert(ModuleToSummariesForIndex->size() == 1);
continue;
}
Callback(*MPI);
}
} else {
for (const auto &MPSE : Index.modulePaths())
Callback(MPSE);
}
}
/// Main entry point for writing a combined index to bitcode.
void write();
@ -370,14 +394,6 @@ private:
void writeModStrings();
void writeCombinedGlobalValueSummary();
/// Indicates whether the provided \p ModulePath should be written into
/// the module string table, e.g. if full index written or if it is in
/// the provided subset.
bool doIncludeModule(StringRef ModulePath) {
return !ModuleToSummariesForIndex ||
ModuleToSummariesForIndex->count(ModulePath);
}
Optional<unsigned> getValueId(GlobalValue::GUID ValGUID) {
auto VMI = GUIDToValueIdMap.find(ValGUID);
if (VMI == GUIDToValueIdMap.end())
@ -864,7 +880,7 @@ static uint64_t getEncodedGVSummaryFlags(GlobalValueSummary::GVFlags Flags) {
uint64_t RawFlags = 0;
RawFlags |= Flags.NotEligibleToImport; // bool
RawFlags |= (Flags.LiveRoot << 1);
RawFlags |= (Flags.Live << 1);
// Linkage don't need to be remapped at that time for the summary. Any future
// change to the getEncodedLinkage() function will need to be taken into
// account here as well.
@ -968,19 +984,18 @@ void ModuleBitcodeWriter::writeValueSymbolTableForwardDecl() {
enum StringEncoding { SE_Char6, SE_Fixed7, SE_Fixed8 };
/// Determine the encoding to use for the given string name and length.
static StringEncoding getStringEncoding(const char *Str, unsigned StrLen) {
static StringEncoding getStringEncoding(StringRef Str) {
bool isChar6 = true;
for (const char *C = Str, *E = C + StrLen; C != E; ++C) {
for (char C : Str) {
if (isChar6)
isChar6 = BitCodeAbbrevOp::isChar6(*C);
if ((unsigned char)*C & 128)
isChar6 = BitCodeAbbrevOp::isChar6(C);
if ((unsigned char)C & 128)
// don't bother scanning the rest.
return SE_Fixed8;
}
if (isChar6)
return SE_Char6;
else
return SE_Fixed7;
return SE_Fixed7;
}
/// Emit top-level description of module, including target triple, inline asm,
@ -1073,8 +1088,7 @@ void ModuleBitcodeWriter::writeModuleInfo() {
SmallVector<unsigned, 64> Vals;
// Emit the module's source file name.
{
StringEncoding Bits = getStringEncoding(M.getSourceFileName().data(),
M.getSourceFileName().size());
StringEncoding Bits = getStringEncoding(M.getSourceFileName());
BitCodeAbbrevOp AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 8);
if (Bits == SE_Char6)
AbbrevOpToUse = BitCodeAbbrevOp(BitCodeAbbrevOp::Char6);
@ -2790,8 +2804,7 @@ void ModuleBitcodeWriter::writeFunctionLevelValueSymbolTable(
for (const ValueName &Name : VST) {
// Figure out the encoding to use for the name.
StringEncoding Bits =
getStringEncoding(Name.getKeyData(), Name.getKeyLength());
StringEncoding Bits = getStringEncoding(Name.getKey());
unsigned AbbrevToUse = VST_ENTRY_8_ABBREV;
NameVals.push_back(VE.getValueID(Name.getValue()));
@ -3149,41 +3162,33 @@ void IndexBitcodeWriter::writeModStrings() {
unsigned AbbrevHash = Stream.EmitAbbrev(std::move(Abbv));
SmallVector<unsigned, 64> Vals;
for (const auto &MPSE : Index.modulePaths()) {
if (!doIncludeModule(MPSE.getKey()))
continue;
StringEncoding Bits =
getStringEncoding(MPSE.getKey().data(), MPSE.getKey().size());
unsigned AbbrevToUse = Abbrev8Bit;
if (Bits == SE_Char6)
AbbrevToUse = Abbrev6Bit;
else if (Bits == SE_Fixed7)
AbbrevToUse = Abbrev7Bit;
forEachModule(
[&](const StringMapEntry<std::pair<uint64_t, ModuleHash>> &MPSE) {
StringRef Key = MPSE.getKey();
const auto &Value = MPSE.getValue();
StringEncoding Bits = getStringEncoding(Key);
unsigned AbbrevToUse = Abbrev8Bit;
if (Bits == SE_Char6)
AbbrevToUse = Abbrev6Bit;
else if (Bits == SE_Fixed7)
AbbrevToUse = Abbrev7Bit;
Vals.push_back(MPSE.getValue().first);
Vals.push_back(Value.first);
Vals.append(Key.begin(), Key.end());
for (const auto P : MPSE.getKey())
Vals.push_back((unsigned char)P);
// Emit the finished record.
Stream.EmitRecord(bitc::MST_CODE_ENTRY, Vals, AbbrevToUse);
// Emit the finished record.
Stream.EmitRecord(bitc::MST_CODE_ENTRY, Vals, AbbrevToUse);
// Emit an optional hash for the module now
const auto &Hash = Value.second;
if (llvm::any_of(Hash, [](uint32_t H) { return H; })) {
Vals.assign(Hash.begin(), Hash.end());
// Emit the hash record.
Stream.EmitRecord(bitc::MST_CODE_HASH, Vals, AbbrevHash);
}
Vals.clear();
// Emit an optional hash for the module now
auto &Hash = MPSE.getValue().second;
bool AllZero = true; // Detect if the hash is empty, and do not generate it
for (auto Val : Hash) {
if (Val)
AllZero = false;
Vals.push_back(Val);
}
if (!AllZero) {
// Emit the hash record.
Stream.EmitRecord(bitc::MST_CODE_HASH, Vals, AbbrevHash);
}
Vals.clear();
}
Vals.clear();
});
Stream.ExitBlock();
}

@ -194,6 +194,10 @@ void llvm::calculateDbgValueHistory(const MachineFunction *MF,
// some variables.
for (const MachineOperand &MO : MI.operands()) {
if (MO.isReg() && MO.isDef() && MO.getReg()) {
// Ignore call instructions that claim to clobber SP. The AArch64
// backend does this for aggregate function arguments.
if (MI.isCall() && MO.getReg() == SP)
continue;
// If this is a virtual register, only clobber it since it doesn't
// have aliases.
if (TRI->isVirtualRegister(MO.getReg()))

@ -77,6 +77,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
initializePostRASchedulerPass(Registry);
initializePreISelIntrinsicLoweringLegacyPassPass(Registry);
initializeProcessImplicitDefsPass(Registry);
initializeRABasicPass(Registry);
initializeRAGreedyPass(Registry);
initializeRegisterCoalescerPass(Registry);
initializeRenameIndependentSubregsPass(Registry);

@ -556,6 +556,10 @@ bool GlobalMerge::doInitialization(Module &M) {
if (GV.isDeclaration() || GV.isThreadLocal() || GV.hasSection())
continue;
// It's not safe to merge globals that may be preempted
if (TM && !TM->shouldAssumeDSOLocal(M, &GV))
continue;
if (!(MergeExternalGlobals && GV.hasExternalLinkage()) &&
!GV.hasInternalLinkage())
continue;

@ -198,13 +198,12 @@ void LivePhysRegs::addLiveOutsNoPristines(const MachineBasicBlock &MBB) {
}
void LivePhysRegs::addLiveOuts(const MachineBasicBlock &MBB) {
const MachineFunction &MF = *MBB.getParent();
if (!MBB.succ_empty()) {
const MachineFunction &MF = *MBB.getParent();
addPristines(*this, MF);
addLiveOutsNoPristines(MBB);
} else if (MBB.isReturnBlock()) {
// For the return block: Add all callee saved registers.
const MachineFunction &MF = *MBB.getParent();
const MachineFrameInfo &MFI = MF.getFrameInfo();
if (MFI.isCalleeSavedInfoValid())
addCalleeSavedRegs(*this, MF);

@ -12,11 +12,13 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/LiveRegUnits.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBundle.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
@ -81,46 +83,50 @@ void LiveRegUnits::accumulateBackward(const MachineInstr &MI) {
}
/// Add live-in registers of basic block \p MBB to \p LiveUnits.
static void addLiveIns(LiveRegUnits &LiveUnits, const MachineBasicBlock &MBB) {
static void addBlockLiveIns(LiveRegUnits &LiveUnits,
const MachineBasicBlock &MBB) {
for (const auto &LI : MBB.liveins())
LiveUnits.addRegMasked(LI.PhysReg, LI.LaneMask);
}
static void addLiveOuts(LiveRegUnits &LiveUnits, const MachineBasicBlock &MBB) {
// To get the live-outs we simply merge the live-ins of all successors.
for (const MachineBasicBlock *Succ : MBB.successors())
addLiveIns(LiveUnits, *Succ);
/// Adds all callee saved registers to \p LiveUnits.
static void addCalleeSavedRegs(LiveRegUnits &LiveUnits,
const MachineFunction &MF) {
const MachineRegisterInfo &MRI = MF.getRegInfo();
for (const MCPhysReg *CSR = MRI.getCalleeSavedRegs(); CSR && *CSR; ++CSR)
LiveUnits.addReg(*CSR);
}
/// Add pristine registers to the given \p LiveUnits. This function removes
/// actually saved callee save registers when \p InPrologueEpilogue is false.
static void removeSavedRegs(LiveRegUnits &LiveUnits, const MachineFunction &MF,
const MachineFrameInfo &MFI,
const TargetRegisterInfo &TRI) {
/// Adds pristine registers to the given \p LiveUnits. Pristine registers are
/// callee saved registers that are unused in the function.
static void addPristines(LiveRegUnits &LiveUnits, const MachineFunction &MF) {
const MachineFrameInfo &MFI = MF.getFrameInfo();
if (!MFI.isCalleeSavedInfoValid())
return;
/// Add all callee saved regs, then remove the ones that are saved+restored.
addCalleeSavedRegs(LiveUnits, MF);
/// Remove the ones that are not saved/restored; they are pristine.
for (const CalleeSavedInfo &Info : MFI.getCalleeSavedInfo())
LiveUnits.removeReg(Info.getReg());
}
void LiveRegUnits::addLiveOuts(const MachineBasicBlock &MBB) {
const MachineFunction &MF = *MBB.getParent();
const MachineFrameInfo &MFI = MF.getFrameInfo();
if (MFI.isCalleeSavedInfoValid()) {
for (const MCPhysReg *I = TRI->getCalleeSavedRegs(&MF); *I; ++I)
addReg(*I);
if (!MBB.isReturnBlock())
removeSavedRegs(*this, MF, MFI, *TRI);
if (!MBB.succ_empty()) {
addPristines(*this, MF);
// To get the live-outs we simply merge the live-ins of all successors.
for (const MachineBasicBlock *Succ : MBB.successors())
addBlockLiveIns(*this, *Succ);
} else if (MBB.isReturnBlock()) {
// For the return block: Add all callee saved registers.
const MachineFrameInfo &MFI = MF.getFrameInfo();
if (MFI.isCalleeSavedInfoValid())
addCalleeSavedRegs(*this, MF);
}
::addLiveOuts(*this, MBB);
}
void LiveRegUnits::addLiveIns(const MachineBasicBlock &MBB) {
const MachineFunction &MF = *MBB.getParent();
const MachineFrameInfo &MFI = MF.getFrameInfo();
if (MFI.isCalleeSavedInfoValid()) {
for (const MCPhysReg *I = TRI->getCalleeSavedRegs(&MF); *I; ++I)
addReg(*I);
if (&MBB != &MF.front())
removeSavedRegs(*this, MF, MFI, *TRI);
}
::addLiveIns(*this, MBB);
addPristines(*this, MF);
addBlockLiveIns(*this, MBB);
}

@ -1,7 +1,19 @@
#include "llvm/CodeGen/MachineRegionInfo.h"
//===- lib/Codegen/MachineRegionInfo.cpp ----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/RegionInfoImpl.h"
#include "llvm/CodeGen/MachinePostDominators.h"
#include "llvm/CodeGen/MachineRegionInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "machine-region-info"
@ -11,36 +23,29 @@ STATISTIC(numMachineRegions, "The # of machine regions");
STATISTIC(numMachineSimpleRegions, "The # of simple machine regions");
namespace llvm {
template class RegionBase<RegionTraits<MachineFunction>>;
template class RegionNodeBase<RegionTraits<MachineFunction>>;
template class RegionInfoBase<RegionTraits<MachineFunction>>;
}
} // end namespace llvm
//===----------------------------------------------------------------------===//
// MachineRegion implementation
//
MachineRegion::MachineRegion(MachineBasicBlock *Entry, MachineBasicBlock *Exit,
MachineRegionInfo* RI,
MachineDominatorTree *DT, MachineRegion *Parent) :
RegionBase<RegionTraits<MachineFunction>>(Entry, Exit, RI, DT, Parent) {
RegionBase<RegionTraits<MachineFunction>>(Entry, Exit, RI, DT, Parent) {}
}
MachineRegion::~MachineRegion() { }
MachineRegion::~MachineRegion() = default;
//===----------------------------------------------------------------------===//
// MachineRegionInfo implementation
//
MachineRegionInfo::MachineRegionInfo() :
RegionInfoBase<RegionTraits<MachineFunction>>() {
MachineRegionInfo::MachineRegionInfo() = default;
}
MachineRegionInfo::~MachineRegionInfo() {
}
MachineRegionInfo::~MachineRegionInfo() = default;
void MachineRegionInfo::updateStatistics(MachineRegion *R) {
++numMachineRegions;
@ -73,9 +78,7 @@ MachineRegionInfoPass::MachineRegionInfoPass() : MachineFunctionPass(ID) {
initializeMachineRegionInfoPassPass(*PassRegistry::getPassRegistry());
}
MachineRegionInfoPass::~MachineRegionInfoPass() {
}
MachineRegionInfoPass::~MachineRegionInfoPass() = default;
bool MachineRegionInfoPass::runOnMachineFunction(MachineFunction &F) {
releaseMemory();
@ -137,8 +140,9 @@ INITIALIZE_PASS_END(MachineRegionInfoPass, DEBUG_TYPE,
// the link time optimization.
namespace llvm {
FunctionPass *createMachineRegionInfoPass() {
return new MachineRegionInfoPass();
}
FunctionPass *createMachineRegionInfoPass() {
return new MachineRegionInfoPass();
}
} // end namespace llvm

@ -36,6 +36,7 @@
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/StackMaps.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
@ -909,17 +910,43 @@ void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) {
}
}
// Generic loads and stores must have a single MachineMemOperand
// describing that access.
if ((MI->getOpcode() == TargetOpcode::G_LOAD ||
MI->getOpcode() == TargetOpcode::G_STORE) &&
!MI->hasOneMemOperand())
report("Generic instruction accessing memory must have one mem operand",
MI);
StringRef ErrorInfo;
if (!TII->verifyInstruction(*MI, ErrorInfo))
report(ErrorInfo.data(), MI);
// Verify properties of various specific instruction types
switch(MI->getOpcode()) {
default:
break;
case TargetOpcode::G_LOAD:
case TargetOpcode::G_STORE:
// Generic loads and stores must have a single MachineMemOperand
// describing that access.
if (!MI->hasOneMemOperand())
report("Generic instruction accessing memory must have one mem operand",
MI);
break;
case TargetOpcode::STATEPOINT:
if (!MI->getOperand(StatepointOpers::IDPos).isImm() ||
!MI->getOperand(StatepointOpers::NBytesPos).isImm() ||
!MI->getOperand(StatepointOpers::NCallArgsPos).isImm())
report("meta operands to STATEPOINT not constant!", MI);
break;
auto VerifyStackMapConstant = [&](unsigned Offset) {
if (!MI->getOperand(Offset).isImm() ||
MI->getOperand(Offset).getImm() != StackMaps::ConstantOp ||
!MI->getOperand(Offset + 1).isImm())
report("stack map constant to STATEPOINT not well formed!", MI);
};
const unsigned VarStart = StatepointOpers(MI).getVarIdx();
VerifyStackMapConstant(VarStart + StatepointOpers::CCOffset);
VerifyStackMapConstant(VarStart + StatepointOpers::FlagsOffset);
VerifyStackMapConstant(VarStart + StatepointOpers::NumDeoptOperandsOffset);
// TODO: verify we have properly encoded deopt arguments
};
}
void

@ -54,8 +54,6 @@ static void doSpillCalleeSavedRegs(MachineFunction &MF, RegScavenger *RS,
const MBBVector &SaveBlocks,
const MBBVector &RestoreBlocks);
static void doScavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger *RS);
namespace {
class PEI : public MachineFunctionPass {
public:
@ -84,7 +82,7 @@ private:
const MBBVector &SaveBlocks,
const MBBVector &RestoreBlocks)>
SpillCalleeSavedRegisters;
std::function<void(MachineFunction &MF, RegScavenger *RS)>
std::function<void(MachineFunction &MF, RegScavenger &RS)>
ScavengeFrameVirtualRegs;
bool UsesCalleeSaves = false;
@ -142,7 +140,6 @@ MachineFunctionPass *llvm::createPrologEpilogInserterPass() {
return new PEI();
}
STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
STATISTIC(NumBytesStackSpace,
"Number of bytes used for stack in all functions");
@ -168,10 +165,10 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) {
SpillCalleeSavedRegisters = [](MachineFunction &, RegScavenger *,
unsigned &, unsigned &, const MBBVector &,
const MBBVector &) {};
ScavengeFrameVirtualRegs = [](MachineFunction &, RegScavenger *) {};
ScavengeFrameVirtualRegs = [](MachineFunction &, RegScavenger &) {};
} else {
SpillCalleeSavedRegisters = doSpillCalleeSavedRegs;
ScavengeFrameVirtualRegs = doScavengeFrameVirtualRegs;
ScavengeFrameVirtualRegs = scavengeFrameVirtualRegs;
UsesCalleeSaves = true;
}
}
@ -222,7 +219,7 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) {
// post-pass, scavenge the virtual registers that frame index elimination
// inserted.
if (TRI->requiresRegisterScavenging(Fn) && FrameIndexVirtualScavenging) {
ScavengeFrameVirtualRegs(Fn, RS);
ScavengeFrameVirtualRegs(Fn, *RS);
// Clear any vregs created by virtual scavenging.
Fn.getRegInfo().clearVirtRegs();
@ -1153,92 +1150,3 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &Fn,
RS->forward(MI);
}
}
/// doScavengeFrameVirtualRegs - Replace all frame index virtual registers
/// with physical registers. Use the register scavenger to find an
/// appropriate register to use.
///
/// 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.
static void
doScavengeFrameVirtualRegs(MachineFunction &MF, RegScavenger *RS) {
// Run through the instructions and find any virtual registers.
MachineRegisterInfo &MRI = MF.getRegInfo();
for (MachineBasicBlock &MBB : MF) {
RS->enterBasicBlock(MBB);
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;
}
}
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
}

@ -58,8 +58,9 @@ namespace {
/// whenever a register is unavailable. This is not practical in production but
/// provides a useful baseline both for measuring other allocators and comparing
/// the speed of the basic algorithm against other styles of allocators.
class RABasic : public MachineFunctionPass, public RegAllocBase
{
class RABasic : public MachineFunctionPass,
public RegAllocBase,
private LiveRangeEdit::Delegate {
// context
MachineFunction *MF;
@ -72,6 +73,9 @@ class RABasic : public MachineFunctionPass, public RegAllocBase
// selectOrSplit().
BitVector UsableRegs;
bool LRE_CanEraseVirtReg(unsigned) override;
void LRE_WillShrinkVirtReg(unsigned) override;
public:
RABasic();
@ -121,17 +125,46 @@ char RABasic::ID = 0;
} // end anonymous namespace
char &llvm::RABasicID = RABasic::ID;
INITIALIZE_PASS_BEGIN(RABasic, "regallocbasic", "Basic Register Allocator",
false, false)
INITIALIZE_PASS_DEPENDENCY(LiveDebugVariables)
INITIALIZE_PASS_DEPENDENCY(SlotIndexes)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_DEPENDENCY(RegisterCoalescer)
INITIALIZE_PASS_DEPENDENCY(MachineScheduler)
INITIALIZE_PASS_DEPENDENCY(LiveStacks)
INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_DEPENDENCY(VirtRegMap)
INITIALIZE_PASS_DEPENDENCY(LiveRegMatrix)
INITIALIZE_PASS_END(RABasic, "regallocbasic", "Basic Register Allocator", false,
false)
bool RABasic::LRE_CanEraseVirtReg(unsigned VirtReg) {
if (VRM->hasPhys(VirtReg)) {
LiveInterval &LI = LIS->getInterval(VirtReg);
Matrix->unassign(LI);
aboutToRemoveInterval(LI);
return true;
}
// Unassigned virtreg is probably in the priority queue.
// RegAllocBase will erase it after dequeueing.
return false;
}
void RABasic::LRE_WillShrinkVirtReg(unsigned VirtReg) {
if (!VRM->hasPhys(VirtReg))
return;
// Register is assigned, put it back on the queue for reassignment.
LiveInterval &LI = LIS->getInterval(VirtReg);
Matrix->unassign(LI);
enqueue(&LI);
}
RABasic::RABasic(): MachineFunctionPass(ID) {
initializeLiveDebugVariablesPass(*PassRegistry::getPassRegistry());
initializeLiveIntervalsPass(*PassRegistry::getPassRegistry());
initializeSlotIndexesPass(*PassRegistry::getPassRegistry());
initializeRegisterCoalescerPass(*PassRegistry::getPassRegistry());
initializeMachineSchedulerPass(*PassRegistry::getPassRegistry());
initializeLiveStacksPass(*PassRegistry::getPassRegistry());
initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry());
initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry());
initializeVirtRegMapPass(*PassRegistry::getPassRegistry());
initializeLiveRegMatrixPass(*PassRegistry::getPassRegistry());
}
void RABasic::getAnalysisUsage(AnalysisUsage &AU) const {
@ -200,7 +233,7 @@ bool RABasic::spillInterferences(LiveInterval &VirtReg, unsigned PhysReg,
Matrix->unassign(Spill);
// Spill the extracted interval.
LiveRangeEdit LRE(&Spill, SplitVRegs, *MF, *LIS, VRM, nullptr, &DeadRemats);
LiveRangeEdit LRE(&Spill, SplitVRegs, *MF, *LIS, VRM, this, &DeadRemats);
spiller().spill(LRE);
}
return true;
@ -259,7 +292,7 @@ unsigned RABasic::selectOrSplit(LiveInterval &VirtReg,
DEBUG(dbgs() << "spilling: " << VirtReg << '\n');
if (!VirtReg.isSpillable())
return ~0u;
LiveRangeEdit LRE(&VirtReg, SplitVRegs, *MF, *LIS, VRM, nullptr, &DeadRemats);
LiveRangeEdit LRE(&VirtReg, SplitVRegs, *MF, *LIS, VRM, this, &DeadRemats);
spiller().spill(LRE);
// The live virtual register requesting allocation was spilled, so tell

@ -49,9 +49,11 @@
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/PBQP/Graph.h"
#include "llvm/CodeGen/PBQP/Math.h"
#include "llvm/CodeGen/PBQP/Solution.h"
#include "llvm/CodeGen/PBQPRAConstraint.h"
#include "llvm/CodeGen/RegAllocPBQP.h"
@ -139,13 +141,13 @@ public:
}
private:
typedef std::map<const LiveInterval*, unsigned> LI2NodeMap;
typedef std::vector<const LiveInterval*> Node2LIMap;
typedef std::vector<unsigned> AllowedSet;
typedef std::vector<AllowedSet> AllowedSetMap;
typedef std::pair<unsigned, unsigned> RegPair;
typedef std::map<RegPair, PBQP::PBQPNum> CoalesceMap;
typedef std::set<unsigned> RegSet;
using LI2NodeMap = std::map<const LiveInterval *, unsigned>;
using Node2LIMap = std::vector<const LiveInterval *>;
using AllowedSet = std::vector<unsigned>;
using AllowedSetMap = std::vector<AllowedSet>;
using RegPair = std::pair<unsigned, unsigned>;
using CoalesceMap = std::map<RegPair, PBQP::PBQPNum>;
using RegSet = std::set<unsigned>;
char *customPassID;
@ -212,12 +214,12 @@ public:
/// @brief Add interference edges between overlapping vregs.
class Interference : public PBQPRAConstraint {
private:
typedef const PBQP::RegAlloc::AllowedRegVector* AllowedRegVecPtr;
typedef std::pair<AllowedRegVecPtr, AllowedRegVecPtr> IKey;
typedef DenseMap<IKey, PBQPRAGraph::MatrixPtr> IMatrixCache;
typedef DenseSet<IKey> DisjointAllowedRegsCache;
typedef std::pair<PBQP::GraphBase::NodeId, PBQP::GraphBase::NodeId> IEdgeKey;
typedef DenseSet<IEdgeKey> IEdgeCache;
using AllowedRegVecPtr = const PBQP::RegAlloc::AllowedRegVector *;
using IKey = std::pair<AllowedRegVecPtr, AllowedRegVecPtr>;
using IMatrixCache = DenseMap<IKey, PBQPRAGraph::MatrixPtr>;
using DisjointAllowedRegsCache = DenseSet<IKey>;
using IEdgeKey = std::pair<PBQP::GraphBase::NodeId, PBQP::GraphBase::NodeId>;
using IEdgeCache = DenseSet<IEdgeKey>;
bool haveDisjointAllowedRegs(const PBQPRAGraph &G, PBQPRAGraph::NodeId NId,
PBQPRAGraph::NodeId MId,
@ -252,8 +254,8 @@ private:
// for the fast interference graph construction algorithm. The last is there
// to save us from looking up node ids via the VRegToNode map in the graph
// metadata.
typedef std::tuple<LiveInterval*, size_t, PBQP::GraphBase::NodeId>
IntervalInfo;
using IntervalInfo =
std::tuple<LiveInterval*, size_t, PBQP::GraphBase::NodeId>;
static SlotIndex getStartPoint(const IntervalInfo &I) {
return std::get<0>(I)->segments[std::get<1>(I)].start;
@ -320,9 +322,10 @@ public:
// Cache known disjoint allowed registers pairs
DisjointAllowedRegsCache D;
typedef std::set<IntervalInfo, decltype(&lowestEndPoint)> IntervalSet;
typedef std::priority_queue<IntervalInfo, std::vector<IntervalInfo>,
decltype(&lowestStartPoint)> IntervalQueue;
using IntervalSet = std::set<IntervalInfo, decltype(&lowestEndPoint)>;
using IntervalQueue =
std::priority_queue<IntervalInfo, std::vector<IntervalInfo>,
decltype(&lowestStartPoint)>;
IntervalSet Active(lowestEndPoint);
IntervalQueue Inactive(lowestStartPoint);
@ -658,7 +661,6 @@ void RegAllocPBQP::spillVReg(unsigned VReg,
SmallVectorImpl<unsigned> &NewIntervals,
MachineFunction &MF, LiveIntervals &LIS,
VirtRegMap &VRM, Spiller &VRegSpiller) {
VRegsToAlloc.erase(VReg);
LiveRangeEdit LRE(&LIS.getInterval(VReg), NewIntervals, MF, LIS, &VRM,
nullptr, &DeadRemats);

@ -15,18 +15,23 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/PassSupport.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
@ -39,6 +44,8 @@ using namespace llvm;
#define DEBUG_TYPE "reg-scavenging"
STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged");
void RegScavenger::setRegUsed(unsigned Reg, LaneBitmask LaneMask) {
LiveUnits.addRegMasked(Reg, LaneMask);
}
@ -469,3 +476,120 @@ unsigned RegScavenger::scavengeRegister(const TargetRegisterClass *RC,
return SReg;
}
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.
// Run through the instructions and find any virtual registers.
MachineRegisterInfo &MRI = MF.getRegInfo();
for (MachineBasicBlock &MBB : MF) {
RS.enterBasicBlock(MBB);
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;
}
}
MRI.clearVirtRegs();
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
}
namespace {
/// This class runs register scavenging independ of the PrologEpilogInserter.
/// This is used in for testing.
class ScavengerTest : public MachineFunctionPass {
public:
static char ID;
ScavengerTest() : MachineFunctionPass(ID) {}
bool runOnMachineFunction(MachineFunction &MF) {
const TargetSubtargetInfo &STI = MF.getSubtarget();
const TargetFrameLowering &TFL = *STI.getFrameLowering();
RegScavenger RS;
// Let's hope that calling those outside of PrologEpilogueInserter works
// well enough to initialize the scavenger with some emergency spillslots
// for the target.
BitVector SavedRegs;
TFL.determineCalleeSaves(MF, SavedRegs, &RS);
TFL.processFunctionBeforeFrameFinalized(MF, &RS);
// Let's scavenge the current function
scavengeFrameVirtualRegs(MF, RS);
return true;
}
};
char ScavengerTest::ID;
} // end anonymous namespace
INITIALIZE_PASS(ScavengerTest, "scavenger-test",
"Scavenge virtual registers inside basic blocks", false, false)

@ -12,32 +12,54 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
#include "llvm/ADT/IntEqClasses.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SparseSet.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBundle.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/CodeGen/RegisterPressure.h"
#include "llvm/CodeGen/ScheduleDAG.h"
#include "llvm/CodeGen/ScheduleDAGInstrs.h"
#include "llvm/CodeGen/ScheduleDFS.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/MC/LaneBitmask.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <string>
#include <utility>
#include <vector>
using namespace llvm;
@ -90,11 +112,9 @@ ScheduleDAGInstrs::ScheduleDAGInstrs(MachineFunction &mf,
const MachineLoopInfo *mli,
bool RemoveKillFlags)
: ScheduleDAG(mf), MLI(mli), MFI(mf.getFrameInfo()),
RemoveKillFlags(RemoveKillFlags), CanHandleTerminators(false),
TrackLaneMasks(false), AAForDep(nullptr), BarrierChain(nullptr),
RemoveKillFlags(RemoveKillFlags),
UnknownValue(UndefValue::get(
Type::getVoidTy(mf.getFunction()->getContext()))),
FirstDbgValue(nullptr) {
Type::getVoidTy(mf.getFunction()->getContext()))) {
DbgValues.clear();
const TargetSubtargetInfo &ST = mf.getSubtarget();
@ -126,7 +146,7 @@ static const Value *getUnderlyingObjectFromInt(const Value *V) {
return V;
}
assert(V->getType()->isIntegerTy() && "Unexpected operand type!");
} while (1);
} while (true);
}
/// This is a wrapper around GetUnderlyingObjects and adds support for basic
@ -563,7 +583,7 @@ void ScheduleDAGInstrs::initSUnits() {
// which is contained within a basic block.
SUnits.reserve(NumRegionInstrs);
for (MachineInstr &MI : llvm::make_range(RegionBegin, RegionEnd)) {
for (MachineInstr &MI : make_range(RegionBegin, RegionEnd)) {
if (MI.isDebugValue())
continue;
@ -606,13 +626,13 @@ void ScheduleDAGInstrs::initSUnits() {
class ScheduleDAGInstrs::Value2SUsMap : public MapVector<ValueType, SUList> {
/// Current total number of SUs in map.
unsigned NumNodes;
unsigned NumNodes = 0;
/// 1 for loads, 0 for stores. (see comment in SUList)
unsigned TrueMemOrderLatency;
public:
Value2SUsMap(unsigned lat = 0) : NumNodes(0), TrueMemOrderLatency(lat) {}
Value2SUsMap(unsigned lat = 0) : TrueMemOrderLatency(lat) {}
/// To keep NumNodes up to date, insert() is used instead of
/// this operator w/ push_back().
@ -630,7 +650,7 @@ public:
void inline clearList(ValueType V) {
iterator Itr = find(V);
if (Itr != end()) {
assert (NumNodes >= Itr->second.size());
assert(NumNodes >= Itr->second.size());
NumNodes -= Itr->second.size();
Itr->second.clear();
@ -646,7 +666,7 @@ public:
unsigned inline size() const { return NumNodes; }
/// Counts the number of SUs in this map after a reduction.
void reComputeSize(void) {
void reComputeSize() {
NumNodes = 0;
for (auto &I : *this)
NumNodes += I.second.size();
@ -676,7 +696,7 @@ void ScheduleDAGInstrs::addChainDependencies(SUnit *SU,
}
void ScheduleDAGInstrs::addBarrierChain(Value2SUsMap &map) {
assert (BarrierChain != nullptr);
assert(BarrierChain != nullptr);
for (auto &I : map) {
SUList &sus = I.second;
@ -687,7 +707,7 @@ void ScheduleDAGInstrs::addBarrierChain(Value2SUsMap &map) {
}
void ScheduleDAGInstrs::insertBarrierChain(Value2SUsMap &map) {
assert (BarrierChain != nullptr);
assert(BarrierChain != nullptr);
// Go through all lists of SUs.
for (Value2SUsMap::iterator I = map.begin(), EE = map.end(); I != EE;) {
@ -1028,7 +1048,7 @@ void ScheduleDAGInstrs::reduceHugeMemNodeMaps(Value2SUsMap &stores,
// The N last elements in NodeNums will be removed, and the SU with
// the lowest NodeNum of them will become the new BarrierChain to
// let the not yet seen SUs have a dependency to the removed SUs.
assert (N <= NodeNums.size());
assert(N <= NodeNums.size());
SUnit *newBarrierChain = &SUnits[*(NodeNums.end() - N)];
if (BarrierChain) {
// The aliasing and non-aliasing maps reduce independently of each
@ -1156,6 +1176,7 @@ std::string ScheduleDAGInstrs::getDAGName() const {
//===----------------------------------------------------------------------===//
namespace llvm {
/// Internal state used to compute SchedDFSResult.
class SchedDFSImpl {
SchedDFSResult &R;
@ -1163,16 +1184,16 @@ class SchedDFSImpl {
/// Join DAG nodes into equivalence classes by their subtree.
IntEqClasses SubtreeClasses;
/// List PredSU, SuccSU pairs that represent data edges between subtrees.
std::vector<std::pair<const SUnit*, const SUnit*> > ConnectionPairs;
std::vector<std::pair<const SUnit *, const SUnit*>> ConnectionPairs;
struct RootData {
unsigned NodeID;
unsigned ParentNodeID; ///< Parent node (member of the parent subtree).
unsigned SubInstrCount; ///< Instr count in this tree only, not children.
unsigned SubInstrCount = 0; ///< Instr count in this tree only, not
/// children.
RootData(unsigned id): NodeID(id),
ParentNodeID(SchedDFSResult::InvalidSubtreeID),
SubInstrCount(0) {}
ParentNodeID(SchedDFSResult::InvalidSubtreeID) {}
unsigned getSparseSetIndex() const { return NodeID; }
};
@ -1340,12 +1361,15 @@ protected:
} while (FromTree != SchedDFSResult::InvalidSubtreeID);
}
};
} // end namespace llvm
namespace {
/// Manage the stack used by a reverse depth-first search over the DAG.
class SchedDAGReverseDFS {
std::vector<std::pair<const SUnit*, SUnit::const_pred_iterator> > DFSStack;
std::vector<std::pair<const SUnit *, SUnit::const_pred_iterator>> DFSStack;
public:
bool isComplete() const { return DFSStack.empty(); }
@ -1367,7 +1391,8 @@ public:
return getCurr()->Preds.end();
}
};
} // anonymous
} // end anonymous namespace
static bool hasDataSucc(const SUnit *SU) {
for (const SDep &SuccDep : SU->Succs) {
@ -1392,7 +1417,7 @@ void SchedDFSResult::compute(ArrayRef<SUnit> SUnits) {
SchedDAGReverseDFS DFS;
Impl.visitPreorder(&SU);
DFS.follow(&SU);
for (;;) {
while (true) {
// Traverse the leftmost path as far as possible.
while (DFS.getPred() != DFS.getPredEnd()) {
const SDep &PredDep = *DFS.getPred();
@ -1457,4 +1482,5 @@ raw_ostream &operator<<(raw_ostream &OS, const ILPValue &Val) {
}
} // end namespace llvm
#endif

@ -225,6 +225,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {
}
return TranslateLegalizeResults(Op, Lowered);
}
LLVM_FALLTHROUGH;
case TargetLowering::Expand:
Changed = true;
return LegalizeOp(ExpandLoad(Op));

@ -1,4 +1,4 @@
//===-- SelectionDAG.cpp - Implement the SelectionDAG data structures -----===//
//===- SelectionDAG.cpp - Implement the SelectionDAG data structures ------===//
//
// The LLVM Compiler Infrastructure
//
@ -11,29 +11,46 @@
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/SelectionDAG.h"
#include "SDNodeDbgValue.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/ISDOpcodes.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineMemOperand.h"
#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/CodeGen/RuntimeLibcalls.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/SelectionDAGTargetInfo.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/KnownBits.h"
@ -41,16 +58,20 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetIntrinsicInfo.h"
#include "llvm/Target/TargetLowering.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <algorithm>
#include <cmath>
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <set>
#include <string>
#include <utility>
#include <vector>
using namespace llvm;
@ -269,7 +290,6 @@ ISD::CondCode ISD::getSetCCInverse(ISD::CondCode Op, bool isInteger) {
return ISD::CondCode(Operation);
}
/// For an integer comparison, return 1 if the comparison is a signed operation
/// and 2 if the result is an unsigned comparison. Return zero if the operation
/// does not depend on the sign of the input (setne and seteq).
@ -338,7 +358,6 @@ ISD::CondCode ISD::getSetCCAndOperation(ISD::CondCode Op1, ISD::CondCode Op2,
//===----------------------------------------------------------------------===//
/// AddNodeIDOpcode - Add the node opcode to the NodeID data.
///
static void AddNodeIDOpcode(FoldingSetNodeID &ID, unsigned OpC) {
ID.AddInteger(OpC);
}
@ -350,7 +369,6 @@ static void AddNodeIDValueTypes(FoldingSetNodeID &ID, SDVTList VTList) {
}
/// AddNodeIDOperands - Various routines for adding operands to the NodeID data.
///
static void AddNodeIDOperands(FoldingSetNodeID &ID,
ArrayRef<SDValue> Ops) {
for (auto& Op : Ops) {
@ -360,7 +378,6 @@ static void AddNodeIDOperands(FoldingSetNodeID &ID,
}
/// AddNodeIDOperands - Various routines for adding operands to the NodeID data.
///
static void AddNodeIDOperands(FoldingSetNodeID &ID,
ArrayRef<SDUse> Ops) {
for (auto& Op : Ops) {
@ -392,10 +409,9 @@ static void AddNodeIDCustom(FoldingSetNodeID &ID, const SDNode *N) {
break;
}
case ISD::TargetConstantFP:
case ISD::ConstantFP: {
case ISD::ConstantFP:
ID.AddPointer(cast<ConstantFPSDNode>(N)->getConstantFPValue());
break;
}
case ISD::TargetGlobalAddress:
case ISD::GlobalAddress:
case ISD::TargetGlobalTLSAddress:
@ -770,7 +786,6 @@ bool SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) {
/// maps and modified in place. Add it back to the CSE maps, unless an identical
/// node already exists, in which case transfer all its users to the existing
/// node. This transfer can potentially trigger recursive merging.
///
void
SelectionDAG::AddModifiedNodeToCSEMaps(SDNode *N) {
// For node types that aren't CSE'd, just act as if no identical node
@ -835,7 +850,6 @@ SDNode *SelectionDAG::FindModifiedNodeSlot(SDNode *N,
return Node;
}
/// FindModifiedNodeSlot - Find a slot for the specified node if its operands
/// were replaced with those specified. If this node is never memoized,
/// return null, otherwise return a pointer to the slot it would take. If a
@ -864,10 +878,9 @@ unsigned SelectionDAG::getEVTAlignment(EVT VT) const {
// EntryNode could meaningfully have debug info if we can find it...
SelectionDAG::SelectionDAG(const TargetMachine &tm, CodeGenOpt::Level OL)
: TM(tm), TSI(nullptr), TLI(nullptr), OptLevel(OL),
: TM(tm), OptLevel(OL),
EntryNode(ISD::EntryToken, 0, DebugLoc(), getVTList(MVT::Other)),
Root(getEntryNode()), NewNodesMustHaveLegalTypes(false),
UpdateListeners(nullptr) {
Root(getEntryNode()) {
InsertNode(&EntryNode);
DbgInfo = new SDDbgInfo();
}
@ -1038,7 +1051,6 @@ SDValue SelectionDAG::getZeroExtendVectorInReg(SDValue Op, const SDLoc &DL,
}
/// getNOT - Create a bitwise NOT operation as (XOR Val, -1).
///
SDValue SelectionDAG::getNOT(const SDLoc &DL, SDValue Val, EVT VT) {
EVT EltVT = VT.getScalarType();
SDValue NegOne =
@ -1317,7 +1329,6 @@ SDValue SelectionDAG::getConstantPool(const Constant *C, EVT VT,
return SDValue(N, 0);
}
SDValue SelectionDAG::getConstantPool(MachineConstantPoolValue *C, EVT VT,
unsigned Alignment, int Offset,
bool isTarget,
@ -1451,7 +1462,7 @@ SDValue SelectionDAG::getVectorShuffle(EVT VT, const SDLoc &dl, SDValue N1,
// Validate that all indices in Mask are within the range of the elements
// input to the shuffle.
int NElts = Mask.size();
assert(all_of(Mask, [&](int M) { return M < (NElts * 2); }) &&
assert(llvm::all_of(Mask, [&](int M) { return M < (NElts * 2); }) &&
"Index out of range");
// Copy the mask so we can do any needed cleanup.
@ -2918,7 +2929,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
else
DemandedRHS.setBit((unsigned)M % NumElts);
}
Tmp = UINT_MAX;
Tmp = std::numeric_limits<unsigned>::max();
if (!!DemandedLHS)
Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedLHS, Depth + 1);
if (!!DemandedRHS) {
@ -3122,7 +3133,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
unsigned EltIdx = CEltNo->getZExtValue();
// If we demand the inserted element then get its sign bits.
Tmp = UINT_MAX;
Tmp = std::numeric_limits<unsigned>::max();
if (DemandedElts[EltIdx]) {
// TODO - handle implicit truncation of inserted elements.
if (InVal.getScalarValueSizeInBits() != VTBits)
@ -3188,7 +3199,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
case ISD::CONCAT_VECTORS:
// Determine the minimum number of sign bits across all demanded
// elts of the input vectors. Early out if the result is already 1.
Tmp = UINT_MAX;
Tmp = std::numeric_limits<unsigned>::max();
EVT SubVectorVT = Op.getOperand(0).getValueType();
unsigned NumSubVectorElts = SubVectorVT.getVectorNumElements();
unsigned NumSubVectors = Op.getNumOperands();
@ -3327,7 +3338,7 @@ bool SelectionDAG::haveNoCommonBitsSet(SDValue A, SDValue B) const {
static SDValue FoldCONCAT_VECTORS(const SDLoc &DL, EVT VT,
ArrayRef<SDValue> Ops,
llvm::SelectionDAG &DAG) {
SelectionDAG &DAG) {
assert(!Ops.empty() && "Can't concatenate an empty list of vectors!");
assert(llvm::all_of(Ops,
[Ops](SDValue Op) {
@ -3836,8 +3847,9 @@ bool SelectionDAG::isUndef(unsigned Opcode, ArrayRef<SDValue> Ops) {
return true;
return ISD::isBuildVectorOfConstantSDNodes(Divisor.getNode()) &&
any_of(Divisor->op_values(),
[](SDValue V) { return V.isUndef() || isNullConstant(V); });
llvm::any_of(Divisor->op_values(),
[](SDValue V) { return V.isUndef() ||
isNullConstant(V); });
// TODO: Handle signed overflow.
}
// TODO: Handle oversized shifts.
@ -3948,8 +3960,8 @@ SDValue SelectionDAG::FoldConstantVectorArithmetic(unsigned Opcode,
// All operands must be vector types with the same number of elements as
// the result type and must be either UNDEF or a build vector of constant
// or UNDEF scalars.
if (!all_of(Ops, IsConstantBuildVectorOrUndef) ||
!all_of(Ops, IsScalarOrSameVectorSize))
if (!llvm::all_of(Ops, IsConstantBuildVectorOrUndef) ||
!llvm::all_of(Ops, IsScalarOrSameVectorSize))
return SDValue();
// If we are comparing vectors, then the result needs to be a i1 boolean
@ -5550,7 +5562,7 @@ SDValue SelectionDAG::getMemIntrinsicNode(unsigned Opcode, const SDLoc &dl,
Opcode == ISD::PREFETCH ||
Opcode == ISD::LIFETIME_START ||
Opcode == ISD::LIFETIME_END ||
(Opcode <= INT_MAX &&
((int)Opcode <= std::numeric_limits<int>::max() &&
(int)Opcode >= ISD::FIRST_TARGET_MEMORY_OPCODE)) &&
"Opcode is not a memory-accessing opcode!");
@ -5884,7 +5896,6 @@ SDValue SelectionDAG::getMaskedLoad(EVT VT, const SDLoc &dl, SDValue Chain,
SDValue Ptr, SDValue Mask, SDValue Src0,
EVT MemVT, MachineMemOperand *MMO,
ISD::LoadExtType ExtTy, bool isExpanding) {
SDVTList VTs = getVTList(VT, MVT::Other);
SDValue Ops[] = { Chain, Ptr, Mask, Src0 };
FoldingSetNodeID ID;
@ -6038,13 +6049,12 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
switch (Opcode) {
default: break;
case ISD::CONCAT_VECTORS: {
case ISD::CONCAT_VECTORS:
// Attempt to fold CONCAT_VECTORS into BUILD_VECTOR or UNDEF.
if (SDValue V = FoldCONCAT_VECTORS(DL, VT, Ops, *this))
return V;
break;
}
case ISD::SELECT_CC: {
case ISD::SELECT_CC:
assert(NumOps == 5 && "SELECT_CC takes 5 operands!");
assert(Ops[0].getValueType() == Ops[1].getValueType() &&
"LHS and RHS of condition must have same type!");
@ -6053,14 +6063,12 @@ SDValue SelectionDAG::getNode(unsigned Opcode, const SDLoc &DL, EVT VT,
assert(Ops[2].getValueType() == VT &&
"select_cc node must be of same type as true and false value!");
break;
}
case ISD::BR_CC: {
case ISD::BR_CC:
assert(NumOps == 5 && "BR_CC takes 5 operands!");
assert(Ops[2].getValueType() == Ops[3].getValueType() &&
"LHS/RHS of comparison should match types!");
break;
}
}
// Memoize nodes.
SDNode *N;
@ -6599,7 +6607,6 @@ SDNode* SelectionDAG::mutateStrictFPToFP(SDNode *Node) {
return Res;
}
/// getMachineNode - These are used for target selectors to create a new node
/// with specified return type(s), MachineInstr opcode, and operands.
///
@ -6812,7 +6819,7 @@ public:
: SelectionDAG::DAGUpdateListener(d), UI(ui), UE(ue) {}
};
}
} // end anonymous namespace
/// ReplaceAllUsesWith - Modify anything using 'From' to use 'To' instead.
/// This can cause recursive merging of nodes in the DAG.
@ -6858,7 +6865,6 @@ void SelectionDAG::ReplaceAllUsesWith(SDValue FromN, SDValue To) {
AddModifiedNodeToCSEMaps(User);
}
// If we just RAUW'd the root, take note.
if (FromN == getRoot())
setRoot(To);
@ -7028,6 +7034,7 @@ void SelectionDAG::ReplaceAllUsesOfValueWith(SDValue From, SDValue To){
}
namespace {
/// UseMemo - This class is used by SelectionDAG::ReplaceAllUsesOfValuesWith
/// to record information about a use.
struct UseMemo {
@ -7040,7 +7047,8 @@ namespace {
bool operator<(const UseMemo &L, const UseMemo &R) {
return (intptr_t)L.User < (intptr_t)R.User;
}
}
} // end anonymous namespace
/// ReplaceAllUsesOfValuesWith - Replace any uses of From with To, leaving
/// uses of other values produced by From.getNode() alone. The same value
@ -7106,7 +7114,6 @@ void SelectionDAG::ReplaceAllUsesOfValuesWith(const SDValue *From,
/// based on their topological order. It returns the maximum id and a vector
/// of the SDNodes* in assigned order by reference.
unsigned SelectionDAG::AssignTopologicalOrder() {
unsigned DAGSize = 0;
// SortedPos tracks the progress of the algorithm. Nodes before it are
@ -7333,6 +7340,7 @@ void SDNode::Profile(FoldingSetNodeID &ID) const {
}
namespace {
struct EVTArray {
std::vector<EVT> VTs;
@ -7342,11 +7350,12 @@ namespace {
VTs.push_back(MVT((MVT::SimpleValueType)i));
}
};
}
static ManagedStatic<std::set<EVT, EVT::compareRawBits> > EVTs;
} // end anonymous namespace
static ManagedStatic<std::set<EVT, EVT::compareRawBits>> EVTs;
static ManagedStatic<EVTArray> SimpleVTArray;
static ManagedStatic<sys::SmartMutex<true> > VTMutex;
static ManagedStatic<sys::SmartMutex<true>> VTMutex;
/// getValueTypeList - Return a pointer to the specified value type.
///
@ -7380,7 +7389,6 @@ bool SDNode::hasNUsesOfValue(unsigned NUses, unsigned Value) const {
return NUses == 0;
}
/// hasAnyUseOfValue - Return true if there are any use of the indicated
/// value. This method ignores uses of other values defined by this operation.
bool SDNode::hasAnyUseOfValue(unsigned Value) const {
@ -7393,9 +7401,7 @@ bool SDNode::hasAnyUseOfValue(unsigned Value) const {
return false;
}
/// isOnlyUserOf - Return true if this node is the only use of N.
///
bool SDNode::isOnlyUserOf(const SDNode *N) const {
bool Seen = false;
for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I) {
@ -7425,7 +7431,6 @@ bool SDNode::areOnlyUsersOf(ArrayRef<const SDNode *> Nodes, const SDNode *N) {
}
/// isOperand - Return true if this node is an operand of N.
///
bool SDValue::isOperandOf(const SDNode *N) const {
for (const SDValue &Op : N->op_values())
if (*this == Op)
@ -7475,7 +7480,7 @@ bool SDValue::reachesChainWithoutSideEffects(SDValue Dest,
}
// Next, try a deep search: check whether every operand of the TokenFactor
// reaches Dest.
return all_of((*this)->ops(), [=](SDValue Op) {
return llvm::all_of((*this)->ops(), [=](SDValue Op) {
return Op.reachesChainWithoutSideEffects(Dest, Depth - 1);
});
}
@ -7627,7 +7632,6 @@ bool SelectionDAG::areNonVolatileConsecutiveLoads(LoadSDNode *LD,
return false;
}
/// InferPtrAlignment - Infer alignment of a load / store address. Return 0 if
/// it cannot be inferred.
unsigned SelectionDAG::InferPtrAlignment(SDValue Ptr) const {
@ -7718,7 +7722,6 @@ unsigned GlobalAddressSDNode::getAddressSpace() const {
return getGlobal()->getType()->getAddressSpace();
}
Type *ConstantPoolSDNode::getType() const {
if (isMachineConstantPoolEntry())
return Val.MachineCPVal->getType();

@ -2022,7 +2022,7 @@ static SDNode *findGlueUse(SDNode *N) {
}
/// findNonImmUse - Return true if "Use" is a non-immediate use of "Def".
/// This function recursively traverses up the operand chain, ignoring
/// This function iteratively traverses up the operand chain, ignoring
/// certain nodes.
static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse,
SDNode *Root, SmallPtrSetImpl<SDNode*> &Visited,
@ -2035,30 +2035,36 @@ static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse,
// The Use may be -1 (unassigned) if it is a newly allocated node. This can
// happen because we scan down to newly selected nodes in the case of glue
// uses.
if ((Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1))
return false;
std::vector<SDNode *> WorkList;
WorkList.push_back(Use);
// Don't revisit nodes if we already scanned it and didn't fail, we know we
// won't fail if we scan it again.
if (!Visited.insert(Use).second)
return false;
for (const SDValue &Op : Use->op_values()) {
// Ignore chain uses, they are validated by HandleMergeInputChains.
if (Op.getValueType() == MVT::Other && IgnoreChains)
while (!WorkList.empty()) {
Use = WorkList.back();
WorkList.pop_back();
if (Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1)
continue;
SDNode *N = Op.getNode();
if (N == Def) {
if (Use == ImmedUse || Use == Root)
continue; // We are not looking for immediate use.
assert(N != Root);
return true;
}
// Don't revisit nodes if we already scanned it and didn't fail, we know we
// won't fail if we scan it again.
if (!Visited.insert(Use).second)
continue;
// Traverse up the operand chain.
if (findNonImmUse(N, Def, ImmedUse, Root, Visited, IgnoreChains))
return true;
for (const SDValue &Op : Use->op_values()) {
// Ignore chain uses, they are validated by HandleMergeInputChains.
if (Op.getValueType() == MVT::Other && IgnoreChains)
continue;
SDNode *N = Op.getNode();
if (N == Def) {
if (Use == ImmedUse || Use == Root)
continue; // We are not looking for immediate use.
assert(N != Root);
return true;
}
// Traverse up the operand chain.
WorkList.push_back(N);
}
}
return false;
}

@ -818,7 +818,7 @@ SelectionDAGBuilder::LowerStatepoint(ImmutableStatepoint ISP,
SI.GCTransitionArgs =
ArrayRef<const Use>(ISP.gc_args_begin(), ISP.gc_args_end());
SI.ID = ISP.getID();
SI.DeoptState = ArrayRef<const Use>(ISP.vm_state_begin(), ISP.vm_state_end());
SI.DeoptState = ArrayRef<const Use>(ISP.deopt_begin(), ISP.deopt_end());
SI.StatepointFlags = ISP.getFlags();
SI.NumPatchBytes = ISP.getNumPatchBytes();
SI.EHPadBB = EHPadBB;

@ -1493,8 +1493,7 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
}
}
// Ensure that the constant occurs on the RHS, and fold constant
// comparisons.
// Ensure that the constant occurs on the RHS and fold constant comparisons.
ISD::CondCode SwappedCC = ISD::getSetCCSwappedOperands(Cond);
if (isa<ConstantSDNode>(N0.getNode()) &&
(DCI.isBeforeLegalizeOps() ||
@ -1638,14 +1637,13 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
return DAG.getSetCC(dl, VT, TopSetCC.getOperand(0),
TopSetCC.getOperand(1),
InvCond);
}
}
}
// If the LHS is '(and load, const)', the RHS is 0,
// the test is for equality or unsigned, and all 1 bits of the const are
// in the same partial word, see if we can shorten the load.
// If the LHS is '(and load, const)', the RHS is 0, the test is for
// equality or unsigned, and all 1 bits of the const are in the same
// partial word, see if we can shorten the load.
if (DCI.isBeforeLegalize() &&
!ISD::isSignedIntSetCC(Cond) &&
N0.getOpcode() == ISD::AND && C1 == 0 &&
@ -1669,10 +1667,10 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
APInt newMask = APInt::getLowBitsSet(maskWidth, width);
for (unsigned offset=0; offset<origWidth/width; offset++) {
if ((newMask & Mask) == Mask) {
if (!DAG.getDataLayout().isLittleEndian())
bestOffset = (origWidth/width - offset - 1) * (width/8);
else
if (DAG.getDataLayout().isLittleEndian())
bestOffset = (uint64_t)offset * (width/8);
else
bestOffset = (origWidth/width - offset - 1) * (width/8);
bestMask = Mask.lshr(offset * (width/8) * 8);
bestWidth = width;
break;
@ -1713,10 +1711,12 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
switch (Cond) {
case ISD::SETUGT:
case ISD::SETUGE:
case ISD::SETEQ: return DAG.getConstant(0, dl, VT);
case ISD::SETEQ:
return DAG.getConstant(0, dl, VT);
case ISD::SETULT:
case ISD::SETULE:
case ISD::SETNE: return DAG.getConstant(1, dl, VT);
case ISD::SETNE:
return DAG.getConstant(1, dl, VT);
case ISD::SETGT:
case ISD::SETGE:
// True if the sign bit of C1 is set.
@ -1816,9 +1816,9 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
BitWidth-1))) {
// Okay, get the un-inverted input value.
SDValue Val;
if (N0.getOpcode() == ISD::XOR)
if (N0.getOpcode() == ISD::XOR) {
Val = N0.getOperand(0);
else {
} else {
assert(N0.getOpcode() == ISD::AND &&
N0.getOperand(0).getOpcode() == ISD::XOR);
// ((X^1)&1)^1 -> X & 1
@ -1883,7 +1883,10 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
// Canonicalize GE/LE comparisons to use GT/LT comparisons.
if (Cond == ISD::SETGE || Cond == ISD::SETUGE) {
if (C1 == MinVal) return DAG.getConstant(1, dl, VT); // X >= MIN --> true
// X >= MIN --> true
if (C1 == MinVal)
return DAG.getConstant(1, dl, VT);
// X >= C0 --> X > (C0 - 1)
APInt C = C1 - 1;
ISD::CondCode NewCC = (Cond == ISD::SETGE) ? ISD::SETGT : ISD::SETUGT;
@ -1898,7 +1901,10 @@ SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
}
if (Cond == ISD::SETLE || Cond == ISD::SETULE) {
if (C1 == MaxVal) return DAG.getConstant(1, dl, VT); // X <= MAX --> true
// X <= MAX --> true
if (C1 == MaxVal)
return DAG.getConstant(1, dl, VT);
// X <= C0 --> X < (C0 + 1)
APInt C = C1 + 1;
ISD::CondCode NewCC = (Cond == ISD::SETLE) ? ISD::SETLT : ISD::SETULT;

@ -1456,6 +1456,7 @@ void TargetLoweringBase::computeRegisterProperties(
}
if (IsLegalWiderType)
break;
LLVM_FALLTHROUGH;
}
case TypeWidenVector: {
// Try to widen the vector.
@ -1473,6 +1474,7 @@ void TargetLoweringBase::computeRegisterProperties(
}
if (IsLegalWiderType)
break;
LLVM_FALLTHROUGH;
}
case TypeSplitVector:
case TypeScalarizeVector: {

@ -27,6 +27,14 @@ Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) {
Error CodeViewRecordIO::endRecord() {
assert(!Limits.empty() && "Not in a record!");
Limits.pop_back();
// We would like to assert that we actually read / wrote all the bytes that we
// expected to for this record, but unfortunately we can't do this. Some
// producers such as MASM over-allocate for certain types of records and
// commit the extraneous data, so when reading we can't be sure every byte
// will have been read. And when writing we over-allocate temporarily since
// we don't know how big the record is until we're finished writing it, so
// even though we don't commit the extraneous data, we still can't guarantee
// we're at the end of the allocated data.
return Error::success();
}
@ -49,6 +57,12 @@ uint32_t CodeViewRecordIO::maxFieldLength() const {
return *Min;
}
Error CodeViewRecordIO::padToAlignment(uint32_t Align) {
if (isReading())
return Reader->padToAlignment(Align);
return Writer->padToAlignment(Align);
}
Error CodeViewRecordIO::skipPadding() {
assert(!isWriting() && "Cannot skip padding while writing!");

Some files were not shown because too many files have changed in this diff Show More