Merge llvm, clang, lld, lldb, compiler-rt and libc++ r304659, and update
build glue.
This commit is contained in:
commit
6d97bb297c
contrib
compiler-rt
include/sanitizer
lib
asan
lsan
sanitizer_common
sanitizer_common.hsanitizer_coverage_interface.incsanitizer_coverage_libcdep.ccsanitizer_coverage_libcdep_new.ccsanitizer_coverage_mapping_libcdep.ccsanitizer_flags.incsanitizer_linux.ccsanitizer_platform.hsanitizer_platform_limits_posix.hsanitizer_posix_libcdep.ccsanitizer_win.cc
ubsan
libc++/include
llvm
include/llvm
ADT
Analysis
CodeGen
MachineRegionInfo.hMachineRegisterInfo.hMachineScheduler.h
PBQP
PBQPRAConstraint.hPasses.hRegAllocPBQP.hRegisterScavenging.hScheduleDAGInstrs.hSelectionDAG.hSelectionDAGNodes.hSlotIndexes.hStackMaps.hTargetSchedule.hWinEHFuncInfo.hDebugInfo
CodeView
CodeView.hCodeViewRecordIO.hDebugChecksumsSubsection.hDebugInlineeLinesSubsection.hDebugSubsectionRecord.hSymbolDeserializer.hSymbolDumper.hSymbolRecordMapping.hSymbolSerializer.h
MSF
PDB/Native
IR
InitializePasses.hLTO
ObjectYAML
TableGen
Transforms
lib
Analysis
ConstantFolding.cppIndirectCallPromotionAnalysis.cppInlineCost.cppLazyValueInfo.cppModuleSummaryAnalysis.cppOrderedBasicBlock.cppRegionPass.cpp
Bitcode
CodeGen
AsmPrinter
CodeGen.cppGlobalMerge.cppLivePhysRegs.cppLiveRegUnits.cppMachineRegionInfo.cppMachineVerifier.cppPrologEpilogInserter.cppRegAllocBasic.cppRegAllocPBQP.cppRegisterScavenging.cppScheduleDAGInstrs.cppSelectionDAG
TargetLoweringBase.cppDebugInfo/CodeView
@ -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
Loading…
x
Reference in New Issue
Block a user